Kami sedang menulis perjodohan untuk Dota 2014

Halo.

Musim semi ini saya menemukan sebuah proyek di mana orang-orang belajar cara menjalankan server Dota 2 versi 2014 dan, karenanya, memainkannya. Saya penggemar berat game ini, dan saya tidak bisa melewatkan kesempatan unik ini untuk membenamkan diri dalam masa kecil saya.

Saya terjun sangat dalam, dan kebetulan saya menulis bot Discord yang bertanggung jawab atas hampir semua fungsi yang tidak didukung di game versi lama, yaitu matchmaking.
Sebelum semua inovasi dengan bot, lobi dibuat secara manual. Kami mengumpulkan 10 reaksi terhadap sebuah pesan dan secara manual merakit server, atau menghosting lobi lokal.

Kami sedang menulis perjodohan untuk Dota 2014

Sifat saya sebagai seorang programmer tidak dapat menahan begitu banyak pekerjaan manual, dan dalam semalam saya membuat sketsa versi bot yang paling sederhana, yang secara otomatis memunculkan server ketika ada 10 orang.

Saya langsung memutuskan untuk menulis di nodejs, karena saya tidak terlalu suka Python, dan saya merasa lebih nyaman dengan lingkungan ini.

Ini adalah pengalaman pertama saya menulis bot untuk Discord, tetapi ternyata sangat sederhana. Modul npm resmi discord.js menyediakan antarmuka yang nyaman untuk bekerja dengan pesan, mengumpulkan reaksi, dll.

Penafian: Semua contoh kode adalah “terkini”, artinya telah melalui beberapa iterasi penulisan ulang pada malam hari.

Dasar dari matchmaking adalah sebuah “antrian” dimana pemain yang ingin bermain ditempatkan dan dikeluarkan ketika mereka tidak ingin atau tidak menemukan permainan.

Seperti inilah esensi dari “pemain”. Awalnya hanya user id di Discord, tapi ada rencana untuk meluncurkan/mencari game dari situs tersebut, tapi yang pertama adalah yang utama.

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 antarmuka antrian. Di sini, alih-alih “pemain”, abstraksi dalam bentuk “grup” digunakan. Untuk pemain tunggal, grupnya terdiri dari dirinya sendiri, dan untuk pemain dalam grup, masing-masing terdiri dari semua pemain dalam grup.

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 peristiwa untuk bertukar konteks. Ini cocok untuk kasus - setelah acara "permainan untuk 10 orang ditemukan", Anda dapat mengirim pesan yang diperlukan kepada para pemain dalam pesan pribadi, dan menjalankan logika bisnis dasar - meluncurkan tugas untuk memeriksa kesiapan, menyiapkan lobi untuk peluncuran, dan sebagainya.

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

Kami memiliki beberapa antrian di server kami - kami telah menambahkan 1x1, normal/rating, dan beberapa mode khusus. Oleh karena itu, ada RoomService tunggal yang terletak di antara pengguna dan pencarian game.

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

(Kode mie untuk memberikan gambaran kira-kira seperti apa prosesnya)

Di sini saya menginisialisasi antrian untuk setiap mode permainan yang diterapkan, dan juga mendengarkan perubahan dalam “grup” untuk menyesuaikan antrian dan menghindari beberapa konflik.

Jadi, bagus sekali, saya menyisipkan potongan kode yang tidak ada hubungannya dengan topik, dan sekarang mari kita langsung ke perjodohan.

Mari kita pertimbangkan kasusnya:

1) Pengguna ingin bermain.

2) Untuk memulai pencarian, dia menggunakan Gateway=Discord, yaitu memberikan reaksi terhadap pesan:

Kami sedang menulis perjodohan untuk Dota 2014

3) Gerbang ini menuju ke RoomService dan mengatakan “Pengguna dari perselisihan ingin masuk ke antrean, mode: permainan tanpa peringkat.”

4) RoomService menerima permintaan gateway dan memasukkan pengguna (lebih tepatnya, grup pengguna) ke antrean yang diinginkan.

5) Pengecekan antrian setiap kali ada cukup pemain untuk bermain. Jika memungkinkan, pancarkan suatu peristiwa:

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

6) RoomService jelas dengan senang hati mendengarkan setiap antrian dengan cemas menantikan acara ini. Kami menerima daftar pemain sebagai masukan, membentuk “ruangan” virtual dari mereka, dan, tentu saja, mengeluarkan sebuah 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 kita sampai pada otoritas "tertinggi" - kelas Bot. Secara umum, ini berkaitan dengan hubungan antara gateway (saya tidak mengerti betapa lucunya tampilannya dalam bahasa Rusia) dan logika bisnis perjodohan. Bot mendengar acara tersebut dan memerintahkan DiscordGateway untuk mengirimkan pemeriksaan kesiapan ke semua pengguna.

Kami sedang menulis perjodohan untuk Dota 2014

8) Jika seseorang menolak atau tidak menerima permainan dalam waktu 3 menit, maka kami TIDAK mengembalikannya ke antrian. Kami mengembalikan semua orang ke antrian dan menunggu sampai ada 10 orang lagi. Jika semua pemain sudah menerima permainan, maka bagian menarik pun dimulai.

Konfigurasi server khusus

Game kami dihosting di VDS dengan server Windows 2012. Dari sini kami dapat menarik beberapa kesimpulan:

  1. Tidak ada buruh pelabuhan di dalamnya, yang membuat saya terpukul
  2. Kami menghemat uang sewa

Tugasnya adalah menjalankan proses di VDS dari VPS di Linux. Saya menulis server sederhana di Flask. Ya, saya tidak suka Python, tapi apa yang bisa Anda lakukan? Lebih cepat dan mudah untuk menulis server ini di dalamnya.

Ia melakukan 3 fungsi:

  1. Memulai server dengan konfigurasi - memilih peta, jumlah pemain untuk memulai permainan, dan satu set plugin. Saya tidak akan menulis tentang plugin sekarang - lain ceritanya jika berliter-liter kopi di malam hari bercampur dengan air mata dan rambut robek.
  2. Menghentikan/me-restart server jika koneksi gagal, yang hanya dapat kami tangani secara manual.

Semuanya sederhana di sini, contoh kode bahkan tidak sesuai. skrip 100 baris

Jadi, ketika 10 orang berkumpul dan menerima game tersebut, server diluncurkan dan semua orang bersemangat untuk bermain, tautan untuk terhubung ke game tersebut dikirim melalui pesan pribadi.

Kami sedang menulis perjodohan untuk Dota 2014

Dengan mengklik link tersebut, pemain terhubung ke server game, dan selesai. Setelah ~25 menit, “ruangan” virtual dengan para pemain dibersihkan.

Saya mohon maaf sebelumnya atas kecanggungan artikel ini, sudah lama saya tidak menulis di sini, dan terlalu banyak kode untuk menyorot bagian-bagian penting. Singkatnya, mie.

Jika saya melihat minat pada topik ini, akan ada bagian kedua - itu akan berisi siksaan saya dengan plugin untuk srcds (Server khusus sumber), dan, mungkin, sistem peringkat dan mini-dotabuff, situs dengan statistik permainan.

Beberapa tautan:

  1. Situs web kami (statistik, papan peringkat, halaman arahan kecil, dan unduhan klien)
  2. Server perselisihan

Sumber: www.habr.com

Tambah komentar