この春、私は、2014バージョンのDota 2サーバーを実行する方法を学び、それに応じてプレイするプロジェクトに出くわしました。私はこのゲームの大ファンであり、子供時代に突入するユニークな機会を逃すことができませんでした。
私は非常に深く突入しましたが、たまたま、古いバージョンのゲームでサポートされていないほとんどすべての機能、つまりマッチメイキングを担当するDiscordボットを作成しました。
ボットによるすべての革新の前に、ロビーは手動で作成されました。メッセージに対する10の応答を収集し、サーバーを手動で組み立てるか、ローカルロビーをホストしました。
プログラマーとしての私の性格はそれほど手作業に耐えることができず、一晩で最も単純なバージョンのボットをスケッチしました。これは、10人が採用されると自動的にサーバーを起動します。
私はpythonがあまり好きではなく、この環境でより快適に感じるので、すぐにnodejsで書くことにしました。
Discord用のボットを作成したのはこれが初めてですが、非常に簡単であることがわかりました。公式のnpmモジュールdiscord.jsは、メッセージの操作、反応の収集などに便利なインターフェイスを提供します。
免責事項:すべてのコード例は「最新」です。つまり、一晩で何度か書き直しを繰り返しました。
マッチメイキングの中核は、プレイしたいプレイヤーがゲームを望まない、または見つけないときに配置および削除される「キュー」です。
これが「プレイヤー」の本質です。当初、それはDiscordの単なるユーザーIDでしたが、計画にはランチャー/サイトからのゲームの検索が含まれていますが、まず最初に行います。
export enum Realm {
DISCORD,
EXTERNAL,
}
export default class QueuePlayer {
constructor(public readonly realm: Realm, public readonly id: string) {}
public is(qp: QueuePlayer): boolean {
return this.realm === qp.realm && this.id === qp.id;
}
static Discord(id: string) {
return new QueuePlayer(Realm.DISCORD, id);
}
static External(id: string) {
return new QueuePlayer(Realm.EXTERNAL, id);
}
}
そして、これがキューインターフェイスです。ここでは、「プレーヤー」の代わりに、「グループ」の形式の抽象化が使用されます。単一のプレーヤーの場合、グループは自分自身で構成され、グループ内のプレーヤーの場合は、それぞれグループ内のすべてのプレーヤーで構成されます。
export default interface IQueue extends EventEmitter {
inQueue: QueuePlayer[]
put(uid: Party): boolean;
remove(uid: Party): boolean;
removeAll(ids: Party[]): void;
mode: MatchmakingMode
roomSize: number;
clear(): void
}
イベントを使用してコンテキストを交換することを決定しました。「10人用のゲームを見つけた」というイベントの場合、プライベートメッセージでプレーヤーに目的のメッセージを送信し、メインのビジネスロジックを実行できます。タスクを起動して準備状況を確認し、ロビーを起動する準備をします。
IOCには、InversifyJSを使用しています。私はこの図書館で楽しい経験をしています。速くて簡単!
サーバー上にいくつかのキューがあります-1x1モード、通常/評価、およびいくつかのカスタムモードを追加しました。したがって、ユーザーとゲーム検索の間にあるシングルトンのRoomServiceがあります。
constructor(
@inject(GameServers) private gameServers: GameServers,
@inject(MatchStatsService) private stats: MatchStatsService,
@inject(PartyService) private partyService: PartyService
) {
super();
this.initQueue(MatchmakingMode.RANKED);
this.initQueue(MatchmakingMode.UNRANKED);
this.initQueue(MatchmakingMode.SOLOMID);
this.initQueue(MatchmakingMode.DIRETIDE);
this.initQueue(MatchmakingMode.GREEVILING);
this.partyService.addListener(
"party-update",
(event: PartyUpdatedEvent) => {
this.queues.forEach((q) => {
if (has(q.queue, (t) => t.is(event.party))) {
// if queue has this party, we re-add party
this.leaveQueue(event.qp, q.mode)
this.enterQueue(event.qp, q.mode)
}
});
}
);
this.partyService.addListener(
"party-removed",
(event: PartyUpdatedEvent) => {
this.queues.forEach((q) => {
if (has(q.queue, (t) => t.is(event.party))) {
// if queue has this party, we re-add party
q.remove(event.party)
}
});
}
);
}
(プロセスがどのように見えるかを表すコードヌードル)
ここでは、実装されたゲームモードごとにキューを初期化し、キューを修正して競合を回避するために「グループ」の変更をリッスンします。
それで、私は素晴らしいです、私はトピックとは関係のないコードの断片を挿入しました、そして今、マストメイキングに直接移りましょう。
ケースを考えてみましょう:
1)ユーザーがプレイしたい。
2)検索を開始するために、彼はGateway = Discordを使用します。つまり、メッセージに反応します
。3)このゲートウェイはRoomServiceに移動し、「不和のユーザーがキューに入れたい、モード:未評価のゲーム」と言います。
4)RoomServiceはゲートウェイの要求を受け入れ、それを目的のユーザーキュー(より正確にはユーザーグループ)に押し込みます。
5)キューは、各変更でプレイするのに十分なプレーヤーがいるかどうかをチェックします。可能であれば、イベントを発行します。
private onRoomFound(players: Party[]) {
this.emit("room-found", {
players,
});
}
6)RoomServiceは、このイベントを見越して各キューを聞いて喜んでいることは明らかです。入り口では、プレーヤーのリストを受け取り、そこから仮想の「部屋」を形成し、もちろん、イベントを発行します。
queue.addListener("room-found", (event: RoomFoundEvent) => {
console.log(
`Room found mode: [${mode}]. Time to get free room for these guys`
);
const room = this.getFreeRoom(mode);
room.fill(event.players);
this.onRoomFormed(room);
});
7)それで、「最高の」インスタンスであるBotクラスに到達しました。一般的に、彼はゲートウェイ(ロシア語でどれほどばかげているように見えるか、私にはできません)とマッチメイキングのビジネスロジックの間の接続を扱います。ボットはイベントを盗聴し、DiscordGatewayにすべてのユーザーに準備チェックを送信するように命令します。
8)誰かが3分以内にゲームを拒否または受け入れなかった場合、キューに戻さない。他の全員をキューに戻し、10人が再び採用されるのを待ちます。すべてのプレイヤーがゲームを受け入れた場合、楽しい部分が始まります。
専用サーバー構成
私たちのゲームは、Windowsサーバー2012を備えたVDSでホストされています。これから、いくつかの結論を導き出すことができます。
- 私の心を打つドッカーはありません
- 家賃を節約
タスクは、Linux上のVPSを使用してVDSでプロセスを開始することです。Flaskでシンプルなサーバーを作成しました。はい、私はpythonが好きではありませんが、何ができますか?このサーバーをその上に作成する方が速くて簡単です。
3つの機能があります。
- 構成を使用したサーバーの起動-マップの選択、ゲームを開始するプレーヤーの数、およびプラグインのセット。プラグインについては今は書きません。これは、夜に何リットルものコーヒーに涙と破れた髪が混ざった別の話です。
- 接続に失敗した場合のサーバーの停止/再起動。これは手動でしか処理できません。
ここではすべてが単純で、コード例も不適切です。100行のスクリプトしたがって
、10人が集まってゲームを受け入れると、サーバーが実行され、誰もがプレイしたいと思っているので、ゲームに接続するためのリンクがプライベートメッセージで表示されます。
リンクをクリックすると、プレーヤーはゲームサーバーに接続し、それだけです。約25分後、プレーヤーのいる仮想の「部屋」がクリアされます。
記事がぎこちなくて、ここに長い間書いていません。重要なセクションを強調するにはコードが多すぎます。要するに、麺。
このトピックに興味がある場合は、2番目の部分があります。これには、srcds(ソース専用サーバー)のプラグインによる苦痛と、おそらく、評価システムとゲーム統計のあるサイトであるmini-dotabuffが含まれます。
いくつかのリンク: