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(); + +?> + + + + <?php echo SERVER_NAME ?> - 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; } +} ?> - <?php - - echo SERVER_NAME - -?> - Crop Finder - - - - - - - - - - - - gpack == null || GP_ENABLE == false) { - echo " - - "; - } - else { - echo " - - "; - } - -?> - +<?php echo SERVER_NAME ?> - Crop Finder + + + + + + + + + + + +gpack == null || GP_ENABLE == false) { + echo " "; + echo " "; +} else { + echo " "; + echo " "; +} ?> + - -
-
-
- +
+
-wid; - $coor2 = $database->getCoor($wref2); -} -?> -
+ +

Crop Finder

- - + +


- - - - - - - - - - - - - - - - -
Cropper Type: - /> 15 crop - /> 9 crop - /> both
-
Oasis Crop Bonus (at least): - -
Startposition:x: y:
+ + + + + + + + + + + + + + + + +
Cropper Type: + /> 15 crop + /> 9 crop + /> both
+
Oasis Crop Bonus (min): + +
Start position:x: + y:
- 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 ) { ?> - + - - - - - - - - - - - - - - + + + + + + + + + + + +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 ""; - if($row['occupied'] == 0) { - echo ""; - echo ""; - echo ""; - } else { - echo ""; - echo ""; - echo ""; - } - echo ""; - echo ""; +if (empty($out)) { + echo ""; +} 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 ""; + if (!$isOcc) { + echo ""; + echo ""; + echo ""; + } else { + $vname = htmlspecialchars($ov['vname'] ?? '', ENT_QUOTES, 'UTF-8'); + $owner = (int)($ov['owner_id'] ?? 0); + $uname = htmlspecialchars($ov['username'] ?? '', ENT_QUOTES, 'UTF-8'); + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + } } ?> + -
Crop Finder - 9c and 15c
TypeCoordinatesOwnerOccupiedDistanceOasis
Crop Finder -
TypeCoordinatesOwnerOccupiedDistanceOasis
" . $field . "getMapCheck($row['id'])."\">".ABANDVALLEY." (".$row['x']."|".$row['y'].")-".UNOCCUPIED."getMapCheck($row['id'])."\">".$database->getVillageField($row['id'], "name")." (".$row['x']."|".$row['y'].")getVillageField($row['id'], "owner")."\">".$database->getUserField($database->getVillageField($row['id'], "owner"), "username", 0)."".OCCUPIED."
".$database->getDistance($coor['x'], $coor['y'], $row['x'], $row['y'])."
-
+ No crops fields found for the selected filters. +
$fieldgetMapCheck($id)."\">".ABANDVALLEY." ($x|$y)-".UNOCCUPIED."getMapCheck($id)."\">".$vname." ($x|$y)".$uname."".OCCUPIED."
".(int)$row['__dist']."
+".(int)$row['best_oasis_bonus']."%
- - + +
-



+ +



+



"; - 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