首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

深度解析 Xnova (OGame) 艦隊系統核心邏輯:FlyingFleetHandler.php 源碼詳解

     編輯:PHP 相關知識

艦隊活動觸發機制:從 common.php 切入

在 Xnova 這類基於 PHP 的網頁遊戲中,艦隊活動並非由定時任務驅動,而是採用「玩家請求觸發」的被動計算模式。每當用戶訪問頁面,common.php 都會執行檢查,掃描資料庫中是否有艦隊抵達目的地或返回起點。這種設計雖然簡單,但隨著玩家增長,每次請求都需全表掃描 fleets 表,效率極低。

原始觸發代碼剖析

// 檢查是否有到達目的地的艦隊
$_fleets = doquery("SELECT * FROM {{table}} WHERE 'fleet_start_time' <= '".time()."';", 'fleets');
// 循環處理每個艦隊
while ($row = mysql_fetch_array($_fleets)) {
    $array = array(
        'galaxy' => $row['fleet_start_galaxy'],
        'system' => $row['fleet_start_system'],
        'planet' => $row['fleet_start_planet'],
        'planet_type' => $row['fleet_start_type']
    );
    $temp = FlyingFleetHandler($array);
}

// 檢查是否有返回出發地的艦隊
$_fleets = doquery("SELECT * FROM {{table}} WHERE 'fleet_end_time' <= '".time()."';", 'fleets');
while ($row = mysql_fetch_array($_fleets)) {
    $array = array(
        'galaxy' => $row['fleet_end_galaxy'],
        'system' => $row['fleet_end_system'],
        'planet' => $row['fleet_end_planet'],
        'planet_type' => $row['fleet_end_type']
    );
    $temp = FlyingFleetHandler($array);
}

優化建議:應避免在 common.php 中全表掃描。可改為僅傳遞單一艦隊 ID 給處理函數,並建立索引優化查詢;或引入任務佇列(如 Gearman、Redis 列表)實現異步處理,將艦隊結算從 HTTP 請求中剝離。

核心調度器:FlyingFleetHandler() 詳解

該函數作為艦隊邏輯的總入口,採用表鎖確保數據一致性,根據 fleet_mission 任務類型分發至對應處理器:

// 鎖定相關表,防止併發衝突
doquery("LOCK TABLE {{table}}lunas WRITE, {{table}}rw WRITE, {{table}}errors WRITE, {{table}}messages WRITE, {{table}}fleets WRITE, {{table}}planets WRITE, {{table}}galaxy WRITE, {{table}}users WRITE", "");

// 複雜的 SQL 查詢獲取當前座標相關的所有艦隊
$QryFleet = "SELECT * FROM {{table}} WHERE ( ... 條件構建 ... ) AND ( `fleet_start_time` < '".time()."' OR `fleet_end_time` < '".time()."' );";
$fleetquery = doquery($QryFleet, 'fleets');

// 根據任務類型分發
while ($CurrentFleet = mysql_fetch_array($fleetquery)) {
    switch ($CurrentFleet["fleet_mission"]) {
        case 1:  MissionCaseAttack($CurrentFleet); break;       // 普通攻擊
        case 2:  /* ACS 攻擊,當前未啟用 */ break;
        case 3:  MissionCaseTransport($CurrentFleet); break;     // 運輸
        case 4:  MissionCaseStay($CurrentFleet); break;          // 派遣
        case 5:  MissionCaseStayAlly($CurrentFleet); break;      // 聯合派遣 (ACS 防禦)
        case 6:  MissionCaseSpy($CurrentFleet); break;           // 偵查
        case 7:  MissionCaseColonisation($CurrentFleet); break;  // 殖民
        case 8:  MissionCaseRecycling($CurrentFleet); break;     // 回收
        case 9:  MissionCaseDestruction($CurrentFleet); break;   // 毀月
        case 10: break;                                          // 保留
        case 15: MissionCaseExpedition($CurrentFleet); break;    // 遠征/探險
        default: doquery("DELETE FROM {{table}} WHERE `fleet_id` = '".$CurrentFleet['fleet_id']."';", 'fleets');
    }
}
doquery("UNLOCK TABLES", "");

關鍵設計點評

  • 表鎖粒度過大:鎖定 8 張表會嚴重阻塞並發,建議改用行級鎖(InnoDB)或樂觀鎖機制。
  • SQL 注入風險:直接拼接變量入查詢,應使用預處理語句。
  • 職責單一原則:每個 MissionCase* 函數專注單一任務邏輯,結構清晰,便於維護與擴展。
  • 異常兜底:default 分支刪除非法艦隊數據,體現防禦性編程思想。

後續優化方向

  1. 引入消息佇列,將艦隊結算異步化,提升響應速度。
  2. 將艦隊狀態機拆分為獨立服務,支援水平擴展。
  3. 使用現代 PHP 框架(如 Laravel、Symfony)重構,利用 ORM、事件系統簡化邏輯。
  4. 增加單元測試覆蓋核心戰鬥、資源運算邏輯。

理解這段經典代碼,不僅能掌握早期瀏覽器遊戲的架構精髓,更能啟發現代高併發系統的設計思路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved