Dota 2014rako matchmaking idazten ari gara

Kaixo guztioi

Udaberri honetan, mutilek Dota 2 zerbitzariaren 2014 bertsioa exekutatu eta, horren arabera, jolasten ikasi zuten proiektu batekin topo egin nuen. Joko hau oso zalea naiz, eta ezin nuen galdu nire haurtzaroan murgiltzeko aukera paregabe hau.

Oso sakon murgildu nintzen, eta gertatu zen Discord bot bat idatzi nuela, jokoaren bertsio zaharrean onartzen ez diren funtzionaltasun ia guztien arduraduna dena, hots, matchmaking-a.
Botarekin egindako berrikuntza guztien aurretik, lobby-a eskuz sortu zen. Mezu baten 10 erreakzio bildu genituen eta eskuz zerbitzari bat muntatu genuen edo tokiko lobby bat antolatu genuen.

Dota 2014rako matchmaking idazten ari gara

Programatzaile gisa nire izaerak ezin zuen hainbeste eskuzko lan jasan, eta egun batetik bestera bot-aren bertsiorik errazena zirriborratu nuen, 10 pertsona zeudenean zerbitzaria automatikoki igotzen zuena.

Berehala erabaki nuen nodejs-en idaztea, ez dudalako oso gustuko Python, eta erosoago sentitzen naiz ingurune honetan.

Discord-erako bot bat idazten dudan lehenengo esperientzia da, baina oso erraza izan da. Discord.js npm modulu ofizialak interfaze erosoa eskaintzen du mezuekin lan egiteko, erreakzioak biltzeko, etab.

Lege-oharra: kode-adibide guztiak "egungoak" dira, hau da, gauez hainbat berridazketa errepikatu dituzte.

Matchmaking-aren oinarria "ilara" bat da, eta bertan jolastu nahi duten jokalariak sartu eta kentzen dira joko bat nahi ez dutenean edo aurkitzen ez dutenean.

Horrelakoa da β€œjokalari” baten esentzia. Hasieran, Discord-en erabiltzailearen ID bat besterik ez zen, baina gunetik jokoak abiarazteko/bilatzeko asmoa dago, baina lehenik eta behin.

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

Eta hona hemen ilararen interfazea. Hemen, "jokalariak" ordez, "talde" formako abstrakzioa erabiltzen da. Jokalari bakarrean, taldea berak osatzen dute, eta talde bateko jokalariek, hurrenez hurren, taldeko jokalari guztiek.

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
}

Gertaerak testuingurua trukatzeko erabiltzea erabaki nuen. Kasuetarako egokia zen - "10 pertsonentzako joko bat aurkitu zen" gertaeran, jokalariei mezu pribatuetan beharrezko mezua bidal diezaiekezu eta oinarrizko negozio-logika gauzatu - prest egotea egiaztatzeko zeregin bat abiarazi, lobby-a prestatzeko. abian jartzeko, eta abar.

IOC-rako InversifyJS erabiltzen dut. Esperientzia atsegina dut liburutegi honekin lanean. Azkarra eta erraza!

Gure zerbitzarian hainbat ilara ditugu: 1x1, normala/baloratua eta modu pertsonalizatu pare bat gehitu ditugu. Hori dela eta, erabiltzailearen eta jokoaren bilaketaren artean dagoen Singleton RoomService bat dago.

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

(Kodetu fideoak prozesuak gutxi gorabehera nolakoak diren jakiteko)

Hemen inplementatutako joko-modu bakoitzaren ilara hasieratzen dut, eta "taldeetan" aldaketak ere entzuten ditut ilarak doitzeko eta gatazka batzuk saihesteko.

Beraz, ondo egin, gaiarekin zerikusirik ez duten kode zatiak txertatu ditut, eta orain zuzenean pasa gaitezen matchmakingera.

Demagun kasua:

1) Erabiltzaileak jolastu nahi du.

2) Bilaketa hasteko, Gateway=Discord erabiltzen du, hau da, erreakzio bat jartzen dio mezuari:

