Kami sedang menulis pencarian jodoh untuk Dota 2014

Helo semua.

Musim bunga ini saya menemui projek di mana mereka belajar cara menjalankan pelayan Dota 2 versi 2014 dan, dengan itu, bermain di atasnya. Saya peminat tegar permainan ini, dan saya tidak boleh melepaskan peluang unik ini untuk menyelami zaman kanak-kanak saya.

Saya terjun dengan sangat mendalam, dan kebetulan saya menulis bot Discord yang bertanggungjawab untuk hampir semua fungsi yang tidak disokong dalam versi lama permainan, iaitu mencari jodoh.
Sebelum semua inovasi dengan bot, lobi dibuat secara manual. Kami mengumpulkan 10 reaksi terhadap mesej dan memasang pelayan secara manual, atau menganjurkan lobi tempatan.

Kami sedang menulis pencarian jodoh untuk Dota 2014

Sifat saya sebagai pengaturcara tidak dapat menahan begitu banyak kerja manual, dan semalaman saya melakar versi paling mudah bot, yang secara automatik menaikkan pelayan apabila terdapat 10 orang.

Saya segera memutuskan untuk menulis dalam nodejs, kerana saya tidak begitu menyukai Python, dan saya berasa lebih selesa dalam persekitaran ini.

Ini adalah pengalaman pertama saya menulis bot untuk Discord, tetapi ia ternyata sangat mudah. Modul npm rasmi discord.js menyediakan antara muka yang mudah untuk bekerja dengan mesej, mengumpul reaksi, dsb.

Penafian: Semua contoh kod adalah "semasa", bermakna mereka telah melalui beberapa lelaran penulisan semula pada waktu malam.

Asas mencari jodoh ialah "baris gilir" di mana pemain yang ingin bermain diletakkan dan dikeluarkan apabila mereka tidak mahu atau mencari permainan.

Beginilah rupa intipati seorang "pemain". Pada mulanya ia hanya id pengguna dalam Discord, tetapi terdapat rancangan untuk melancarkan/mencari permainan dari tapak, tetapi perkara pertama dahulu.

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);
  }
}

Dan inilah antara muka baris gilir. Di sini, bukannya "pemain", abstraksi dalam bentuk "kumpulan" digunakan. Untuk pemain tunggal, kumpulan itu terdiri daripada dirinya sendiri, dan untuk pemain dalam kumpulan, masing-masing, semua pemain dalam kumpulan.

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
}

Saya memutuskan untuk menggunakan acara untuk bertukar konteks. Ia sesuai untuk kes - apabila acara "permainan untuk 10 orang ditemui", anda boleh menghantar mesej yang diperlukan kepada pemain dalam mesej peribadi, dan menjalankan logik perniagaan asas - melancarkan tugas untuk memeriksa kesediaan, menyediakan lobi untuk pelancaran, dan sebagainya.

Untuk IOC saya menggunakan InversifyJS. Saya mempunyai pengalaman yang menyenangkan bekerja dengan perpustakaan ini. Cepat dan mudah!

Kami mempunyai beberapa baris gilir pada pelayan kami - kami telah menambah 1x1, normal/dinilai dan beberapa mod tersuai. Oleh itu, terdapat Singleton RoomService yang terletak di antara pengguna dan carian permainan.

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)
          }
        });
      }
    );
  }

(Kod mi untuk memberi gambaran tentang rupa proses secara kasarnya)

Di sini saya memulakan baris gilir untuk setiap mod permainan yang dilaksanakan, dan juga mendengar perubahan dalam "kumpulan" untuk melaraskan baris gilir dan mengelakkan beberapa konflik.

Jadi, syabas, saya memasukkan cebisan kod yang tiada kaitan dengan topik itu, dan sekarang mari kita teruskan ke pencarian jodoh.

Mari kita pertimbangkan kes itu:

1) Pengguna ingin bermain.

2) Untuk memulakan carian, dia menggunakan Gateway=Discord, iaitu, memberikan reaksi kepada mesej:

Kami sedang menulis pencarian jodoh untuk Dota 2014

