Class CharacterItemFilterManager

java.lang.Object
client.CharacterItemFilterManager

public final class CharacterItemFilterManager extends Object
角色的「帳號道具過濾」子系統協作者,封裝 _filter_item 資料表的查詢/寫入與其記憶體快取。

過濾設定以帳號acc_id)為單位,故同帳號的所有角色共用同一份過濾清單:玩家只要設定一次, 之後該帳號任一角色擊殺怪物時,被過濾的道具皆不再掉落。被過濾的道具編號保存在 _filter_item 資料表(主鍵 (acc_id, item_id)),並於登入時(MapleCharacter.loadCharFromDB(int, MapleClient, boolean) / MapleCharacter.ReconstructChr(CharacterTransfer, MapleClient, boolean))一次性載入到記憶體 Set 快取。

為何必須快取於記憶體:isFilterItem(int)MapleMonsterKillManager 的掉落滾動(dropFromMonster)對每一筆掉落條目呼叫, 屬高頻熱路徑;若每次都查資料庫將嚴重拖慢掉落。因此本協作者於登入時把該帳號的過濾清單載入 執行緒安全的 Set,之後 isFilterItem 僅做記憶體 contains。新增/刪除(addFilterItem(int) / subFilterItem(int))會同時更新資料庫與此快取,使後續掉落判定即時生效。

執行緒安全:讀取(isFilterItem,掉落/地圖執行緒)與寫入(addsub, NPC 腳本所在的玩家連線執行緒)可能並發,故快取採 ConcurrentHashMap.newKeySet()

MapleCharacter 對外保留簽名完全相同的委派方法(addFilterItem / subFilterItem / isFilterItem / getFilterItemInfo / getMapDropItemInfo), 因此遊戲內容腳本(如 scripts/special/0400_便利功能/_物品過濾.js)以 cm.getPlayer().addFilterItem(...) 等方式呼叫,完全不受協作者抽離影響。所有資料庫寫入經 Db 執行(僅關閉 Statement,不關閉共用 Connection),失敗時記錄 debug 並吞掉, 不影響遊戲流程。

  • Method Summary

    Modifier and Type
    Method
    Description
    void
    addFilterItem(int itemId)
    將指定道具加入本帳號的過濾清單(同步寫入資料庫與記憶體快取)。
    組出「目前過濾的道具」清單字串,供 NPC 對話框顯示(每個道具為可點選的連結,點選後可解除過濾)。
    組出「目前地圖上的掉落物」清單字串,供 NPC 對話框顯示(每個道具為可點選的連結,點選後可加入過濾)。
    boolean
    isFilterItem(int itemId)
    查詢指定道具是否在本帳號的過濾清單中(記憶體快取查詢,掉落熱路徑使用)。
    void
    依角色所屬帳號 id 自 _filter_item 載入過濾道具清單到記憶體快取。
    void
    subFilterItem(int itemId)
    將指定道具自本帳號的過濾清單移除(同步刪除資料庫列與記憶體快取項目)。

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • loadFilterItems

      public void loadFilterItems()
      依角色所屬帳號 id 自 _filter_item 載入過濾道具清單到記憶體快取。

      於帳號 id 已知後呼叫(MapleCharacter.loadCharFromDB(int, MapleClient, boolean) 的頻道伺服器分支、 以及換頻道的 MapleCharacter.ReconstructChr(CharacterTransfer, MapleClient, boolean))。會先清空既有快取再重新載入,因此可安全地重複呼叫。 透過 DatabaseConnection 取得當前執行緒共用 Connection 執行唯讀查詢;發生例外時記錄 debug 並維持已載入到一半的內容(最壞情況退化為部分/不過濾,不影響其他流程)。

    • isFilterItem

      public boolean isFilterItem(int itemId)
      查詢指定道具是否在本帳號的過濾清單中(記憶體快取查詢,掉落熱路徑使用)。

      僅讀取 filterItems 快取、不查資料庫;由 MapleMonsterKillManagerdropFromMonster 對每筆掉落條目呼叫,命中時該道具不掉落。楓幣掉落的條目 itemId 為 0, 而過濾清單只會經由地圖掉落物(itemId > 50000)加入,故 isFilterItem(0) 恆為 false, 不會誤過濾楓幣。

      Parameters:
      itemId - 道具編號
      Returns:
      true 表示該道具被本帳號過濾(不應掉落);否則 false
    • addFilterItem

      public void addFilterItem(int itemId)
      將指定道具加入本帳號的過濾清單(同步寫入資料庫與記憶體快取)。

      INSERT ... ON DUPLICATE KEY UPDATE 寫入 _filter_item(主鍵 (acc_id, item_id) 確保帳號內唯一、且防止並發重複),成功後加入記憶體快取使後續掉落判定即時生效。已在快取中時直接返回 (避免多餘的資料庫往返)。經 Db.update(String, Object...) 執行(僅關閉 Statement,不關閉共用 Connection);發生例外時記錄 debug 並吞掉。

      Parameters:
      itemId - 要過濾的道具編號
    • subFilterItem

      public void subFilterItem(int itemId)
      將指定道具自本帳號的過濾清單移除(同步刪除資料庫列與記憶體快取項目)。

      _filter_item(acc_id, item_id) 刪除對應列,並自記憶體快取移除,使該道具恢復正常掉落。 經 Db.update(String, Object...) 執行(僅關閉 Statement,不關閉共用 Connection);發生例外時記錄 debug 並吞掉。

      Parameters:
      itemId - 要解除過濾的道具編號
    • getFilterItemInfo

      public String getFilterItemInfo()
      組出「目前過濾的道具」清單字串,供 NPC 對話框顯示(每個道具為可點選的連結,點選後可解除過濾)。

      讀取記憶體快取(依道具編號排序以確保顯示穩定),對每個道具產生 #L<id>#...#l 連結 + #v<id># 圖示 + #z<id># 名稱的標記字串;連結的選擇索引即道具編號, 故腳本可直接以 selection 當道具編號呼叫 subFilterItem(int)。清單為空時回傳提示字串。

      Returns:
      過濾清單的 NPC 標記字串;無任何過濾道具時回傳提示文字
    • getMapDropItemInfo

      public String getMapDropItemInfo()
      組出「目前地圖上的掉落物」清單字串,供 NPC 對話框顯示(每個道具為可點選的連結,點選後可加入過濾)。

      掃描角色目前地圖的所有掉落物(MapleMapItem.getItemId()),略過非道具(itemId <= 50000,含楓幣)與不存在於道具資料(MapleItemInformationProvider.itemExists(int))者, 並對相同道具去重,對每個道具產生 #L<id>#...#l 連結;連結的選擇索引即道具編號,故腳本可直接以 selection 當道具編號呼叫 addFilterItem(int)。地圖上沒有掉落物時回傳提示字串。

      Returns:
      地圖掉落物的 NPC 標記字串;地圖上無掉落物時回傳提示文字