Mir schreiwen matchmaking fir Dota 2014

Salut alleguer.

Dëst Fréijoer sinn ech op e Projet begéint, an deem d'Jongen geléiert hunn wéi d'Dota 2 Server Versioun 2014 lafen an deementspriechend drop spillen. Ech sinn e grousse Fan vun dësem Spill, an ech konnt dës eemoleg Geleeënheet net verlassen fir mech a menger Kandheet z'ënnerdecken.

Ech daucht ganz déif, an et ass sou geschitt datt ech en Discord Bot geschriwwen hunn dee verantwortlech ass fir bal all Funktionalitéit déi net an der aler Versioun vum Spill ënnerstëtzt gëtt, nämlech matchmaking.
Virun all Innovatiounen mam Bot gouf de Lobby manuell erstallt. Mir hunn 10 Reaktiounen op e Message gesammelt an e Server manuell zesummegesat, oder eng lokal Lobby gehost.

Mir schreiwen matchmaking fir Dota 2014

Meng Natur als Programméierer konnt net sou vill manuell Aarbecht ausstoen, an iwwer Nuecht hunn ech déi einfachst Versioun vum Bot skizzéiert, deen automatesch de Server erhéicht huet wann et 10 Leit waren.

Ech hunn direkt decidéiert an nodejs ze schreiwen, well ech Python net wierklech gär hunn, an ech fille mech méi bequem an dësem Ëmfeld.

Dëst ass meng éischt Erfahrung fir e Bot fir Discord ze schreiwen, awer et huet sech ganz einfach erausgestallt. Den offiziellen npm Modul discord.js bitt e prakteschen Interface fir mat Messagen ze schaffen, Reaktiounen ze sammelen, asw.

Verzichterklärung: All Code Beispiller sinn "aktuell", dat heescht datt se an der Nuecht e puer Iteratiounen vun der Iwwerschreiwe gemaach hunn.

D'Basis vum matchmaking ass eng "Schlaang" an där Spiller, déi spille wëllen, plazéiert a geläscht ginn wann se net wëllen oder e Spill fannen.

Dëst ass wéi d'Essenz vun engem "Spiller" ausgesäit. Am Ufank war et just e Benotzer-ID am Discord, awer et gi Pläng fir Spiller vum Site ze starten / ze sichen, awer éischt Saache fir d'éischt.

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

An hei ass d'Schlaang Interface. Hei gëtt amplaz "Spiller" eng Abstraktioun a Form vun enger "Grupp" benotzt. Fir een eenzege Spiller besteet de Grupp aus sech selwer, a fir Spiller an engem Grupp, respektiv aus all de Spiller am Grupp.

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
}

Ech hu beschloss Eventer ze benotzen fir Kontext auszetauschen. Et war gëeegent fir Fäll - op der Manifestatioun "e Spill fir 10 Leit gouf fonnt", kënnt Dir déi néideg Noriicht un d'Spiller a private Messagen schécken, an d'Basis Geschäftslogik ausféieren - eng Aufgab starten fir d'Bereetschaft ze kontrolléieren, d'Lobby virbereeden fir starten, a sou weider.

Fir IOC benotzen ech InversifyJS. Ech hunn eng agreabel Erfahrung mat dëser Bibliothéik ze schaffen. Schnell an einfach!

Mir hunn e puer Schlaangen op eisem Server - mir hunn 1x1 bäigefüügt, normal / bewäert, an e puer personaliséiert Modi. Dofir gëtt et e Singleton RoomService deen tëscht dem Benotzer an der Spillsich läit.

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

(Code Nuddelen fir eng Iddi ze ginn wéi d'Prozesser ongeféier ausgesinn)

Hei initialiséieren ech d'Schlaang fir jiddereng vun den ëmgesate Spillmodi, an lauschteren och no Ännerungen an "Gruppen" fir d'Schlaangen unzepassen an e puer Konflikter ze vermeiden.

Also, gutt geschafft, Ech hunn Stécker Code agebaut déi näischt mam Thema ze dinn hunn, a loosst eis direkt op matchmaking weidergoen.

Loosst eis de Fall betruechten:

1) De Benotzer wëll spillen.

