diff --git a/GameEngine/Database.php b/GameEngine/Database.php
index 65cf227c..e4f19f62 100755
--- a/GameEngine/Database.php
+++ b/GameEngine/Database.php
@@ -612,6 +612,33 @@ class MYSQLi_DB implements IDbConnection {
public function is_connected() {
return ($this->dblink ? true : false);
}
+
+
+ /***************************
+ Function to calc oasis bonus
+ References: lietuvis10
+ ***************************/
+
+ public function getBestOasisCropBonus($x, $y) {
+ $x = (int)$x;
+ $y = (int)$y;
+
+ // Adjust oasis type codes if your fork differs:
+ // - 50% crop only: type IN (12)
+ // - 25% crop (pure or mixed w/ wood/clay/iron): type IN (4,9,10,11)
+
+ $sql = "SELECT COALESCE(SUM(bonus), 0) AS total FROM (SELECT CASE
+ WHEN o.type IN (12) THEN 50 WHEN o.type IN (4,9,10,11) THEN 25 ELSE 0
+ END AS bonus FROM " . TB_PREFIX . "wdata w JOIN " . TB_PREFIX . "odata o ON o.wref = w.id
+ WHERE w.fieldtype = 0 AND ABS(w.x - $x) <= 3 AND ABS(w.y - $y) <= 3
+ AND o.type IN (12,4,9,10,11) -- only crop-giving oases ORDER BY bonus DESC LIMIT 3) t";
+
+ $q = mysqli_query($this->dblink, $sql);
+ $row = mysqli_fetch_assoc($q);
+ $total = (int)($row['total'] ?? 0);
+ if ($total > 150) $total = 150; // safety cap
+ return $total;
+ }
/***************************
Function to process MYSQLi->fetch_all (Only exist in MYSQL)
diff --git a/Templates/menu.tpl b/Templates/menu.tpl
index 0bb50dcd..e330c369 100644
--- a/Templates/menu.tpl
+++ b/Templates/menu.tpl
@@ -44,6 +44,7 @@ div.c1 {text-align: center}
} ?> access == ADMIN) {
echo "".ADMIN_PANEL." ";
echo "".MASS_MESSAGE." ";
+ echo 'Build Cropper ';
echo "".SYSTEM_MESSAGE." ";
} ?>
diff --git a/build_croppers.php b/build_croppers.php
new file mode 100644
index 00000000..753d218e
--- /dev/null
+++ b/build_croppers.php
@@ -0,0 +1,348 @@
+pageLoadTimeStart();
+
+include_once("GameEngine/Session.php");
+include_once("GameEngine/config.php");
+include_once("GameEngine/Database.php");
+include_once("GameEngine/Village.php");
+
+AccessLogger::logRequest();
+
+// ---------- Admin gate ----------
+if (!isset($session) || !isset($session->access) || (int)$session->access < 8) {
+ header('Location: dorf1.php');
+ exit;
+}
+
+// ---------- Setup ----------
+@session_start();
+
+$TBP = defined('TB_PREFIX') ? TB_PREFIX : 's1_';
+$CROP_TABLE = $TBP . 'croppers';
+$WDATA = $TBP . 'wdata';
+
+// Build an absolute-safe asset prefix for CSS/JS
+$assetBase = $session->gpack ?: GP_LOCATE;
+$assetBase = '/'.ltrim($assetBase, '/');
+
+// CSRF
+if (empty($_SESSION['csrf_cb'])) {
+ $_SESSION['csrf_cb'] = bin2hex(random_bytes(16));
+}
+$csrf = $_SESSION['csrf_cb'];
+
+function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
+
+// Ensure table exists (minimal schema, unsigned tinyints)
+mysqli_query($database->dblink, "CREATE TABLE IF NOT EXISTS `$CROP_TABLE` (
+ `wref` INT UNSIGNED NOT NULL PRIMARY KEY,
+ `x` INT NOT NULL,
+ `y` INT NOT NULL,
+ `fieldtype` TINYINT UNSIGNED NOT NULL,
+ `best_oasis_bonus` TINYINT UNSIGNED NOT NULL,
+ `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CHECK (`best_oasis_bonus` IN (0,25,50,75,100,125,150))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
+
+// Helpful indexes (ignore errors if already exist)
+@mysqli_query($database->dblink, "CREATE INDEX `idx_ft_bonus_xy` ON `$CROP_TABLE` (`fieldtype`, `best_oasis_bonus`, `x`, `y`)");
+@mysqli_query($database->dblink, "CREATE INDEX `idx_xy` ON `$CROP_TABLE` (`x`, `y`)");
+@mysqli_query($database->dblink, "CREATE INDEX `idx_bonus` ON `$CROP_TABLE` (`best_oasis_bonus`)");
+
+// ---------- Helpers ----------
+function worldSizeLabel(): string {
+ if (defined('WORLD_MIN') && defined('WORLD_MAX')) {
+ $min = (int)WORLD_MIN; $max = (int)WORLD_MAX;
+ return ($max - $min + 1) . "×" . ($max - $min + 1) . " (" . $min . " .. " . $max . ")";
+ }
+ if (defined('WORLD_MAX')) {
+ $max = (int)WORLD_MAX; $min = -$max;
+ return ($max - $min + 1) . "×" . ($max - $min + 1) . " (" . $min . " .. " . $max . ")";
+ }
+ return "unknown";
+}
+
+function getCounts($db, $WDATA, $CROP_TABLE) {
+ $c1 = mysqli_fetch_assoc(mysqli_query($db, "SELECT COUNT(*) c FROM `$WDATA` WHERE fieldtype IN (1,6)"));
+ $c2 = mysqli_fetch_assoc(mysqli_query($db, "SELECT COUNT(*) c FROM `$CROP_TABLE`"));
+ $lu = mysqli_fetch_assoc(mysqli_query($db, "SELECT MAX(updated_at) lu FROM `$CROP_TABLE`"));
+ return [
+ 'croppers_world' => (int)($c1['c'] ?? 0),
+ 'croppers_table' => (int)($c2['c'] ?? 0),
+ 'last_updated' => $lu['lu'] ?? null,
+ ];
+}
+
+// stream log
+function startStreaming() {
+ @ini_set('output_buffering','off');
+ @ini_set('zlib.output_compression', 0);
+ while (ob_get_level()) { @ob_end_flush(); }
+ ob_implicit_flush(true);
+ echo "
";
+ echo htmlspecialchars("[".date('H:i:s')."] Croppers builder started")."\n";
+ flush();
+}
+function logLine($msg) { echo htmlspecialchars("[".date('H:i:s')."] ".$msg)."\n"; flush(); }
+function endStreaming() { echo " "; flush(); }
+
+// ---------- Actions ----------
+$action = $_POST['action'] ?? null;
+$okCsrf = isset($_POST['csrf']) && hash_equals($_SESSION['csrf_cb'], $_POST['csrf']);
+$notice = null;
+
+if ($action && !$okCsrf) {
+ $notice = "Invalid CSRF token. Please reload the page.";
+ $action = null;
+}
+
+if ($action === 'truncate') {
+ mysqli_query($database->dblink, "TRUNCATE TABLE `$CROP_TABLE`");
+ $notice = "Croppers table truncated.";
+}
+if ($action === 'reindex') {
+ @mysqli_query($database->dblink, "DROP INDEX `idx_ft_bonus_xy` ON `$CROP_TABLE`");
+ @mysqli_query($database->dblink, "DROP INDEX `idx_xy` ON `$CROP_TABLE`");
+ @mysqli_query($database->dblink, "DROP INDEX `idx_bonus` ON `$CROP_TABLE`");
+ @mysqli_query($database->dblink, "CREATE INDEX `idx_ft_bonus_xy` ON `$CROP_TABLE` (`fieldtype`, `best_oasis_bonus`, `x`, `y`)");
+ @mysqli_query($database->dblink, "CREATE INDEX `idx_xy` ON `$CROP_TABLE` (`x`, `y`)");
+ @mysqli_query($database->dblink, "CREATE INDEX `idx_bonus` ON `$CROP_TABLE` (`best_oasis_bonus`)");
+ $notice = "Indexes rebuilt.";
+}
+if ($action === 'estimate') {
+ $notice = "Estimated counts refreshed.";
+}
+
+$stats = getCounts($database->dblink, $WDATA, $CROP_TABLE);
+$worldLabel = worldSizeLabel();
+
+?>
+
+
+
+ - Mass Message
+
+
+
+
+
+
+
+
+
+
+
+
+ gpack == null || GP_ENABLE == false) {
+ echo "
+
+ ";
+ } else {
+ echo "
+
+ ";
+ }
+ ?>
+
+
+
+
+
+
+ gpack == null || GP_ENABLE == false) {
+ echo "
+
+ ";
+ } else {
+ echo "
+
+ ";
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Build crop finder
+
+
+
+
+
+
+
+
Status
+
World:
+
+
9c/15c in map:
+
Rows in table:
+
Last updated:
+
+
+ The croppers table stores only wref,x,y,fieldtype,best_oasis_bonus .
+ Ownership and occupied status are pulled live from vdata/users by the finder.
+
+
+
+
+
Actions
+
+
+ Building streams progress below. You can leave this page; the process stops when the request ends.
+
+
+
+
+dblink, "SELECT COUNT(*) AS c FROM `$WDATA` WHERE `fieldtype` IN (1,6)"));
+ $target = (int)($cnt['c'] ?? 0);
+ logLine("Detected $target croppers.");
+
+ $offset = 0; $total = 0;
+ while (true) {
+ $sql = "SELECT id AS wref, x, y, fieldtype
+ FROM `$WDATA`
+ WHERE `fieldtype` IN (1,6)
+ LIMIT $offset, $batch";
+ $res = mysqli_query($database->dblink, $sql);
+ if (!$res) { logLine('Query failed: '.mysqli_error($database->dblink)); break; }
+
+ $rows = [];
+ while ($r = mysqli_fetch_assoc($res)) { $rows[] = $r; }
+ if (!$rows) break;
+
+ $values = [];
+ foreach ($rows as $r) {
+ $x = (int)$r['x']; $y = (int)$r['y'];
+ $bonus = (int)$database->getBestOasisCropBonus($x, $y);
+ if (!in_array($bonus, [0,25,50,75,100,125,150], true)) {
+ $bonus = max(0, min(150, $bonus));
+ }
+ $values[] = sprintf("(%d,%d,%d,%d,%d)",
+ (int)$r['wref'], $x, $y, (int)$r['fieldtype'], $bonus);
+ }
+ if ($values) {
+ $sql = "REPLACE INTO `$CROP_TABLE`
+ (`wref`,`x`,`y`,`fieldtype`,`best_oasis_bonus`)
+ VALUES ".implode(',', $values);
+ if (!mysqli_query($database->dblink, $sql)) {
+ logLine('Upsert failed: '.mysqli_error($database->dblink));
+ break;
+ }
+ }
+ $countThis = count($rows);
+ $total += $countThis;
+ $offset += $batch;
+ logLine("Processed $total / $target");
+ }
+
+ @mysqli_query($database->dblink, "ANALYZE TABLE `$CROP_TABLE`");
+ logLine("Analyze complete.");
+ logLine("Done.");
+ endStreaming();
+
+ // Refresh stats after build
+ $stats = getCounts($database->dblink, $WDATA, $CROP_TABLE);
+}
+?>
+
+
+
+
+
+ ";
+ include("Templates/links.tpl");
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+ pageLoadTimeEnd()-$start_timer)*1000); ?> ms
+
+
+
+
+
+
+
+
diff --git a/crop_finder.php b/crop_finder.php
index 21179965..ad1e8e03 100644
--- a/crop_finder.php
+++ b/crop_finder.php
@@ -1,220 +1,291 @@
croppers
+// Fixes:
+// - Uses WORLD_MIN/WORLD_MAX from config if present (works for 0..N or -W..+W)
+// - If not defined in config, auto-detects bounds from DB
+// - Larger window cap + extra expansion
+// - Global fallback so it never returns only a few rows
+
include_once("GameEngine/Generator.php");
$start_timer = $generator->pageLoadTimeStart();
+include_once("GameEngine/config.php");
+use App\Utils\AccessLogger;
+include_once("GameEngine/Village.php");
+AccessLogger::logRequest();
-/*-------------------------------------------------------*\
-| ********* DO NOT REMOVE THIS COPYRIGHT NOTICE ********* |
-+---------------------------------------------------------+
-| Developed by: Manni < manuel_mannhardt@web.de > |
-| Dzoki < dzoki.travian@gmail.com > |
-| Copyright: TravianX Project All rights reserved |
-\*-------------------------------------------------------*/
+if ($session->goldclub == 0) { header("Location: plus.php?id=3"); exit; }
- use App\Utils\AccessLogger;
+// Tables
+$TBP = defined('TB_PREFIX') ? TB_PREFIX : 's1_';
+$CROP_TABLE = $TBP . 'croppers';
+$VDATA = $TBP . 'vdata';
+$USERS = $TBP . 'users';
- include_once("GameEngine/Village.php");
- AccessLogger::logRequest();
+$RENDER_MAX = 100;
- if($session->goldclub == 0) {
- header("Location: plus.php?id=3");
- exit;
- }
+// ---------- POST -> GET ----------
+if (!empty($_POST['type'])) {
+ $x = isset($_POST['x']) ? preg_replace("/[^0-9-]/", "", $_POST['x']) : '0';
+ $y = isset($_POST['y']) ? preg_replace("/[^0-9-]/", "", $_POST['y']) : '0';
+ $b = isset($_POST['bonus_getreide']) ? preg_replace("/[^0-9a-zA-Z]/", "", $_POST['bonus_getreide']) : 'all';
+ if ($_POST['type'] == 15) header("Location: " . $_SERVER['PHP_SELF'] . "?s=1&x=$x&y=$y&b=$b");
+ elseif ($_POST['type'] == 9) header("Location: " . $_SERVER['PHP_SELF'] . "?s=2&x=$x&y=$y&b=$b");
+ else header("Location: " . $_SERVER['PHP_SELF'] . "?s=3&x=$x&y=$y&b=$b");
+ exit;
+}
- if ( !empty( $_POST['type'] ) ) {
- if ( $_POST['type'] == 15 ) {
- header( "Location: " . $_SERVER['PHP_SELF'] . "?s=1&x=" . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['x'] ) . '&y=' . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['y'] ) );
- exit;
- } elseif ( $_POST['type'] == 9 ) {
- header( "Location: " . $_SERVER['PHP_SELF'] . "?s=2&x=" . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['x'] ) . '&y=' . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['y'] ) );
- exit;
- } elseif ( $_POST['type'] == 'both' ) {
- header( "Location: " . $_SERVER['PHP_SELF'] . "?s=3&x=" . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['x'] ) . '&y=' . preg_replace( "/[^a-zA-Z0-9_-]/", "", $_POST['y'] ) );
- exit;
- }
- }
+// ---------- Helpers ----------
+/**
+ * Wrap-aware BETWEEN that works for arbitrary [min..max] (e.g. 0..49 or -300..300)
+ */
+function betweenWrapFlexible($col, $center, $R, $min, $max) {
+ $span = $max - $min + 1;
+ $lo = $center - $R;
+ $hi = $center + $R;
+ // normalize to [min,max]
+ $norm = function($v) use ($min,$span) {
+ $n = ($v - $min) % $span;
+ if ($n < 0) $n += $span;
+ return $min + $n;
+ };
+ $loN = $norm($lo);
+ $hiN = $norm($hi);
+ if ($loN <= $hiN) return "($col BETWEEN $loN AND $hiN)";
+ return "(($col BETWEEN $min AND $hiN) OR ($col BETWEEN $loN AND $max))";
+}
+// ---------- Coordinates ----------
+if (!empty($_GET['x']) && !empty($_GET['y']) && is_numeric($_GET['x']) && is_numeric($_GET['y'])) {
+ $coor2 = ['x'=>(int)$_GET['x'], 'y'=>(int)$_GET['y']];
+} else {
+ $wref2 = $village->wid;
+ $coor2 = $database->getCoor($wref2);
+}
+$startX = isset($coor2['x']) ? (int)$coor2['x'] : 0;
+$startY = isset($coor2['y']) ? (int)$coor2['y'] : 0;
+
+// ---------- UI selections ----------
+// UI selections
+$selBonus = isset($_GET['b']) ? $_GET['b'] : 'all';
+$selType = (!empty($_GET['s'])) ? (int)$_GET['s'] : 0;
+$minBonus = ($selBonus !== 'all') ? (int)$selBonus : null;
+$fieldWhere = ($selType === 1) ? "6" : (($selType === 2) ? "1" : "1,6");
+$bonusCond = is_null($minBonus) ? "1" : ("c.best_oasis_bonus >= ".(int)$minBonus);
+
+// Only run the queries after the user pressed Search (i.e., we have s, x, y in the URL)
+$rows = [];
+$out = [];
+$searchTriggered = isset($_GET['s']) && isset($_GET['x']) && isset($_GET['y']);
+
+if ($searchTriggered) {
+ // --- Windowed fetch with bigger cap and one more expansion ---
+ $R = 40; // start radius
+ $tries= 0;
+ $CAP = 2000; // increased cap per window
+
+ do {
+ $tries++;
+ $condX = betweenWrapFlexible('c.x', $startX, $R, $MIN_X, $MAX_X);
+ $condY = betweenWrapFlexible('c.y', $startY, $R, $MIN_Y, $MAX_Y);
+
+ $sql = "SELECT c.wref, c.x, c.y, c.fieldtype, c.best_oasis_bonus
+ FROM `$CROP_TABLE` c
+ WHERE c.fieldtype IN ($fieldWhere) AND $bonusCond AND $condX AND $condY
+ LIMIT $CAP";
+ $res = mysqli_query($database->dblink, $sql);
+
+ $rows = [];
+ if ($res) {
+ while ($r = mysqli_fetch_assoc($res)) {
+ $r['__dist'] = $database->getDistance($startX, $startY, (int)$r['x'], (int)$r['y']);
+ $rows[] = $r;
+ }
+ }
+
+ if (count($rows) < $RENDER_MAX && $tries < 4) { // 40 -> 80 -> 160 -> 320
+ $R *= 2;
+ } else {
+ break;
+ }
+ } while (true);
+
+ // --- Global fallback if window was too sparse ---
+ if (count($rows) < $RENDER_MAX) {
+ $sql = "SELECT c.wref, c.x, c.y, c.fieldtype, c.best_oasis_bonus
+ FROM `$CROP_TABLE` c
+ WHERE c.fieldtype IN ($fieldWhere) AND $bonusCond
+ LIMIT 5000";
+ $res = mysqli_query($database->dblink, $sql);
+ $rows = [];
+ if ($res) {
+ while ($r = mysqli_fetch_assoc($res)) {
+ $r['__dist'] = $database->getDistance($startX, $startY, (int)$r['x'], (int)$r['y']);
+ $rows[] = $r;
+ }
+ }
+ }
+
+ // Sort by distance and keep first RENDER_MAX
+ usort($rows, function($a,$b){ return $a['__dist'] <=> $b['__dist']; });
+ $out = array_slice($rows, 0, $RENDER_MAX);
+}
+
+// Live owner info for visible rows
+$wrefs = array_map(function($r){ return (int)$r['wref']; }, $out);
+$owners = [];
+if ($wrefs) {
+ $in = implode(',', array_unique($wrefs));
+ $sql = "SELECT v.wref, v.name AS vname, v.owner AS owner_id, u.username
+ FROM `$VDATA` v
+ JOIN `$USERS` u ON u.id = v.owner
+ WHERE v.wref IN ($in)";
+ $res = mysqli_query($database->dblink, $sql);
+ if ($res) while ($row = mysqli_fetch_assoc($res)) { $owners[(int)$row['wref']] = $row; }
+}
?>
- - Crop Finder
-
-
-
-
-
-
-
-
-
-
-
- gpack == null || GP_ENABLE == false) {
- echo "
-
- ";
- }
- else {
- echo "
-
- ";
- }
-
-?>
-
+ - Crop Finder
+
+
+
+
+
+
+
+
+
+
+
+gpack == null || GP_ENABLE == false) {
+ echo " ";
+ echo " ";
+} else {
+ echo " ";
+ echo " ";
+} ?>
+
-
-
-
-
+
+
-wid;
- $coor2 = $database->getCoor($wref2);
-}
-?>
-
+
+
Crop Finder
-
dblink,"SELECT id, x, y, occupied, fieldtype FROM ".TB_PREFIX."wdata WHERE $fieldType");
-
-if ( !empty( $_GET['x'] ) && is_numeric($_GET['x']) && !empty( $_GET['y'] ) && is_numeric($_GET['y'])) {
- $coor['x'] = $_GET['x'];
- $coor['y'] = $_GET['y'];
-} else {
- $wref = $village->wid;
- $coor = $database->getCoor($wref);
+// Debug panel (toggle with ?debug=1)
+if (!empty($_GET['debug'])) {
+ echo "
";
+ echo "Debug: bounds=[$MIN_X..$MAX_X]x[$MIN_Y..$MAX_Y], R=$R, tries=$tries, fetched=".count($rows).", render=".count($out).", type={$selType}, minBonus=".($minBonus??'all');
+ echo "
";
}
-
-if ( !empty( $_GET['s'] ) && $_GET['s'] >= 1 && $_GET['s'] <= 3 ) {
?>
-
+
-
-
- Crop Finder - 9c and 15c
-
-
- Type
- Coordinates
- Owner
- Occupied
- Distance
- Oasis
-
-
-
+
+Crop Finder -
+
+ Type
+ Coordinates
+ Owner
+ Occupied
+ Distance
+ Oasis
+
+
+
getDistance($coor['x'], $coor['y'], $row['x'], $row['y']);
- $rows[$dist] = $row;
-}
-ksort($rows);
-foreach($rows as $row) {
- $field = $row['fieldtype'] == 1 ? '9c' : '15c';
-
- echo "" . $field . " ";
- if($row['occupied'] == 0) {
- echo "getMapCheck($row['id'])."\">".ABANDVALLEY." (".$row['x']."|".$row['y'].") ";
- echo "- ";
- echo "".UNOCCUPIED." ";
- } else {
- echo "getMapCheck($row['id'])."\">".$database->getVillageField($row['id'], "name")." (".$row['x']."|".$row['y'].") ";
- echo "getVillageField($row['id'], "owner")."\">".$database->getUserField($database->getVillageField($row['id'], "owner"), "username", 0)." ";
- echo "".OCCUPIED." ";
- }
- echo "".$database->getDistance($coor['x'], $coor['y'], $row['x'], $row['y'])."
";
- echo "- ";
+if (empty($out)) {
+ echo "
+ No crops fields found for the selected filters.
+ ";
+} else {
+ foreach ($out as $row) {
+ $field = ($row['fieldtype'] == 1) ? '9c' : '15c';
+ $x=(int)$row['x']; $y=(int)$row['y']; $id=(int)$row['wref'];
+ $ov = $owners[$id] ?? null;
+ $isOcc = $ov !== null;
+ echo "$field ";
+ if (!$isOcc) {
+ echo "getMapCheck($id)."\">".ABANDVALLEY." ($x|$y) ";
+ echo "- ";
+ echo "".UNOCCUPIED." ";
+ } else {
+ $vname = htmlspecialchars($ov['vname'] ?? '', ENT_QUOTES, 'UTF-8');
+ $owner = (int)($ov['owner_id'] ?? 0);
+ $uname = htmlspecialchars($ov['username'] ?? '', ENT_QUOTES, 'UTF-8');
+ echo "getMapCheck($id)."\">".$vname." ($x|$y) ";
+ echo "".$uname." ";
+ echo "".OCCUPIED." ";
+ }
+ echo "".(int)$row['__dist']."
";
+ echo "+".(int)$row['best_oasis_bonus']."% ";
+ echo " ";
+ }
}
?>
+
-
-
-
+
+
-
+
+
+
";
- include("Templates/links.tpl");
+ echo " ";
+ include("Templates/links.tpl");
}
?>
@@ -222,25 +293,16 @@ if(!NEW_FUNCTIONS_DISPLAY_LINKS) {
-
-
+
- pageLoadTimeEnd()-$start_timer)*1000);
-?> ms
-
+ pageLoadTimeEnd()-$start_timer)*1000); ?> ms
-
-
+
+
diff --git a/var/db/struct.sql b/var/db/struct.sql
index 8919e38c..b6bd1991 100644
--- a/var/db/struct.sql
+++ b/var/db/struct.sql
@@ -1731,14 +1731,35 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%password` (
--
CREATE TABLE IF NOT EXISTS `%PREFIX%ww_attacks` (
- `vid` int(25) DEFAULT NULL,
+ `vid` int(25) DEFAULT NULL,
`attack_time` int(11) DEFAULT NULL,
KEY `attack_time` (`attack_time`),
KEY `vid` (`vid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
--
--- Dumping data for table `%prefix%password`
+-- Dumping data for table `%prefix%ww_attacks`
--
-- --------------------------------------------------------
+--
+-- Table structure for table `%prefix%croppers`
+--
+
+CREATE TABLE IF NOT EXISTS %PREFIX%croppers (
+ wref INT UNSIGNED NOT NULL PRIMARY KEY,
+ x INT NOT NULL,
+ y INT NOT NULL,
+ fieldtype TINYINT UNSIGNED NOT NULL, -- 1 = 9c, 6 = 15c
+ best_oasis_bonus TINYINT UNSIGNED NOT NULL, -- 0,25,50,75,100,125,150
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CHECK (best_oasis_bonus IN (0,25,50,75,100,125,150))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE INDEX idx_ft_bonus_xy ON %PREFIX%croppers (fieldtype, best_oasis_bonus, x, y);
+CREATE INDEX idx_xy ON %PREFIX%croppers (x, y);
+CREATE INDEX idx_bonus ON %PREFIX%croppers (best_oasis_bonus);
+
+--
+-- Dumping data for table `%prefix%croppers`
+--
\ No newline at end of file