変化するデザイナーデータと変化するプレーヤーデータを管理する方法


14

プレイヤーが何らかの方法で世界を形作るオンラインゲームを持っています-例えば。世界地図の特定の部分に直接家を建てることができるウルティマオンラインの住宅。これらは、永続的な世界の一部として時間とともに持続する必要がある変更です。

同時に、デザインチームは新しいコンテンツを追加し、古いコンテンツを修正して、新しいプレーヤーのためにゲームを改善および拡張しています。彼らは最初にテスト中に開発サーバー上でこれを行い、その後、ライブサーバー上のプレイヤーの「作業」に自分の作業をマージする必要があります。

ゲームデザインの問題を修正すると仮定します。プレーヤーは指定された領域でのみ構築できるため、デザイナーの編集と地理的に衝突することはありません- 新しいデザイナーデータが新しいプレーヤーデータとマージされるときに競合を避けるためにデータを処理したりデータ構造を配置する良い方法は何ですか?

例1:プレーヤーが新しいタイプのアイテムを作成すると、ゲームはそれにID 123456を割り当てます。そのアイテムのインスタンスはすべて123456を参照します。ゲームデザイナーが同様のシステムを持ち、デザイナーが123456という番号の新しいアイテムを作成するとします。これを回避するにはどうすればよいですか?

例2:誰かがすべてのドラゴンにフランス語のアクセントを与える人気のあるMODを作成します。これには、新しいassignFrenchAccentドラゴンオブジェクトに新しい音声アセットを割り当てるために使用する、新しいオブジェクトと呼ばれるスクリプトが含まれています。しかし、同じ名前のオブジェクトを持つ「ナポレオン対スマウグ」DLCを展開しようとしています-多くの顧客サービスの問題なくこれを行うにはどうすればよいですか?

