Skryf pasmaats vir Dota 2014

Hallo almal.

Hierdie lente het ek op 'n projek afgekom waarin die ouens geleer het hoe om die Dota 2-bedienerweergawe 2014 te laat loop en daarvolgens daarop te speel. Ek is 'n groot aanhanger van hierdie speletjie, en ek kon nie hierdie unieke geleentheid laat verbygaan om myself in my kinderjare te verdiep nie.

Ek het baie diep geduik, en dit het so gebeur dat ek 'n Discord-bot geskryf het wat verantwoordelik is vir byna al die funksionaliteit wat nie in die ou weergawe van die speletjie ondersteun word nie, naamlik matchmaking.
Voor al die innovasies met die bot, is die lobby met die hand geskep. Ons het 10 reaksies op 'n boodskap versamel en 'n bediener met die hand saamgestel, of 'n plaaslike voorportaal aangebied.

Skryf pasmaats vir Dota 2014

My aard as 'n programmeerder kon nie soveel handwerk weerstaan ​​nie, en oornag het ek die eenvoudigste weergawe van die bot geskets, wat die bediener outomaties verhoog het toe daar 10 mense was.

Ek het dadelik besluit om in nodejs te skryf, want ek hou nie regtig van Python nie, en ek voel meer gemaklik in hierdie omgewing.

Dit is my eerste ervaring om 'n bot vir Discord te skryf, maar dit blyk baie eenvoudig te wees. Die amptelike npm-module discord.js bied 'n gerieflike koppelvlak om met boodskappe te werk, reaksies te versamel, ens.

Vrywaring: Alle kodevoorbeelde is "aktueel", wat beteken dat hulle snags deur verskeie iterasies van herskryf gegaan het.

Die basis van pasmaats is 'n "tou" waarin spelers wat wil speel geplaas en verwyder word wanneer hulle nie wil nie of 'n speletjie vind.

Dit is hoe die wese van 'n "speler" lyk. Aanvanklik was dit net 'n gebruikers-ID in Discord, maar daar is planne om speletjies vanaf die webwerf te begin/soek, maar eerstens.

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

En hier is die tou-koppelvlak. Hier word, in plaas van "spelers", 'n abstraksie in die vorm van 'n "groep" gebruik. Vir 'n enkele speler bestaan ​​die groep onderskeidelik uit homself en vir spelers in 'n groep uit al die spelers in die groep.

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
}

Ek het besluit om gebeure te gebruik om konteks uit te ruil. Dit was geskik vir gevalle - met die geleentheid "'n speletjie vir 10 mense is gevind", kan u die nodige boodskap aan die spelers stuur in privaat boodskappe, en die basiese besigheidslogika uitvoer - 'n taak begin om gereedheid na te gaan, die voorportaal voor te berei vir bekendstelling, ensovoorts.

Vir IOC gebruik ek InversifyJS. Ek het 'n aangename ervaring om met hierdie biblioteek te werk. Vinnig en maklik!

Ons het verskeie toue op ons bediener - ons het 1x1, normaal/gegradeer, en 'n paar persoonlike modusse bygevoeg. Daarom is daar 'n singleton RoomService wat tussen die gebruiker en die speletjiesoektog lê.

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 noedels om 'n idee te gee van hoe die prosesse min of meer lyk)

Hier inisialiseer ek die tou vir elk van die geïmplementeerde spelmodusse, en luister ook vir veranderinge in "groepe" om die toue aan te pas en sommige konflikte te vermy.

So, welgedaan, ek het stukkies kode ingevoeg wat niks met die onderwerp te doen het nie, en kom ons gaan nou direk aan na pasmaats.

Kom ons kyk na die saak:

1) Die gebruiker wil speel.

2) Om die soektog te begin, gebruik hy Gateway=Discord, dit wil sê, plaas 'n reaksie op die boodskap:

Skryf pasmaats vir Dota 2014

3) Hierdie poort gaan na RoomService en sê "'n Gebruiker van discord wil die tou betree, modus: ongegradeerde speletjie."

4) RoomService aanvaar die poort se versoek en druk die gebruiker (meer presies, die gebruikersgroep) in die verlangde tou.

5) Die tou kontroleer elke keer as daar genoeg spelers is om te speel. Indien moontlik, stuur 'n gebeurtenis uit:

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

6) RoomService luister natuurlik gelukkig na elke tou in angstige afwagting van hierdie geleentheid. Ons ontvang 'n lys spelers as insette, vorm 'n virtuele "kamer" van hulle en reik natuurlik 'n geleentheid uit:

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) Ons het dus by die “hoogste” gesag uitgekom – die klas Bot. Oor die algemeen handel hy oor die verband tussen poorte (ek kan nie verstaan ​​hoe snaaks dit in Russies lyk nie) en die besigheidslogika van pasmaats. Die bot hoor die gebeurtenis en beveel DiscordGateway om 'n gereedheidskontrole aan alle gebruikers te stuur.

Skryf pasmaats vir Dota 2014

8) As iemand die wedstryd binne 3 minute verwerp of nie aanvaar nie, dan stuur ons hulle NIE terug na die tou nie. Ons bring almal terug na die tou en wag tot daar weer 10 mense is. As al die spelers die speletjie aanvaar het, begin die interessante deel.

Toegewyde bedienerkonfigurasie

Ons speletjies word op VDS met Windows-bediener 2012 aangebied. Hieruit kan ons verskeie gevolgtrekkings maak:

  1. Daar is geen dokker daarop nie, wat my in die hart getref het
  2. Ons spaar op huur

Die taak is om 'n proses op VDS vanaf 'n VPS op Linux uit te voer. Ek het 'n eenvoudige bediener in Flask geskryf. Ja, ek hou nie van Python nie, maar wat kan jy doen Dit is vinniger en makliker om hierdie bediener daarop te skryf.

Dit voer 3 funksies uit:

  1. Begin 'n bediener met 'n konfigurasie - kies 'n kaart, die aantal spelers om die speletjie te begin, en 'n stel inproppe. Ek sal nie nou oor plugins skryf nie - dis 'n ander storie met liters koffie in die nag gemeng met trane en geskeurde hare.
  2. Stop/herbegin die bediener in geval van onsuksesvolle verbindings, wat ons slegs met die hand kan hanteer.

Alles is eenvoudig hier, kodevoorbeelde is nie eers gepas nie. 100 reëls skrif

Dus, toe 10 mense bymekaargekom het en die speletjie aanvaar het, is die bediener geloods en almal was gretig om te speel, 'n skakel om aan die speletjie te koppel is in privaat boodskappe gestuur.

Skryf pasmaats vir Dota 2014

Deur op die skakel te klik, koppel die speler aan die speletjiebediener, en dan is dit dit. Na ~25 minute word die virtuele "kamer" met spelers skoongemaak.

Ek vra by voorbaat om verskoning vir die ongemaklikheid van die artikel, ek het lanklaas hier geskryf, en daar is te veel kode om belangrike afdelings uit te lig. Noedels, kortom.

As ek belangstelling in die onderwerp sien, sal daar 'n tweede deel wees - dit sal my kwelling bevat met plugins vir srcd's (Source dedicated server), en waarskynlik 'n graderingstelsel en mini-dotabuff, 'n webwerf met speletjiestatistieke.

Sommige skakels:

  1. Ons webwerf (statistieke, ranglys, klein bestemmingsbladsy en kliënt aflaai)
  2. Discord-bediener

Bron: will.com

Voeg 'n opmerking