2) Fir d'Sich unzefänken, benotzt hien Gateway=Discord, dat heescht eng Reaktioun op de Message:

Mir schreiwen matchmaking fir Dota 2014

3) Dëse Paart geet op RoomService a seet "E Benotzer aus der Discord wëll an d'Schlaang kommen, Modus: net bewäert Spill."

4) RoomService akzeptéiert d'Ufro vum Paart an dréckt de Benotzer (méi präzis, d'Benotzergrupp) an déi gewënscht Schlaang.

5) D'Schlaang kontrolléiert all Kéier wann et genuch Spiller sinn ze spillen. Wa méiglech, emittéiert en Event:

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

6) RoomService lauschtert selbstverständlech frou all Schlaang an ängschtlech Erwaardung vun dësem Event. Mir kréien eng Lëscht vu Spiller als Input, bilden e virtuelle "Raum" vun hinnen, an natierlech en Event eraus:

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) Also si mir op déi "héchst" Autoritéit komm - d'Klass Bot. Am Allgemengen beschäftegt hien sech mat der Verbindung tëscht Paarte (Ech kann net verstoen wéi witzeg et op Russesch ausgesäit) an der Geschäftslogik vum Matchmaking. De Bot iwwerhéiert d'Evenement an bestellt DiscordGateway fir e Bereetschaftscheck un all Benotzer ze schécken.

Mir schreiwen matchmaking fir Dota 2014

8) Wann iergendeen d'Spill innerhalb vun 3 Minutten refuséiert oder net akzeptéiert, da kréie mir se NET zréck an d'Schlaang. Mir ginn all déi aner zréck an d'Schlaang a waarden bis et erëm 10 Leit sinn. Wann all Spiller d'Spill akzeptéiert hunn, fänkt den interessanten Deel un.

Engagéiert Server Konfiguratioun

Eis Spiller ginn op VDS mat Windows Server 2012 gehost. Doraus kënne mir verschidde Conclusiounen zéien:

  1. Et gëtt keen Docker drop, deen mech an d'Häerz geschloen huet
  2. Mir spueren op Loyer

D'Aufgab ass e Prozess op VDS vun engem VPS op Linux auszeféieren. Ech hunn en einfachen Server a Flask geschriwwen. Jo, ech hunn Python net gär, awer wat kënnt Dir maachen? Et ass méi séier a méi einfach dëse Server drop ze schreiwen.

Et mécht 3 Funktiounen:

  1. E Server mat enger Konfiguratioun starten - eng Kaart auswielen, d'Zuel vun de Spiller fir d'Spill ze starten an eng Rei vu Plugins. Ech wäert elo net iwwer Plugins schreiwen - dat ass eng aner Geschicht mat Liter Kaffi an der Nuecht gemëscht mat Tréinen an zerräissen Hoer.
  2. Stoppen / Neistarten vum Server am Fall vun net erfollegräiche Verbindungen, déi mir nëmmen manuell handhaben.

Alles ass einfach hei, Code Beispiller sinn net emol passend. 100 Linn Schrëft

Also, wéi 10 Leit sech zesummegedoen an d'Spill akzeptéiert hunn, gouf de Server lancéiert a jidderee war gär ze spillen, e Link fir mat dem Spill ze verbannen gouf a Privatmessage geschéckt.

Mir schreiwen matchmaking fir Dota 2014

Andeems Dir op de Link klickt, verbënnt de Spiller mat dem Spillserver, an dann ass et. No ~25 Minutten ass de virtuelle "Raum" mat Spiller geläscht.

Ech entschëllege mech am Viraus fir d'Schwieregkeet vum Artikel, ech hunn hei net laang geschriwwen, an et gëtt ze vill Code fir wichteg Sektiounen ze markéieren. Nuddelen, kuerz.

Wann ech Interessi am Thema gesinn, gëtt et en zweeten Deel - et wäert meng Péng mat Plugins fir srcds enthalen (Quell dedizéierten Server), an, wahrscheinlech, e Bewäertungssystem a Mini-Dotabuff, e Site mat Spillstatistiken.

E puer Linken:

  1. Eis Websäit (Statistiken, Leaderboard, kleng Landung Säit a Client Download)
  2. Discord Server

Source: will.com

Setzt e Commentaire