私は次の戦略を考えました:

  • 2つの個別のファイル/ディレクトリ/データベースを使用できますが、読み取り操作は非常に複雑です。「すべてのアイテムを表示」では、デザイナーDBで1回の読み取りを実行し、プレーヤーDBで1回の読み取りを実行する必要があります(それでも2を区別する必要があります)。
  • 1つのストア内で2つの異なる名前空間を使用できます。文字列を主キーとして使用し、接頭辞に「DESIGN:」または「PLAYER:」を付けますが、これらの名前空間の作成は簡単ではなく、依存関係は明確ではありません。(たとえば、RDBMSでは、文字列を主キーとして効率的に使用できない場合があります。整数を使用して、特定の数(100万など)未満のすべての主キーをデザイナーデータに割り当て、そのポイントより上のすべてを割り当てることができますただし、その情報はRDBMSからは見えず、外部キーリンクは「分割」を通過します。つまり、すべてのツールとスクリプトは明示的に回避する必要があります。
  • 同じ共有データベースでいつでもリアルタイムで作業できますが、パフォーマンスが低下したり、プレーヤーのデータが破損するリスクが高まる場合があります。また、異なるワールドデータを持つ複数のサーバーで実行されるゲームには適用されません。
  • ...他のアイデアはありますか?

これは主にオンラインゲームの問題ですが、開発者がゲームにパッチを適用すると同時にコミュニティがMODを作成するMODにも概念が適用される可能性があります。新しいパッチがリリースされたときにmodが壊れる可能性を減らすために、ここで使用されている戦略はありますか?

また、これを「バージョン管理」としてタグ付けしました。これは、あるレベルでは、これが何であるかということです。マージが必要なデータ開発の2つのブランチです。おそらく、その方向からの洞察がいくつかあるかもしれません。

編集-問題を明確にするために、上にいくつかの例を追加しました。この問題は、実際にはネームスペースの1つであり、複合キーを介してストアに実装できると考え始めています。これにより、少なくともマージ戦略が簡素化されます。しかし、私が見ていない選択肢があるかもしれません。


1
これに対する答えは、少なくとも部分的には、デザイナーが追加するデータの種類とプレーヤーが追加するデータに依存する可能性があると思います。
lathomas64

可能性はありますが、私は両方の当事者が単一のデータストアに貢献する一般的なソリューションに興味があります。
キロタン

1
多くの人がこの質問の要点を見逃しています。競合するのはプレイヤーの変更ではなく、コンテンツの更新など、既存のレイアウトを壊します。@カイロタンは正しいですか?
ジョナサンディキンソン

開発者コンテンツの更新がプレーヤーコンテンツの更新と衝突する可能性がある場所です。ゲームデザインの回避策(たとえば、プレイヤーが特定の場所でのみビルドできるようにする)にはあまり興味がありませんが、データ構造の回避策(たとえば、100万を超えるIDを持つもののみ作成できるようにする)には興味がありません。
キロタン

2
あなたは指定しなかった、あなたはライブの世界にリアルタイムの更新を行うことを期待していますか?補足説明:単一のデータストアに貢献する2つの関係者はデータベースであり、データベースが行うことです。その事実を回避することはできません。共有データの問題を回避する方法に関する何十年もの知識を無視するのは愚かなことです。
パトリックヒューズ

回答:


2

DBソリューションを提案する答えは、問題を理解せずに特定の実装にジャンプしていると思います。データベースはマージを容易にするものではなく、データを保存するためのフレームワークを提供するだけです。競合は、DB内にある場合でも競合です。そして、チェックアウトは問題に対する貧乏人の解決策です-それは機能しますが、あなたのユーザビリティに大きな負担をかけます。

ここで話していることは、問題の分散開発モデルに該当します。私が信じる最初のステップは、プレイヤーとデザイナーを別々のタイプのコンテンツクリエーターと考えないことです。これにより、ソリューションに影響を与えない人工的な次元が問題から取り除かれます。

事実上、メインライン-開発者が承認した正規バージョンがあります。(おそらく)他のブランチもあります-ライブサーバーは、人々が積極的にmodを開発および共有しています。コンテンツはどのブランチにも追加できます。ここで重要なことは、デザイナーはここで特別なことではありません-彼らはたまたま社内に住んでいるコンテンツクリエーターです(そして、それらを見つけて、手に負えなくなったらヒットさせることができます)。

ユーザーが生成したコンテンツを受け入れることは、標準的なマージの問題です。それらの変更をメインラインに戻し、マージしてから再度プッシュするか、メインラインの変更をブランチにプルしてマージする必要があります(メインラインはユーザーが生成したものを「クリーン」に残します)。いつものように、あなたのブランチに引っ張ってそこに修正することは、他の人にあなたの変更を引っ張ってからリモートで修正しようとするよりも友好的です。

この種のモデルを使用すると、マージの競合を回避するための通常のプロセスがすべて適用されます。より明白ないくつか:

  • 特定の作成者/ MOD /チームからのコンテンツをリングフェンスするために、名前空間の自由な使用を奨励します。
  • コンテンツが相互作用する必要がある場合、明確な呼び出し/使用規則、命名規則、および開発をガイドするその他の緩い「規則」を確立して、マージしやすくします。コンテンツ作成者がそれらのルールに従っているかどうかを知ることができるツールを提供し、理想的にはコンテンツ作成自体に統合します。
  • レポート/分析ツールを提供して、発生する可能性のあるマージ障害を発見します。マージ後の修正はおそらく非常に苦痛です。特定のコンテンツの一部をチェックして、マージ準備完了としてすべてをクリアできるようにして、マージが簡単になるようにします
  • マージ/統合を堅牢にします。簡単なロールバックを許可します。マージされたコンテンツの厳密なテストを行います。テストに失敗した場合は、マージしないでください!マージが正常に実行されるまで、コンテンツまたはユーザーのコンテンツを繰り返します。
  • あらゆるものに増分整数IDを使用することは避けてください(作成者にそれらを配布する信頼できる方法はありません)。DB自体はIDの正規のプロバイダーであるため、DBでのみ機能し、重複を取得することはありません。ただし、システムに単一障害点/負荷も発生します。
  • 代わりにGUIDを使用します。保存に費用がかかりますが、マシン固有であるため、衝突は発生しません。代わりに文字列識別子を使用すると、これはデバッグ/解決がはるかに簡単になりますが、保存と比較にはさらに費用がかかります。

悲しいことに、これのいくつかは私の問題に役立たない(例えば、プレイヤーが特定のルールに従うように、これはすべて自動的にサーバー側で行われなければならないので)そして、マージ管理とトランザクションセマンティクスに言及しますが、保証された一意のID(おそらくGUID)を割り当てる一般的なアプローチは、おそらく私が行くものに最も近いでしょう。
キロタン

ああ、分かった。構築ツールを管理しているので、少なくともこれらのマージフレンドリなアプローチ(名前空間など)を強制することは、プレイヤーが同意しなくてもできることです。
MrCranky

2人のプレーヤーが重複したコンテンツを作成した場合はどうしますか?または、ゲームワールドの個別のインスタンスは一意として扱われますか?その場合、おそらく、それらの変更をインスタンスにプッシュするときに発生する競合について、コア/メインラインブランチに対して、あなたが知っているすべての一意のインスタンスを自動的にチェックすることは有用なアプローチです。プレイヤーを制御できない場合は、少なくとも開発の初期段階で、彼らが行っている作業が世界のインスタンスXと競合することを社内チームに警告できます。
MrCranky

名前空間の概念はそれほど問題ではありません-すべての可能な名前空間の名前空間から適切な名前空間を選ぶのは問題です!:)そして、私にとって重複したコンテンツは問題ではありません-それは同等のもののちょうど2つのインスタンスです。重要なことは、有害なマージや上書きが発生しないことです。自動衝突チェックに関しては、それは書き込みで行われた損傷を止めますが、元の命名問題を解決しません。(衝突を避けるために名前を変更することは、相互参照のために簡単ではない場合があります。)
Kylotan

