Class CharacterLogManager
MapleCharacter。
本類別封裝對 bosslog(王挑戰每日次數)、onetimelog(一次性事件旗標)、
prizelog/aclog(領獎/成就領取閘門)、chronolog(時空石 30 天閘門)等
資料表的計數查詢與插入,這些紀錄被遊戲內容用來實作「每日/一次性」挑戰與領獎限制。
MapleCharacter 以**逐字搬移**的方式把這些方法移入此處,並對每個對外公開方法保留
**簽名完全相同**的委派(delegate),因此所有 Java 呼叫端與 ~2,700 支腳本完全不受影響。協作者僅
持有對所屬角色的回參考,沿用其角色 id/帳號 id(同 package 存取)與共用的 SLF4J logger
(MapleCharacter.log)。
-
Method Summary
Modifier and TypeMethodDescriptionint查詢帳號在過去 24 小時內領取指定成就的次數,用於每日成就領取閘門。intgetBossLog(String bossid) 查詢角色在過去 24 小時內挑戰指定王的次數,用於每日王挑戰次數閘門。intgetChronosphereLog(String chronoLog) 查詢角色在過去 30 天內使用指定時空石的次數,用於 30 天時空石閘門。intgetGiftLog(String bossid) 查詢帳號在過去 24 小時內的禮物(gift)領取次數,用於以帳號為單位的每日禮物閘門。int取得指定維度在當前週期內的計數。intgetOneTimeLog(String log) 查詢角色是否已有指定一次性事件旗標,用於「一次性」事件閘門。intgetPrizeLog(String bossid) 查詢帳號是否已領取指定獎勵,用於以帳號為單位的領獎閘門。static StringperiodKeyCase(String dateExpr) static StringperiodKeyOf(ResetType resetType, String dateExpr) 把ResetType與任意「日期來源 SQL 運算式」對應到該日期所屬的週期鍵運算式。static StringperiodKeySql(ResetType resetType) 把ResetType對應到「當前週期鍵」的 MySQL 運算式(以CURDATE()為基準、伺服器本機時間、日曆邊界)。void為帳號寫入一筆成就領取紀錄。voidsetBossLog(String bossid) 為角色寫入一筆指定王的挑戰紀錄。voidsetChronosphereLog(String chronoLog) 為角色寫入一筆時空石使用紀錄。void對指定維度當前週期的計數+1(UPSERT)。void把指定維度當前週期的計數覆蓋為count(UPSERT)。voidsetOneTimeLog(String log) 為角色寫入一筆一次性事件旗標。voidsetPrizeLog(String bossid) 為帳號寫入一筆領獎紀錄。
-
Method Details
-
getBossLog
查詢角色在過去 24 小時內挑戰指定王的次數,用於每日王挑戰次數閘門。對
bosslog資料表以characterid(角色 id)與bossid條件計數, 並以 SQLlastattempt >= subtime(current_timestamp, '1 0:0:0.0')限定為近一日內的紀錄。 透過DatabaseConnection取得當前執行緒共用的Connection執行唯讀查詢, 不會修改任何狀態;查詢過程中發生任何例外時靜默回傳-1。- Parameters:
bossid- 王的識別字串- Returns:
- 近 24 小時內的挑戰次數;查無紀錄或發生例外時回傳
-1
-
setBossLog
為角色寫入一筆指定王的挑戰紀錄。對
bosslog資料表插入一列(characterid=角色 id、bossid), 其lastattempt由資料表預設值帶入當前時間,藉此推進getBossLog(String)的每日計數。 經Db.update(String, Object...)執行寫入(僅關閉Statement,不關閉共用Connection); 發生例外時以MapleCharacter.log記錄 debug 並吞掉。- Parameters:
bossid- 王的識別字串
-
getOneTimeLog
查詢角色是否已有指定一次性事件旗標,用於「一次性」事件閘門。對
onetimelog資料表以characterid(角色 id)與log條件計數 (不含時間限制,故為永久旗標)。透過DatabaseConnection取得共用Connection執行唯讀查詢,不修改任何狀態;發生例外時靜默回傳-1。- Parameters:
log- 一次性事件的識別字串- Returns:
- 符合的紀錄筆數(
0表示尚未觸發、大於0表示已觸發);查無或例外時回傳-1
-
setOneTimeLog
為角色寫入一筆一次性事件旗標。對
onetimelog資料表插入一列(characterid=角色 id、log), 使getOneTimeLog(String)之後對同一旗標永久回傳大於0。 經Db.update(String, Object...)執行寫入(僅關閉Statement,不關閉共用Connection); 發生例外時以MapleCharacter.log記錄 debug 並吞掉。注意:參數名
log與類別共用 logger 同名,方法內部記錄一律以MapleCharacter.log限定。- Parameters:
log- 一次性事件的識別字串
-
setPrizeLog
為帳號寫入一筆領獎紀錄。對
prizelog資料表插入一列(accid=帳號 id、bossid), 推進getPrizeLog(String)的領取計數。注意此閘門以**帳號**為單位 (取自chr.getClient().getAccID()),而非角色。 經Db.update(String, Object...)執行寫入(僅關閉Statement,不關閉共用Connection); 發生例外時以MapleCharacter.log記錄 debug 並吞掉。- Parameters:
bossid- 領獎來源(王/事件)的識別字串
-
getPrizeLog
查詢帳號是否已領取指定獎勵,用於以帳號為單位的領獎閘門。對
prizelog資料表以accid(帳號 id,取自chr.getClient().getAccID()) 與bossid條件計數(不含時間限制,故為永久領取旗標)。透過DatabaseConnection取得共用Connection執行唯讀查詢,不修改任何狀態;發生例外時靜默回傳-1。- Parameters:
bossid- 領獎來源(王/事件)的識別字串- Returns:
- 符合的紀錄筆數(大於
0表示已領取);查無或例外時回傳-1
-
setAcLog
為帳號寫入一筆成就領取紀錄。對
aclog資料表插入一列(accid=帳號 id、bossid), 其lastattempt由資料表預設值帶入當前時間,推進getAcLog(String)的每日成就閘門。 此閘門以**帳號**為單位(取自chr.getClient().getAccID())。 經Db.update(String, Object...)執行寫入(僅關閉Statement,不關閉共用Connection); 發生例外時以MapleCharacter.log記錄 debug 並吞掉。- Parameters:
bossid- 成就來源的識別字串
-
getAcLog
查詢帳號在過去 24 小時內領取指定成就的次數,用於每日成就領取閘門。對
aclog資料表以accid(帳號 id,取自chr.getClient().getAccID()) 與bossid條件計數,並以 SQLlastattempt >= subtime(current_timestamp, '1 0:0:0.0')限定為近一日內的紀錄。透過DatabaseConnection取得共用Connection執行唯讀查詢, 不修改任何狀態;發生例外時靜默回傳-1。- Parameters:
bossid- 成就來源的識別字串- Returns:
- 近 24 小時內的領取次數;查無或例外時回傳
-1
-
getGiftLog
查詢帳號在過去 24 小時內的禮物(gift)領取次數,用於以帳號為單位的每日禮物閘門。對
bosslog資料表以accountid(帳號 id,取自chr.accountid) 與bossid條件計數,並以 SQLlastattempt >= subtime(current_timestamp, '1 0:0:0.0')限定為近一日內的紀錄。透過DatabaseConnection取得共用Connection執行唯讀查詢, 不修改任何狀態;發生例外時靜默回傳-1。注意:本方法與
getBossLog(String)查詢**同一張**bosslog資料表,但比對的是accountid欄位(帳號層級),而getBossLog(String)比對的是characterid欄位(角色層級)。- Parameters:
bossid- 禮物來源(王/事件)的識別字串- Returns:
- 近 24 小時內的領取次數;查無或例外時回傳
-1
-
getChronosphereLog
查詢角色在過去 30 天內使用指定時空石的次數,用於 30 天時空石閘門。對
chronolog資料表以characterid(角色 id)與chronid條件計數, 並以 SQLlastattempt >= subtime(current_timestamp, '30 0:0:0.0')限定為近 30 日內的紀錄。 透過DatabaseConnection取得共用Connection執行唯讀查詢,不修改任何狀態; 發生例外時靜默回傳-1。- Parameters:
chronoLog- 時空石的識別字串(對應資料表chronid欄位)- Returns:
- 近 30 天內的使用次數;查無或例外時回傳
-1
-
setChronosphereLog
為角色寫入一筆時空石使用紀錄。對
chronolog資料表插入一列(characterid=角色 id、chronid), 其lastattempt由資料表預設值帶入當前時間,推進getChronosphereLog(String)的 30 天閘門。 經Db.update(String, Object...)執行寫入(僅關閉Statement,不關閉共用Connection); 發生例外時以MapleCharacter.log記錄 debug 並吞掉。- Parameters:
chronoLog- 時空石的識別字串(對應資料表chronid欄位)
-
periodKeySql
把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_created/last_update的NOW()同屬一個時區框架, 不受 JDBC 時區轉換影響。本方法(當前週期)與
periodKeyOf(ResetType, String)(任意日期來源,供date_created推導) 亦由server.gui.GuiApiServer共用,使 GUI 管理控制台與遊戲端getLog/setLog共用 同一份週期運算邏輯(單一真實來源),故為public。- Parameters:
resetType- 重置週期維度- Returns:
- 對應的 MySQL「當前週期鍵」運算式(可直接內嵌至 SQL)
-
periodKeyOf
把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
組出涵蓋所有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
對指定維度當前週期的計數+1(UPSERT)。不帶數字的
setLog即累加 1:同一週期內每次呼叫使該週期的計數遞增;跨越週期邊界後, 因新列的date_created落在新週期、uq_log函式索引不命中而新增一列(初值1), 舊週期的列則原樣保留為歷史。若要直接覆蓋當前週期的計數,請改用setLog(LogScope, ResetType, String, int)。- Parameters:
scope- 範圍維度(角色/帳號)resetType- 重置週期維度(日/週/月/永久)eventName- 事件名稱(識別字)
-
setLog
把指定維度當前週期的計數覆蓋為count(UPSERT)。帶數字參數的
setLog為覆蓋(非累加):把當前週期那一列的計數直接設為傳入的count(例如setLog(..., 0)會把當前週期歸零、setLog(..., 7)設為 7)。當前週期尚無列時則以該值 INSERT 新列;舊週期的列不受影響。若要遞增,請用不帶數字的setLog(LogScope, ResetType, String)。- Parameters:
scope- 範圍維度;LogScope.ACC時char_id填哨兵0,LogScope.CHAR時填角色 idresetType- 重置週期維度(日/週/月/永久)eventName- 事件名稱(識別字)count- 要覆蓋寫入的計數值
-
getLog
取得指定維度在當前週期內的計數。以「該列
date_created推導之週期 = 當前週期鍵」(periodKeyOf(ResetType, String)/periodKeySql(ResetType))查詢_acc_char_log對應唯一鍵的計數:若當前週期尚無列 (即尚未在本週期寫入過),一律回傳0;舊週期的歷史列不會被讀到。透過DatabaseConnection取得共用Connection執行唯讀查詢,不修改任何狀態;發生例外時記錄 debug 並回傳0。- Parameters:
scope- 範圍維度(角色/帳號)resetType- 重置週期維度(日/週/月/永久)eventName- 事件名稱(識別字)- Returns:
- 當前週期內的計數;當前週期查無或發生例外時回傳
0
-