Class CharacterLogManager

java.lang.Object
client.CharacterLogManager

public final class CharacterLogManager extends Object
角色各種「*log」資料表的查詢/寫入協作者,由 P5 God class 拆分自 MapleCharacter

本類別封裝對 bosslog(王挑戰每日次數)、onetimelog(一次性事件旗標)、 prizelogaclog(領獎/成就領取閘門)、chronolog(時空石 30 天閘門)等 資料表的計數查詢與插入,這些紀錄被遊戲內容用來實作「每日/一次性」挑戰與領獎限制。

MapleCharacter 以**逐字搬移**的方式把這些方法移入此處,並對每個對外公開方法保留 **簽名完全相同**的委派(delegate),因此所有 Java 呼叫端與 ~2,700 支腳本完全不受影響。協作者僅 持有對所屬角色的回參考,沿用其角色 id/帳號 id(同 package 存取)與共用的 SLF4J logger (MapleCharacter.log)。

  • Method Details

    • getBossLog

      public int getBossLog(String bossid)
      查詢角色在過去 24 小時內挑戰指定王的次數,用於每日王挑戰次數閘門。

      bosslog 資料表以 characterid(角色 id)與 bossid 條件計數, 並以 SQL lastattempt >= subtime(current_timestamp, '1 0:0:0.0') 限定為近一日內的紀錄。 透過 DatabaseConnection 取得當前執行緒共用的 Connection 執行唯讀查詢, 不會修改任何狀態;查詢過程中發生任何例外時靜默回傳 -1

      Parameters:
      bossid - 王的識別字串
      Returns:
      近 24 小時內的挑戰次數;查無紀錄或發生例外時回傳 -1
    • setBossLog

      public void setBossLog(String bossid)
      為角色寫入一筆指定王的挑戰紀錄。

      bosslog 資料表插入一列(characterid=角色 id、bossid), 其 lastattempt 由資料表預設值帶入當前時間,藉此推進 getBossLog(String) 的每日計數。 經 Db.update(String, Object...) 執行寫入(僅關閉 Statement,不關閉共用 Connection); 發生例外時以 MapleCharacter.log 記錄 debug 並吞掉。

      Parameters:
      bossid - 王的識別字串
    • getOneTimeLog

      public int getOneTimeLog(String log)
      查詢角色是否已有指定一次性事件旗標,用於「一次性」事件閘門。

      onetimelog 資料表以 characterid(角色 id)與 log 條件計數 (不含時間限制,故為永久旗標)。透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢,不修改任何狀態;發生例外時靜默回傳 -1

      Parameters:
      log - 一次性事件的識別字串
      Returns:
      符合的紀錄筆數(0 表示尚未觸發、大於 0 表示已觸發);查無或例外時回傳 -1
    • setOneTimeLog

      public void setOneTimeLog(String log)
      為角色寫入一筆一次性事件旗標。

      onetimelog 資料表插入一列(characterid=角色 id、log), 使 getOneTimeLog(String) 之後對同一旗標永久回傳大於 0。 經 Db.update(String, Object...) 執行寫入(僅關閉 Statement,不關閉共用 Connection); 發生例外時以 MapleCharacter.log 記錄 debug 並吞掉。

      注意:參數名 log 與類別共用 logger 同名,方法內部記錄一律以 MapleCharacter.log 限定。

      Parameters:
      log - 一次性事件的識別字串
    • setPrizeLog

      public void setPrizeLog(String bossid)
      為帳號寫入一筆領獎紀錄。

      prizelog 資料表插入一列(accid=帳號 id、bossid), 推進 getPrizeLog(String) 的領取計數。注意此閘門以**帳號**為單位 (取自 chr.getClient().getAccID()),而非角色。 經 Db.update(String, Object...) 執行寫入(僅關閉 Statement,不關閉共用 Connection); 發生例外時以 MapleCharacter.log 記錄 debug 並吞掉。

      Parameters:
      bossid - 領獎來源(王/事件)的識別字串
    • getPrizeLog

      public int getPrizeLog(String bossid)
      查詢帳號是否已領取指定獎勵,用於以帳號為單位的領獎閘門。

      prizelog 資料表以 accid(帳號 id,取自 chr.getClient().getAccID()) 與 bossid 條件計數(不含時間限制,故為永久領取旗標)。透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢,不修改任何狀態;發生例外時靜默回傳 -1

      Parameters:
      bossid - 領獎來源(王/事件)的識別字串
      Returns:
      符合的紀錄筆數(大於 0 表示已領取);查無或例外時回傳 -1
    • setAcLog

      public void setAcLog(String bossid)
      為帳號寫入一筆成就領取紀錄。

      aclog 資料表插入一列(accid=帳號 id、bossid), 其 lastattempt 由資料表預設值帶入當前時間,推進 getAcLog(String) 的每日成就閘門。 此閘門以**帳號**為單位(取自 chr.getClient().getAccID())。 經 Db.update(String, Object...) 執行寫入(僅關閉 Statement,不關閉共用 Connection); 發生例外時以 MapleCharacter.log 記錄 debug 並吞掉。

      Parameters:
      bossid - 成就來源的識別字串
    • getAcLog

      public int getAcLog(String bossid)
      查詢帳號在過去 24 小時內領取指定成就的次數,用於每日成就領取閘門。

      aclog 資料表以 accid(帳號 id,取自 chr.getClient().getAccID()) 與 bossid 條件計數,並以 SQL lastattempt >= subtime(current_timestamp, '1 0:0:0.0') 限定為近一日內的紀錄。透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢, 不修改任何狀態;發生例外時靜默回傳 -1

      Parameters:
      bossid - 成就來源的識別字串
      Returns:
      近 24 小時內的領取次數;查無或例外時回傳 -1
    • getGiftLog

      public int getGiftLog(String bossid)
      查詢帳號在過去 24 小時內的禮物(gift)領取次數,用於以帳號為單位的每日禮物閘門。

      bosslog 資料表以 accountid(帳號 id,取自 chr.accountid) 與 bossid 條件計數,並以 SQL lastattempt >= subtime(current_timestamp, '1 0:0:0.0') 限定為近一日內的紀錄。透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢, 不修改任何狀態;發生例外時靜默回傳 -1

      注意:本方法與 getBossLog(String) 查詢**同一張** bosslog 資料表,但比對的是 accountid 欄位(帳號層級),而 getBossLog(String) 比對的是 characterid 欄位(角色層級)。

      Parameters:
      bossid - 禮物來源(王/事件)的識別字串
      Returns:
      近 24 小時內的領取次數;查無或例外時回傳 -1
    • getChronosphereLog

      public int getChronosphereLog(String chronoLog)
      查詢角色在過去 30 天內使用指定時空石的次數,用於 30 天時空石閘門。

      chronolog 資料表以 characterid(角色 id)與 chronid 條件計數, 並以 SQL lastattempt >= subtime(current_timestamp, '30 0:0:0.0') 限定為近 30 日內的紀錄。 透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢,不修改任何狀態; 發生例外時靜默回傳 -1

      Parameters:
      chronoLog - 時空石的識別字串(對應資料表 chronid 欄位)
      Returns:
      近 30 天內的使用次數;查無或例外時回傳 -1
    • setChronosphereLog

      public void setChronosphereLog(String chronoLog)
      為角色寫入一筆時空石使用紀錄。

      chronolog 資料表插入一列(characterid=角色 id、chronid), 其 lastattempt 由資料表預設值帶入當前時間,推進 getChronosphereLog(String) 的 30 天閘門。 經 Db.update(String, Object...) 執行寫入(僅關閉 Statement,不關閉共用 Connection); 發生例外時以 MapleCharacter.log 記錄 debug 並吞掉。

      Parameters:
      chronoLog - 時空石的識別字串(對應資料表 chronid 欄位)
    • periodKeySql

      public static String periodKeySql(ResetType resetType)
      ResetType 對應到「當前週期鍵」的 MySQL 運算式(以 CURDATE() 為基準、伺服器本機時間、日曆邊界)。

      periodKeyOf(ResetType, String)CURDATE() 為日期來源的特例,把「當前時間」 正規化到所屬日曆週期的字串。reset_type 為受控列舉、非外部輸入,回傳值一律為硬編碼常數字串, 直接內嵌進 SQL 無注入風險:

      • ResetType.DAY'2026-06-06'(當日)。
      • ResetType.WEEK'2026-06-01'(本週一;WEEKDAY() 對週一回傳 0,故減去與週一的天數差)。
      • ResetType.MON'2026-06'(本月)。
      • ResetType.NEVER'ALL'(常數,故永遠單一列、永久累計)。

      設計_acc_char_log 不再儲存 period_key 欄位——週期改由 date_created 即時推導(見 periodKeyOf(ResetType, String)periodKeyCase(String)),並以「date_created 推導出的週期」作為 uq_log 唯一鍵的函式索引鍵之一,因此仍是每個週期各自成為一列 (跨週期 → date_created 落在新週期 → 函式索引不命中 → INSERT 新列;同週期 → 命中既有列 → 累加/覆蓋)。 全部在伺服器端以日期函式計算,與 date_createdlast_updateNOW() 同屬一個時區框架, 不受 JDBC 時區轉換影響。

      本方法(當前週期)與 periodKeyOf(ResetType, String)(任意日期來源,供 date_created 推導) 亦由 server.gui.GuiApiServer 共用,使 GUI 管理控制台與遊戲端 getLogsetLog 共用 同一份週期運算邏輯(單一真實來源),故為 public

      Parameters:
      resetType - 重置週期維度
      Returns:
      對應的 MySQL「當前週期鍵」運算式(可直接內嵌至 SQL)
    • periodKeyOf

      public static String periodKeyOf(ResetType resetType, String dateExpr)
      ResetType 與任意「日期來源 SQL 運算式」對應到該日期所屬的週期鍵運算式。

      periodKeySql(ResetType) 的一般化:把出現 CURDATE() 之處換成傳入的 dateExpr, 即可得到「以該日期推導週期」的運算式。兩個主要用途:

      • dateExpr = "CURDATE()" → 當前週期鍵(即 periodKeySql(ResetType))。
      • dateExpr = "`date_created`" → 某一列自其建立時間推導出的週期鍵;此即 uq_log 函式索引採用的運算式,也是 getLog 用來比對「該列是否屬於當前週期」的左運算元。

      dateExpr 為呼叫端提供的受控 SQL 片段(僅 "CURDATE()" 或反引號欄名等常數), 非外部輸入,直接內嵌無注入風險;reset_type 為受控列舉。

      Parameters:
      resetType - 重置週期維度
      dateExpr - 日期來源 SQL 運算式(如 "CURDATE()""`date_created`"
      Returns:
      dateExpr 正規化到所屬週期的 MySQL 運算式(可直接內嵌至 SQL)
    • periodKeyCase

      public static String periodKeyCase(String dateExpr)
      組出涵蓋所有 ResetType 的「週期鍵」CASE 運算式(依每一列的 reset_type 分支)。

      當查詢/索引需要對多種 reset_type 混在一起的列各自取其週期鍵時(例如 uq_log 函式索引、或 GUI 一次撈一個範圍下日/週/月/永久全部的列),無法用單一 periodKeyOf(ResetType, String) 表示,故以 CASE `reset_type` WHEN ... END 對每列套用對應的 periodKeyOf(ResetType, String)

      dateExpr = "`date_created`" 即每列自其建立時間推導的週期鍵(uq_log 函式索引採此式); dateExpr = "CURDATE()" 即「當前週期」。reset_type 為受控列舉、dateExpr 為受控片段, 內嵌無注入風險。

      Parameters:
      dateExpr - 日期來源 SQL 運算式(如 "`date_created`""CURDATE()"
      Returns:
      對每列依其 reset_type 取週期鍵的 CASE 運算式(含外層括號,可直接內嵌至 SQL)
    • setLog

      public void setLog(LogScope scope, ResetType resetType, String eventName)
      對指定維度當前週期的計數 +1(UPSERT)。

      不帶數字的 setLog累加 1:同一週期內每次呼叫使該週期的計數遞增;跨越週期邊界後, 因新列的 date_created 落在新週期、uq_log 函式索引不命中而新增一列(初值 1), 舊週期的列則原樣保留為歷史。若要直接覆蓋當前週期的計數,請改用 setLog(LogScope, ResetType, String, int)

      Parameters:
      scope - 範圍維度(角色/帳號)
      resetType - 重置週期維度(日/週/月/永久)
      eventName - 事件名稱(識別字)
    • setLog

      public void setLog(LogScope scope, ResetType resetType, String eventName, int count)
      把指定維度當前週期的計數覆蓋count(UPSERT)。

      帶數字參數的 setLog覆蓋(非累加):把當前週期那一列的計數直接設為傳入的 count (例如 setLog(..., 0) 會把當前週期歸零、setLog(..., 7) 設為 7)。當前週期尚無列時則以該值 INSERT 新列;舊週期的列不受影響。若要遞增,請用不帶數字的 setLog(LogScope, ResetType, String)

      Parameters:
      scope - 範圍維度;LogScope.ACCchar_id 填哨兵 0LogScope.CHAR 時填角色 id
      resetType - 重置週期維度(日/週/月/永久)
      eventName - 事件名稱(識別字)
      count - 要覆蓋寫入的計數值
    • getLog

      public int getLog(LogScope scope, ResetType resetType, String eventName)
      取得指定維度在當前週期內的計數。

      以「該列 date_created 推導之週期 = 當前週期鍵」(periodKeyOf(ResetType, String)periodKeySql(ResetType))查詢 _acc_char_log 對應唯一鍵的計數:若當前週期尚無列 (即尚未在本週期寫入過),一律回傳 0;舊週期的歷史列不會被讀到。透過 DatabaseConnection 取得共用 Connection 執行唯讀查詢,不修改任何狀態;發生例外時記錄 debug 並回傳 0

      Parameters:
      scope - 範圍維度(角色/帳號)
      resetType - 重置週期維度(日/週/月/永久)
      eventName - 事件名稱(識別字)
      Returns:
      當前週期內的計數;當前週期查無或發生例外時回傳 0