ああ、そうですね、名前の選択ほど名前空間そのものではありません。その場合、おそらくGUIDが再び答えになるでしょう-コンテンツをそれ自身の小さな領域に効果的に保持してください。装飾的な名前を付けることができますが、ゲームはGUIDを使用します。
MrCranky

1

すべてを属性(またはデコレータ)として保存します-マウントポイントを使用します。例としてプレイヤーが設計した家を見てみましょう。

o House: { Type = 105 } // Simple square cottage.
 o Mount point: South Wall:
  o Doodad: Chair { Displacement = 10cm }
   o Mount point: Seat:
    o Doodad: Pot Plant { Displacement = 0cm, Flower = Posies } // Work with me here :)
 o Mount point: North Wall:
  o Doodad: Table { Displacement = 1m }
    o Mount point: Left Edge:
     o Doodad: Food Bowl { Displacement = 20cm, Food = Meatballs}

したがって、各エンティティは1つ以上のマウントポイントを持つことができます。各マウントポイントは、0個以上の他のコンポーネントを受け入れることができます。このデータは、関連するプロパティ(この例ではDisplacementなど)とともに保存されたバージョンで保存されます-NoSQLはここで本当にうまく適合します(キー=エンティティID、値=シリアル化されたバイナリデータ)。

各コンポーネントは、以前のバージョンから古いデータを「アップグレード」する必要があります(シリアル化されたデータからフィールドを削除しないでください-単に「null」)-このアップグレードは、ロードされるとすぐに発生します(すぐに保存されます)利用可能な最新バージョン)。私たちの家の寸法が変更されたとしましょう。アップグレードコードは、北と南の壁の間の距離を相対的に計算し、それに含まれるすべてのエンティティの変位を比例的に変更します。別の例として、ミートボウルの「フード」フィールドを削除し、代わりに「バラエティ」(肉)と「レシピ」(ボール)を取得する場合があります。アップグレードスクリプトは、「ミートボール」を「肉」、「ボール」に変換します。各コンポーネントは、マウントポイントの変更に対処する方法も知っている必要があります。たとえば、

これにより、1つの問題が完全に解決されません。2つのオブジェクトが互いに衝突した場合(コンテナーではなく、マウントポイントが衝突するとどうなりますか)。アップグレード後、衝突をチェックし、それらを解決しようとする必要があります(SATのように、物をばらばらにすることにより)。衝突を解決する方法がわからない場合は、オブジェクトの1つを削除して隠し場所に置きます-削除されたアイテムを購入(無料)または販売(定価)できる場所 明らかに、アップグレードによってレイアウトの一部が破損したことをプレーヤーに通知します。問題を確認できるように、おそらく「ズームイン」機能を使用します。

最終的には、審美性を説明できるアルゴリズムはないため、プレーヤーの手に複雑な変更を残す必要があります(高速で失敗します)-単にアイテムがどこにあったのかをプレーヤーのコンテキストに与えることができるだけです(そうするだけでなく、隠し場所にあるこれらすべてのアイテムで着地し、それらがどこにあったのか分からない)。


これはオブジェクトの位置付けに少し狭すぎますが、これは私が解決しようとしている重要な問題ではありません。それは、同時データセットに一意の識別子を持ち、競合のリスクなしにそれらをマージできるようにする必要があるということです。先日、私の投稿に2つの例を追加して、もう少し説明しようとしました。
キロタン

1

私はこれを自分が理解しているものと関連付けようとしているので、今はMinecraftの観点から考えています。開発者が新しいコンテンツを修正/作成するテストサーバーで実行している間に、リアルタイムで変更を行うプレーヤーを含むライブサーバーを描いています。

あなたの質問は、2つのユニークな質問のように見えます。

  1. オブジェクトIDが一意であることを保証する方法
  2. スクリプト名前空間が衝突しないことを保証する方法

私は一時的な参照システムを通して#1を解こうとします。たとえば、誰かが新しいオブジェクトを作成すると、揮発性または一時としてマークされます。テストサーバーで作成されたすべての新しいコンテンツは、揮発性とマークされます(ただし、不揮発性コンテンツも参照する場合があります)。

ライブサーバーに新しいコンテンツを持ち込む準備ができたら、インポートプロセスで揮発性オブジェクトを見つけ、石に設定されたライブサーバーオブジェクトIDを割り当てます。これは、既存の不揮発性オブジェクトを修正または更新する必要がある場合に参照できるようにする必要があるため、直接インポート/マージとは異なります。

