前書き
hero_chest_rank<public> := enum<open>:
C
B
A
S
最近の更新で、列挙型(enum)に対する<open>と<closed>というエフェクト指定子が追加されました。公式ドキュメントにも詳細が追記されています。
<open> 現在、列挙型にのみ適用できます。
オープンの列挙型にある列挙値を追加または並べ替えたり、<closed> の列挙型に変更したりすることができます。
オープンの列挙型は、列挙型内の値の数が将来的に増加する可能性がある場合に最適です。 たとえば、武器タイプの列挙型があります。
<closed> 現在、列挙型にのみ適用できます。
列挙型はデフォルトでクローズドの状態です。
クローズドの列挙型は、曜日のように値が変わらないことが想定されるケースに最適です。
https://dev.epicgames.com/documentation/ja-jp/fortnite/enum-in-verse
Open
まずはopen指定子についてですが、簡単に説明すると「enumの中身が今後増える可能性がある」ということを明示するための機能となります。マップ制作において武器の種類やスキルなどをジャンル分けしたい場合に、enumで管理するということが多く発生するはずです。
通常の作業において、enumの中身を書き換えたとしてもそこまで重大な問題が起こることはないかと思います。caseのようなもので分岐させる処理を書いていたとしても、追加のタイミングで書き直せばよいので。
しかし、Verseの永続化を組み合わせると話は別となってきます。
weapon_type := enum<persistable>:
Assault
Shotgun
SMG
このようなpersistableの列挙型を作った場合、マップを公開した時点で中身を書き換えるのが禁止されます。特に、open指定子が無いバージョンではenumの中身を変更するために、weapon_type2のようなまた新たな列挙型を作成するか、enumを整数に変換してInt型の変数で永続データを管理するといった手法も使われてきました。
しかし、当然管理する上では不便なことこの上ないため、
weapon_type := enum<persistable><open>:
Assault
Shotgun
SMG
のような<open>指定子を足してあげることで、中身を書き換えることができない制限を緩和できるようになりました。
では、open指定子を足した場合の仕様も軽く見ていきます。
1. マップ公開後にも中身を足せる
# Version: 1
weapon_type := enum<persistable><open>:
Assault
Shotgun
SMG
# Version: 2
weapon_type := enum<persistable><open>:
Assault
Shotgun
SMG
Sniper
open指定子は列挙型の中身を書き換える可能性があると明示できる機能です。そのため、persistableのenumでマップを公開したとしても、その後に値を増やして公開してもエラーが発生しなくなります。
openをつけなかった場合
VerseBuild: Error: C:/build/FortniteGame/Plugins/GameFeatures/c5cf078b-43f9-1c1e-5d89-18aaa527a9c2/Content/PersistableDataTest.verse(4,14, 4,15): Script error 3645: This enumerator is not present in the published definition of the enumeration. Adding enumerators is not allowed as it can break exhaustive case expressions.
open指定子をつけない状態で中身を増やし、マップを公開すると「Verse の持続性」のチェックでエラーが発生します。
2. caseはdefaultが必須となる
weapon_type := enum<open>:
Assault
Shotgun
SMG
# 使用箇所
var WeaponType:weapon_type = weapon_type.Assault
case(WeaponType):
weapon_type.Assault=>
Print("中身はアサルト")
weapon_type.Shotgun=>
Print("中身はショットガン")
weapon_type.SMG=>
Print("中身はサブマシンガン")
_=>
Print("中身は未定")
中身が書き換わる前提であるため、_=>を用いたデフォルトのcaseが必須となります。もし、weapon_typeの中身が増えたとしても、コード使用側で追加のエラーは発生せず、増えた分は「_=>」がキャッチしてそこでの処理が実行されるというわけです。もちろん、追加後に「weapon_type.Sniper=>」のような条件を増やすこともできます。
3. 減らすことはできない
# Version: 2 (エラー)
weapon_type := enum<persistable><open>:
Assault
Shotgun
特にVerse永続データを組み合わせる際に意識すべきことですが、追加は可能でも「減らす」ということは一切禁止されたままです。増やす分にはcaseのデフォルトで対応できるが、減らすとなるとその時点で存在しないenumに対応した処理が発生してしまうからです。
4. 順番を変える
# Version: 1
weapon_type := enum<persistable><open>:
SMG
Assault
Shotgun
あまり使用する機会はないと思いますが、一応open指定子をつけると中身の順番を変えることができます。
closed
weapon_type := enum<persistable><closed>:
Assault
Shotgun
SMG
closedも一応見ていきます。こちらはenumに対して追加しなくてもデフォルトで付与されている指定子で、仕様としては「中身の書き換え」「追加/削除」のようなことは一切行えません。
また、open指定子からclosed指定に変更することはできますが、「closed」から「open」に変更することはできません。
最後に
Verseの永続データはかなりの曲者で、色々な場面で制限がかけられていました。その中の一つである「列挙型の編集」に対する対応策として今回追加されました。
weapon_type := enum:
Assault
Shotgun
SMG
(WeaponType:weapon_type).ToInt()<transacts>:int=
case(WeaponType):
weapon_type.Assault=> 0
weapon_type.Shotgun=> 1
weapon_type.SMG=> 2
save_data := class<final><persistable>:
EquippedWeapon:int = 0
のように、数字での管理をしていた人もいるはずです。
特に長期運営するうえで数字での管理となると必ずケアレスミスやある値に対する対応し忘れなども発生するはずです。減らせるというメリットも一応にはあるのですが、、、こちらも減らした分の対応コストが必ず発生するのであまりオススメはしません。
ということで、ひょっこりと追加されていた<open>と<closed>指定子でした。ぜひ活用してみてくださいね。