Párkeresést írunk a Dota 2014-hez

Üdvözlet mindenkinek.

Idén tavasszal találkoztam egy projekttel, amelyben a srácok megtanulták, hogyan kell futtatni a Dota 2 szerver 2014-es verzióját, és ennek megfelelően játszani is rajta. Nagy rajongója vagyok ennek a játéknak, és nem hagyhattam ki ezt az egyedülálló lehetőséget, hogy elmerüljek a gyerekkoromban.

Nagyon mélyen belemerültem, és úgy esett, hogy írtam egy Discord botot, amely szinte minden olyan funkcióért felelős, amelyet a játék régi verziója nem támogat, nevezetesen a párkeresésért.
A bottal kapcsolatos újítások előtt az előcsarnokot manuálisan hozták létre. Összegyűjtöttünk 10 reakciót egy üzenetre, és manuálisan összeállítottunk egy szervert, vagy helyi lobbit hoztunk létre.

Párkeresést írunk a Dota 2014-hez

Programozói természetem nem bírt ki ennyi kézi munkát, és egyik napról a másikra felvázoltam a bot legegyszerűbb változatát, ami 10 fő esetén automatikusan megemelte a szervert.

Azonnal úgy döntöttem, hogy nodejs-ben írok, mert nem igazán szeretem a Python-t, és jobban érzem magam ebben a környezetben.

Ez az első tapasztalatom, hogy botot írok a Discordhoz, de nagyon egyszerűnek bizonyult. A hivatalos discord.js npm modul kényelmes felületet biztosít az üzenetekkel való munkavégzéshez, a reakciók összegyűjtéséhez stb.

Felelősség kizárása: Minden kódpélda „aktuális”, ami azt jelenti, hogy több iteráción estek át éjszakai újraíráson.

A matchmaking alapja egy „sor”, amelybe a játszani akaró játékosokat behelyezik és eltávolítják, amikor nem akarnak vagy nem találnak játékot.

Így néz ki a „játékos” lényege. Kezdetben ez csak egy felhasználói azonosító volt a Discordban, de tervben van játékok elindítása/keresése az oldalról, de először is.

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

És itt van a sor felület. Itt a „játékosok” helyett egy „csoport” formájú absztrakciót használnak. Egyetlen játékos esetén a csoport saját magából, a csoport játékosainál pedig a csoport összes játékosából áll.

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
}

Úgy döntöttem, hogy az eseményeket felhasználom a kontextus cseréjére. Alkalmas volt az esetekre - a "talált egy 10 fős játékot" eseményen privát üzenetben elküldheti a játékosoknak a szükséges üzenetet, és végrehajthatja az alapvető üzleti logikát - készenléti feladatot indíthat, előkészítheti a lobbyt. indításhoz és így tovább.

IOC-hoz InversifyJS-t használok. Kellemes tapasztalataim vannak ezzel a könyvtárral. Gyorsan és egyszerűen!

Szerverünkön több sor is található – hozzáadtunk 1x1, normál/besorolt ​​módot és néhány egyéni módot. Ezért van egy egyetlen RoomService, amely a felhasználó és a játékkereső között helyezkedik el.

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

(Kódolja a tésztát, hogy képet adjon arról, hogy nagyjából hogyan is néznek ki a folyamatok)

Itt inicializálom a sort az egyes megvalósított játékmódokhoz, és figyelem a „csoportok” változásait is, hogy módosítsam a sorokat és elkerülhessem az ütközéseket.

Szóval, jól sikerült, beszúrtam olyan kódrészleteket, amelyeknek semmi közük a témához, és most térjünk át közvetlenül a párkeresésre.

Nézzük az esetet:

1) A felhasználó játszani akar.

2) A keresés elindításához a Gateway=Discord parancsot használja, azaz reagál az üzenetre:

Párkeresést írunk a Dota 2014-hez

3) Ez az átjáró a RoomService-hez megy, és azt mondja: „A discordból származó felhasználó be akar lépni a sorba, mód: besorolatlan játék.”

4) A RoomService elfogadja az átjáró kérését, és a felhasználót (pontosabban a felhasználói csoportot) a kívánt sorba tolja.

5) A sor minden alkalommal ellenőrzi, hogy van elég játékos. Ha lehetséges, küldjön eseményt:

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

6) A RoomService nyilvánvalóan boldogan hallgat minden sorban állást, izgatottan várja ezt az eseményt. Bemenetként megkapjuk a játékosok listáját, belőlük egy virtuális „szobát” alakítunk ki, és természetesen eseményt adunk ki:

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) Így eljutottunk a „legmagasabb” tekintélyhez - az osztályhoz Bot. Általában az átjárók (nem értem, milyen viccesen néz ki oroszul) és a párkeresés üzleti logikája közötti kapcsolattal foglalkozik. A bot kihallgatja az eseményt, és megparancsolja a DiscordGateway-nek, hogy küldjön készenléti ellenőrzést minden felhasználónak.

Párkeresést írunk a Dota 2014-hez

8) Ha valaki 3 percen belül elutasítja vagy nem fogadja el a játékot, akkor NEM tesszük vissza a sorba. A többieket visszaállítjuk a sorba, és megvárjuk, amíg ismét 10 ember lesz. Ha minden játékos elfogadta a játékot, akkor kezdődik az érdekes rész.

Dedikált szerver konfiguráció

Játékaink Windows Server 2012 rendszerű VDS-en vannak tárolva. Ebből több következtetést is levonhatunk:

  1. Nincs rajta dokkoló, ami szíven ütött
  2. A bérleti díjon spórolunk

A feladat egy folyamat futtatása VDS-en egy VPS-ről Linuxon. Flaskban írtam egy egyszerű szervert. Igen, nem szeretem a Pythont, de mit tehetsz? Gyorsabb és egyszerűbb ráírni ezt a szervert.

3 funkciót lát el:

  1. Szerver indítása konfigurációval – térkép kiválasztása, a játék indításához szükséges játékosok száma és a beépülő modulok készlete. A bővítményekről most nem írok – az egy másik történet, amikor az éjszakai kávék literei könnyekkel és tépett hajjal keverednek.
  2. A szerver leállítása/újraindítása sikertelen csatlakozások esetén, amit csak manuálisan tudunk kezelni.

Itt minden egyszerű, a kódpéldák nem is megfelelőek. 100 soros szkript

Így amikor 10 ember összegyűlt és elfogadta a játékot, elindult a szerver és mindenki szívesen játszott, privát üzenetben elküldték a linket a játékhoz való csatlakozáshoz.

Párkeresést írunk a Dota 2014-hez

A linkre kattintva a játékos csatlakozik a játékszerverhez, és ennyi. ~25 perc elteltével a virtuális „terem” a játékosokkal kiürül.

Előre is elnézést kérek a cikk kínos voltáért, régóta nem írtam ide, és túl sok a kód a fontos részek kiemeléséhez. Tészta, röviden.

Ha látok érdeklődést a téma iránt, lesz egy második rész is – benne lesz az srcds-hez (Forrás dedikált szerver) való pluginokkal való gyötrelem, és valószínűleg egy minősítő rendszer és egy mini-dotabuff, egy játékstatisztikájú oldal.

Néhány link:

  1. Weboldalunk (statisztika, ranglista, kis nyitóoldal és kliens letöltés)
  2. Discord szerver

Forrás: will.com

Hozzászólás