FiveMでRankとXPを作る【character_id単位で進行度を管理します】

HaruuuCoreのhc_progressionで、character_id単位のRank / XP、DB保存、XP加算、Rank再計算、progression stateの責務を整理します。

この記事の見出し 開く

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 ごとの rankxptotal_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_moneyhc_progression をそれぞれ呼ぶ形にします。

hc_progression が担当しないこと:
  job 成功判定
  delivery complete 判定
  money 付与本体
  reward cash 決定
  UI 表示
  常時 HUD
  notification
  audit log
  XP log table
  複数 skill rank
  character stats
  job proficiency

sourceは永続基準にしない

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_selected

Rank / 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 = 0

lazy 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 += 50

Rank 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_deliverytier2_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 = 2

Rank 不足時の 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_selectedinvalid_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_selected

character 選択後は、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 が決まっていません。

/charui

character selection UI から character を選びます。 開発中に command で確認する場合は、slot を指定して選択します。

/selectchar 1
/rank
/xp
/addxp_test 100
/rank

XP 加算後に /rank を実行し、Rank、現在 Rank 内 XP、nextRequiredXp、totalXp が変わることを確認します。 必要 XP を超えた場合は Rank up し、余った XP は次 Rank へ持ち越されます。

/tpcoords 152.82 -3211.76 6.12 345.82

delivery 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 基盤は動き始めました。

見出しへ戻る 開く