Dota 2014rako matchmaking idazten ari gara

3) Atebide hau RoomService-ra doa eta "Discord-eko erabiltzaile batek ilaran sartu nahi du, modua: baloratu gabeko jokoa".

4) RoomService-k atebidearen eskaera onartzen du eta erabiltzailea (zehazkiago, erabiltzaile taldea) nahi den ilarara bultzatzen du.

5) Ilarak egiaztatzen du jolasteko nahikoa jokalari dauden bakoitzean. Ahal izanez gero, igorri gertaera bat:

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

6) RoomService, jakina, pozik entzuten ari da ilara guztiak gertaera honen zain egonez. Jokalarien zerrenda jasotzen dugu sarrera gisa, haiengandik "gela" birtual bat osatzen dugu eta, noski, ekitaldi bat igortzen dugu:

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) Beraz, agintari "gorenera" iritsi ginen - klasera Bot. Oro har, atebideen arteko lotura jorratzen du (errusieraz ezin dut ulertu zein dibertigarria den) eta matchmaking-aren negozio-logika. Botak gertaera entzuten du eta DiscordGateway-i erabiltzaile guztiei prest dagoen egiaztapena bidaltzeko agindu dio.

Dota 2014rako matchmaking idazten ari gara

8) Norbaitek 3 minuturen buruan jokoa baztertzen badu edo ez badu onartzen, EZ dugu ilarara itzuliko. Beste guztiak ilarara bueltatzen ditugu eta berriro 10 pertsona egon arte itxarongo dugu. Jokalari guztiek jokoa onartu badute, orduan hasten da zati interesgarria.

Zerbitzari dedikatuaren konfigurazioa

Gure jokoak VDS-n daude ostatatuta Windows Server 2012. Hortik hainbat ondorio atera ditzakegu:

  1. Ez dago dockerrik, eta horrek bihotzean jo nau
  2. Errentan aurrezten dugu

Zeregin da VDS-n prozesu bat exekutatzen Linux-eko VPS batetik. Zerbitzari sinple bat idatzi nuen Flask-en. Bai, ez zait gustatzen Python, baina zer egin dezakezu?Azkarrago eta errazagoa da zerbitzari hau bertan idaztea.

3 funtzio betetzen ditu:

  1. Zerbitzari bat konfigurazio batekin abiaraztea: mapa bat, jokoa hasteko jokalari kopurua eta plugin multzo bat hautatzea. Orain ez dut pluginei buruz idatziko; hori beste istorio bat da gauez kafe litroekin malkoekin eta ile urratuta nahastuta.
  2. Zerbitzaria gelditu/berrabiaraztea arrakastarik gabeko konexioen kasuan, eskuz bakarrik kudeatu ditzakegunak.

Hemen dena erraza da, kode adibideak ere ez dira egokiak. 100 lerroko gidoia

Beraz, 10 lagun elkartu eta jokoa onartu zutenean, zerbitzaria martxan jarri zen eta denak jolasteko gogoz zeuden, jokora konektatzeko esteka bidali zen mezu pribatuetan.

Dota 2014rako matchmaking idazten ari gara

Estekan klik eginez, jokalaria joko zerbitzarira konektatzen da, eta kito. ~25 minutu igaro ondoren, jokalariekin dagoen "gela" birtuala garbitzen da.

Aldez aurretik barkamena eskatzen dut artikuluaren traketsagatik, aspaldi ez dut hemen idatzi, eta kode gehiegi dago atal garrantzitsuak nabarmentzeko. Fideoak, laburbilduz.

Gaiari interesa ikusten badut, bigarren zati bat egongo da: nire oinazea edukiko du srcds-erako pluginekin (Iturburuko zerbitzari dedikatua), eta, ziurrenik, balorazio sistema eta mini-dotabuff, jokoen estatistikak dituen gune bat.

Esteka batzuk:

  1. Gure webgunea (estatistikak, sailkapena, lurreratze orri txikia eta bezeroen deskarga)
  2. Discord zerbitzaria

Iturria: www.habr.com

Gehitu iruzkin berria