3) Gerbang ini pergi ke RoomService dan berkata "Pengguna dari perselisihan mahu memasuki baris gilir, mod: permainan tidak dinilai."

4) RoomService menerima permintaan get laluan dan menolak pengguna (lebih tepat lagi, kumpulan pengguna) ke dalam baris gilir yang dikehendaki.

5) Barisan memeriksa setiap kali terdapat cukup pemain untuk bermain. Jika boleh, pancarkan peristiwa:

private onRoomFound(players: Party[]) {
    this.emit("room-found", {
      players,
    });
  }

6) RoomService jelas gembira mendengar setiap barisan dalam jangkaan cemas acara ini. Kami menerima senarai pemain sebagai input, membentuk "bilik" maya daripada mereka, dan, sudah tentu, mengeluarkan acara:

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) Jadi kami sampai ke pihak berkuasa "tertinggi" - kelas bot. Secara umum, dia berurusan dengan hubungan antara pintu masuk (saya tidak dapat memahami betapa lucunya ia kelihatan dalam bahasa Rusia) dan logik perniagaan mencari jodoh. Bot terdengar acara itu dan memerintahkan DiscordGateway untuk menghantar semakan kesediaan kepada semua pengguna.

Kami sedang menulis pencarian jodoh untuk Dota 2014

8) Jika seseorang menolak atau tidak menerima permainan dalam masa 3 minit, maka kami TIDAK mengembalikannya ke barisan. Kami kembalikan orang lain ke barisan dan tunggu sehingga ada 10 orang lagi. Jika semua pemain telah menerima permainan, maka bahagian yang menarik bermula.

Konfigurasi pelayan khusus

Permainan kami dihoskan pada VDS dengan pelayan Windows 2012. Daripada ini kami boleh membuat beberapa kesimpulan:

  1. Tidak ada docker di atasnya, yang memukul saya di dalam hati
  2. Kami menjimatkan sewa

Tugasnya adalah untuk menjalankan proses pada VDS daripada VPS di Linux. Saya menulis pelayan mudah dalam Flask. Ya, saya tidak suka Python, tetapi apa yang boleh anda lakukan? Lebih cepat dan lebih mudah untuk menulis pelayan ini padanya.

Ia menjalankan 3 fungsi:

  1. Memulakan pelayan dengan konfigurasi - memilih peta, bilangan pemain untuk memulakan permainan dan satu set pemalam. Saya tidak akan menulis tentang pemalam sekarang - itu cerita berbeza dengan liter kopi pada waktu malam bercampur dengan air mata dan rambut yang koyak.
  2. Menghentikan/memulakan semula pelayan sekiranya sambungan tidak berjaya, yang kami hanya boleh kendalikan secara manual.

Semuanya mudah di sini, contoh kod tidak sesuai. skrip 100 baris

Jadi, apabila 10 orang berkumpul dan menerima permainan itu, pelayan telah dilancarkan dan semua orang tidak sabar-sabar untuk bermain, pautan untuk menyambung kepada permainan telah dihantar dalam mesej peribadi.

Kami sedang menulis pencarian jodoh untuk Dota 2014

Dengan mengklik pada pautan, pemain menyambung ke pelayan permainan, dan kemudian itu sahaja. Selepas ~25 minit, "bilik" maya dengan pemain dibersihkan.

Saya memohon maaf terlebih dahulu atas kejanggalan artikel itu, saya sudah lama tidak menulis di sini, dan terdapat terlalu banyak kod untuk menyerlahkan bahagian penting. Mi, ringkasnya.

Jika saya melihat minat dalam topik itu, akan ada bahagian kedua - ia akan mengandungi siksaan saya dengan pemalam untuk srcds (Pelayan khusus sumber), dan, mungkin, sistem penarafan dan mini-dotabuff, tapak dengan statistik permainan.

Beberapa pautan:

  1. Tapak web kami (statistik, papan pendahulu, halaman pendaratan kecil dan muat turun pelanggan)
  2. Pelayan Discord

Sumber: www.habr.com

Tambah komen