#2の場合、関数名を一意の名前空間にハッシュできる中間レベルの中間スクリプト変換が本当に必要なようです。すなわち

assignFrenchAccent

になる

_Z11assignFrenchAccent

0

データのファイルがバイナリではなくテキストであり、デザイナーとプレーヤーが異なる領域を変更している場合は、SVNマージを試すことができます。


0

「チェックアウト」手順で環境間で複製されたデータベース/ファイルシステムが最適だと思います。

そのため、デザイナーが世界に何らかの変更を加える場合は、データベースのすべてのコピー(開発および生産)で作成/変更するすべてのアセットをチェックアウト/ロックするため、他のプレーヤーやデザイナーは変更できません。 。その後、彼は新しい設計が完了するまで開発データベースで作業し、その時点で変更が本番データベースにマージされ、それらの資産はすべての環境でチェックイン/ロック解除されました。

プレイヤーの編集はほぼ同じように機能しますが、データベース/ファイルシステムの役割が逆になります-それらは本番データベースで機能し、すべての更新は終了時にdevにアップロードされます。

アセットのロックは、競合しないことを保証したいプロパティに制限できます。例1ではID 123456、プレーヤーが作成を開始するとすぐにロックされるため、開発者にはそのIDが割り当てられません。例2では、​​開発者はassignFrenchAccent開発中にスクリプト名をロックするため、プレイヤーは変更を開発するときに別の名前を選択する必要があります(名前空間によって小さな迷惑を減らすことができますが、ユーザー/開発者が特定の名前空間を使用すると、名前空間の管理に関して同じ問題が発生します)。これは、すべての開発が単一のオンラインデータベースから読み取る必要があることを意味しますが、これらの例でそのデータベースに必要なのはオブジェクト名のみであるため、パフォーマンスは問題になりません。

実装に関しては、すべてのキーとアセットの状態(使用可能、devからロック、prodからロック)が単一のテーブルにあり、環境間でリアルタイムで同期/アクセス可能であれば十分です。より複雑なソリューションでは、完全なバージョン管理システムを実装します。資産がすべてファイルシステムにある場合は、CVSやSVNなどの既存のシステムを使用できます。


通常、データをグローバルにロックすることは実用的ではありません。プレイヤーは通常のプレイで世界を編集している可能性があります。グローバルロックを許可する場合、マージ操作は基本的に上書き操作です。これは簡単ですが、グローバルロックがない場合はどうでしょうか。
キロタン

lathomas64が述べたように、答えはあなたが話しているデータの種類によって異なります。グローバルロックがなければ、競合を解決するためにバージョン管理システムと一連のルールが必要になると思います。これらのルールはデータとゲームプレイの要件に依存します。これらがあれば、すべてのマージが単純な上書き操作に還元されると思います。
SkimFlux

0

ここでのポイントは、あなたの責任を明確に受け入れることだと思います。1)サーバーは、現在受け入れ可能なものと、アクセスに使用するAPIを伝えます。特定の規則に従って、データベースが変更されています。2)作成者はコンテンツを作成できますが、更新後に再生可能でなければなりません。これは純粋にあなたの責任です:更新は古いデータ構造を解析できる必要があります。できればできるだけきれいで簡単にできます。

特にプレイヤーの「ホーム」構造全体が劇的に変化することを受け入れ、それを維持したい場合、マウントポイントのアイデアは、可鍛性の構造内で一意のアイテムと位置を追跡することに興味がある場合にメリットがありますそれぞれのロッカーにある小さな装飾品。

それは非常に複雑な問題であり、幸運です!おそらく、1つの答えは存在しません。


0

あなたがそれを作っているので、私はこれが大きな問題を抱えているとは思わない。

ユーザーが作成したmodを上書きし、「Mod Xはこのバージョンでは正しく動作しない可能性がある」という警告を表示し、modの作成者に任せて作業を変更します。これは、更新によって特定のMODが無効になる可能性があるという非現実的な期待ではないと思います。

ユーザーが作成したコンテンツについても同様で、バックアップを作成して上書きするだけです。

私はこれについて実際の経験はなく、ただ提案をしています。


それが純粋にユーザー提供のmodであったなら、あなたは正しいだろうと思います。しかし、一部のゲームはユーザーが作成したコンテンツを明示的に扱っているため、単に破壊することはできません。
キロタン

その後、後で追加する可能性のあるコンテンツのためにシステム内にスペースを残してください。ID番号を使用している場合、1-1000を予約します。または、ユーザーがアセットに名前を付けることができる場合、ユーザーが「FINAL-」などで名前を始めないようにします(自分のアセット用に予約してください)。EDIT:またはより良いまだ、範囲またはプレフィックスにユーザーコンテンツを強制的に、逆にそれを行う
ウッディZantzinger
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.