RankとXPをcharacter_idに紐づける理由
HaruuuCore では、接続中の player を表す source、アカウント側の識別子である identifier、ゲーム内キャラクターの実体である character_id を分けて扱います。
money と同じく、Rank / XP も account 直下ではなく、selected character に紐づく gameplay data として扱います。
1つの identifier が複数の character slot を持てる場合、Rank / XP を identifier に直接持たせると、別 character 間で進行度が混ざります。 生活、仕事、犯罪歴、所有物、解放状態は character ごとに分かれるほうが自然です。
この作業では、hc_progression を追加し、character_id ごとの rank、xp、total_xp を DB に保存し、XP 加算と Rank up 判定を行える状態まで確認しました。
hc_progressionが担当する範囲
hc_progression は、Rank / XP の正本 resource です。
どの character を操作中にするかは hc_core 側で管理し、hc_progression はその selected character_id を基準に progression state を扱います。
hc_progression:
character_id ごとの rank / xp / total_xp 管理
hc_character_progression table 自動作成
progression row の lazy create
hc_core:getCharacterId(source) による character_id 解決
XP 加算
rank up 判定
total_xp 更新
requiredRank 判定
/rank
/xp
/addxp_test
server exports逆に、hc_progression は job の成功判定や money 付与本体を担当しません。
job / mission resource 側が、成功時に hc_money と hc_progression をそれぞれ呼ぶ形にします。
hc_progression が担当しないこと:
job 成功判定
delivery complete 判定
money 付与本体
reward cash 決定
UI 表示
常時 HUD
notification
audit log
XP log table
複数 skill rank
character stats
job proficiencysourceは永続基準にしない
source は FiveM の接続中 player handle です。
reconnect や接続順によって変わるため、Rank / XP の保存単位には使いません。
hc_progression では、処理の入口では source を受け取り、そこから hc_core:getCharacterId(source) を使って selected character_id を解決します。
DB へ保存する progression state は、最終的に character_id を基準にします。
source
↓
hc_core:getCharacterId(source)
↓
character_id
↓
hc_character_progressionこの流れにすることで、接続中だけの一時 ID と、DB 上の永続 character を分けられます。 money、job、ownership、inventory などを今後追加する場合も、同じく character_id ベースへそろえやすくなります。
character未選択時はprogressionを扱わない
character がまだ選択されていない場合、hc_core:getCharacterId(source) は progression の対象になる character_id を返せません。
この状態では、Rank / XP の操作を行いません。
character未選択:
selected character_id = nil
progression target = nil
progression operation = skip / reject代表 reason は character_not_selected です。
接続直後や character selection UI を開いているだけの状態では、これは異常ではありません。
まだ進行度を紐づける character が決まっていない状態として扱います。
/rank
rank unavailable reason=character_not_selectedRank / XP を確認したい場合は、先に character を select します。
UI から選択してもよいですし、開発中は /selectchar 1 のような command で確認できます。
progression rowをlazy createする
hc_progression は、起動時に hc_character_progression table を作成します。
ただし、すべての character に対して最初から progression row を作るのではなく、必要になったタイミングで lazy create します。
hc_character_progression
├── character_id
├── rank
├── xp
├── total_xp
├── created_at
└── updated_at初期値は、Rank 1、XP 0、total XP 0 です。
初めて /rank、/xp、XP 加算などで progression が必要になったとき、存在しなければ row を作成します。
default progression:
rank = 1
xp = 0
total_xp = 0lazy create にしておくと、character 作成直後に progression を必ず初期化する必要がありません。 progression が実際に必要になったタイミングで作成されるため、character resource と progression resource の結合も弱くできます。
xpとtotal_xpを分ける
xp は、現在 Rank 内の進捗です。
一方で、total_xp は累積 XP です。
Rank up した場合、xp は必要 XP を差し引いた残りになりますが、total_xp は減らしません。
rank=3
xp=50
total_xp=350この場合、character は Rank 3 の途中で、現在 Rank 内 XP が 50、累積 XP が 350 という意味です。
total_xp を残しておくことで、将来的な集計、履歴、balance 調整にも使える余地を残します。
Rank 表示や次 Rank までの進捗には xp を使い、長期的な累積値として total_xp を残す設計です。
XPを加算してRankを再計算する
XP を加算すると、現在 Rank の必要 XP と比較し、必要量を超えた場合は Rank up します。 余った XP は次 Rank に持ち越します。
rank=1
xp=75
required=100
add=50
result:
rank=2
xp=25
total_xp += 50Rank up 判定は server 側で行います。
client から XP amount や Rank を信用せず、job / mission / transaction の成功を server 側で確認したあとに、server resource から addXp を呼びます。
server:
job / mission / transaction 成功確認
XP amount 決定
hc_progression:addXp(...)
rank up 判定
total_xp 更新この時点では、Rank up notification や XP HUD は実装しません。 まずは server / DB authoritative な progression state を成立させることを優先します。
MAX_RANKは100にする
現時点の最大 Rank は 100 です。 Rank 100 は短期で到達する値ではなく、長期目標として扱います。
MAX_RANK = 100
DEFAULT_RANK = 1
DEFAULT_XP = 0
DEFAULT_TOTAL_XP = 0必要 XP は、Rank 帯ごとに重くなる仮テーブルとして server 側で生成しています。
将来的には config.lua に分離する候補ですが、現時点では server/main.lua 内で Rank 帯ごとに必要 XP を組み立てます。
Rank 1〜10:
軽め
Rank 11〜25:
中程度
Rank 26〜50:
徐々に重い
Rank 51〜75:
明確に重い
Rank 76〜100:
長期目標としてかなり重いMAX_RANK に到達した場合は、Rank 100、XP 0 として扱います。 それ以上 Rank を上げる処理は行いません。
character slot unlockには使わない
Rank は progression の土台ですが、character slot unlock には使いません。 HaruuuCore では、character slot は初期から最大3枠を利用できる方針にしています。
character slot:
Rankでは解放しない
初期から最大3枠を利用可能Rank を character slot に使うと、別 character を作ること自体が進行度に縛られます。 HaruuuCore では、slot は player がキャラクターを分けるための枠として扱い、Rank は gameplay の解放条件に使う候補として残します。
Rank unlock候補:
job tier
farming crop
farm size
property tier
business tier
garage size
vehicle shop tier
vehicle custom tier
clothes category
black market tier
crime mission tier
NPC worker tier現在は、hc_job_delivery の tier2_delivery unlock で Rank 判定を使っています。
ただし、本格的な unlock registry や unlock UI はまだ作りません。
delivery jobからXPへ接続する
hc_progression は job の成功判定をしません。
delivery complete の判定、reward cash の決定、job state の管理は hc_job_delivery の責務です。
delivery job 側で成功を確認したあと、money と XP をそれぞれの resource へ渡します。 これにより、cash 付与と XP 加算を分離できます。
exports['hc_money']:addMoney(source, 'cash', rewardCash)
exports['hc_progression']:addXp(source, 'job_delivery_complete', rewardXp)現在の delivery reward では、basic delivery が XP 25、tier2 delivery が XP 50 です。
tier2 delivery は requiredRank 2 として扱い、開始時に hasRank で判定します。
basic_delivery:
rewardXp = 25
requiredRank = 1
tier2_delivery:
rewardXp = 50
requiredRank = 2Rank 不足時の reason は delivery_rank_required_2 のように返します。
hc_progression は requiredRank 以上かどうかを返すだけで、delivery の開始可否や表示文言の最終判断は job resource 側に残します。
server exportsを用意する
Rank / XP は、他 resource から参照・更新される前提です。
そのため、hc_progression では server exports を用意し、job や mission resource が直接 DB を触らなくてよい形にします。
exports:
getProgression(source)
getProgressionByCharacterId(characterId)
getRank(source)
getRankByCharacterId(characterId)
getXp(source)
getXpByCharacterId(characterId)
addXp(source, reason, amount)
addXpByCharacterId(characterId, reason, amount)
hasRank(source, requiredRank)
hasRankByCharacterId(characterId, requiredRank)通常は source を渡す exports を使い、内部で selected character_id を解決します。
character_id がすでに確定している server-side 処理では、ByCharacterId 系の exports を使えます。
local progression, reason = exports['hc_progression']:getProgression(source)
local success, resultOrReason = exports['hc_progression']:addXp(source, 'job_delivery_complete', 25)
local hasRank, reason = exports['hc_progression']:hasRank(source, 2)reason は内部識別子として扱います。
たとえば delivery 完了時は job_delivery_complete を渡し、失敗時には character_not_selected や invalid_amount などの reason を返します。
clientにXP量を決めさせない
Rank / XP は server / DB authoritative として扱います。 client から任意の XP 量、Rank、unlock 結果を送らせる設計にはしません。
禁止する考え方:
client → addXp(1000)
client → setRank(50)
client → unlock(vehicle_custom_tier_4)
採用する考え方:
serverで成功判定する
serverでXP量を決める
serverでaddXpを呼ぶ
serverでrank upを判定するclient は表示や操作入力の入口にはなりますが、XP amount や unlock 成否の正本にはしません。 job complete、mission success、transaction complete などの判定は server resource 側で行います。
これにより、progression を gameplay system の基盤として使うときも、client 側の任意入力で Rank が変わる状態を避けられます。
テストコマンドで確認する
progression の挙動は、まず command で確認します。 character selection、Rank 表示、XP 加算、Rank up、delivery reward との接続を段階的に見ます。
/rank/rank は、現在の Rank / XP を表示します。
character 未選択時は character_not_selected になります。
rank unavailable reason=character_not_selectedcharacter 選択後は、character_id、rank、xp、nextRequiredXp、totalXp が表示されます。
character_id=<id> rank=1 xp=0 nextRequiredXp=100 totalXp=0/xp/xp は、現時点では /rank と同じ内容を表示します。
Rank と XP のどちらの確認からでも同じ progression state を見られるようにしています。
/addxp_test 100
/addxp_test 1000/addxp_test は開発用の XP 加算 command です。
本番 player 向けの command ではありません。
公開運用では permission や command policy に合わせて制限する前提です。
確認した流れ
久しぶりに Rank / XP を確認する場合は、まず character を選択してから progression command を実行します。 character 未選択のままでは progression target が決まっていません。
/charuicharacter selection UI から character を選びます。 開発中に command で確認する場合は、slot を指定して選択します。
/selectchar 1
/rank
/xp
/addxp_test 100
/rankXP 加算後に /rank を実行し、Rank、現在 Rank 内 XP、nextRequiredXp、totalXp が変わることを確認します。
必要 XP を超えた場合は Rank up し、余った XP は次 Rank へ持ち越されます。
/tpcoords 152.82 -3211.76 6.12 345.82delivery job と接続して確認する場合は、Delivery Office へ移動して basic delivery を完了します。 basic delivery では XP +25、tier2 delivery では XP +50 が入ることを確認します。
Rank unlockを確認する
hc_progression では、requiredRank 判定として hasRank を用意しています。
現在は hc_job_delivery の tier2 delivery 開始条件で使います。
Rank 1:
tier2_delivery rejected
reason = delivery_rank_required_2
Rank 2以上:
tier2_delivery startedここで重要なのは、hc_progression が delivery の marker、blip、route、complete 判定を担当しないことです。
hc_progression は requiredRank を満たしているかを返し、delivery の詳細は hc_job_delivery に残します。
Rank unlock は今後の job tier、property tier、vehicle custom tier などにも使える候補ですが、現時点では full unlock system までは作りません。
現時点でやらないこと
hc_progression は、Rank / XP の最小基盤として作っています。
そのため、今後必要になりそうなものでも、現時点では入れない範囲を明確にしています。
現時点でやらないこと:
full unlock system
unlock UI
Rank up notification
XP HUD
XP log table
audit log
config.lua 分離
複数 skill rank
job proficiency
Life Rank / Business Rank / Criminal Reputation 分離
character stats
external leaderboard
account rank
permission 付き admin XP command特に、job proficiency や character stats は Rank / XP と近く見えますが、別 system として考えます。 まずは共通の progression state として、character_id ごとの Rank / XP を成立させる段階です。
RankとXPで到達した状態
この作業で、HaruuuCore は character ごとの progression state を持てるようになりました。 Rank / XP は selected character_id を基準に保存され、job や mission から呼び出せる server exports として整理しました。
確認済み:
hc_progression resource が起動する
hc_character_progression table が作成される
progression row が lazy create される
character 未選択時に /rank が character_not_selected になる
character 選択後に /rank が表示される
/xp が /rank と同じ内容を表示する
/addxp_test で XP を加算できる
必要 XP 到達時に rank up する
total_xp が累積される
addXp が source から selected character_id を解決して XP を付与する
hasRank が requiredRank 判定に使える
basic_delivery complete で XP +25 される
tier2_delivery complete で XP +50 される
Rank 1 では tier2_delivery が拒否される
Rank 2 以上では tier2_delivery が開始できるまだ扱っていないものもあります。 Rank up notification、XP HUD、XP log table、audit log、unlock UI、permission 付き admin XP command などは未実装です。
ただし、character_id ごとの rank / xp / total_xp、XP 加算、Rank up、delivery reward との接続、requiredRank 判定が入ったことで、HaruuuCore の progression 基盤は動き始めました。