Ne po shkruajmë mblesëri për Dota 2014

Pershendetje te gjitheve

Këtë pranverë hasa në një projekt në të cilin djemtë mësuan se si të ekzekutonin versionin e serverit Dota 2 2014 dhe, në përputhje me rrethanat, të luanin në të. Unë jam një fans i madh i kësaj loje dhe nuk mund ta humbisja këtë mundësi unike për t'u zhytur në fëmijërinë time.

U zhyta shumë thellë dhe ndodhi që shkrova një bot Discord që është përgjegjës për pothuajse të gjithë funksionalitetin që nuk mbështetet në versionin e vjetër të lojës, përkatësisht mblesëri.
Para të gjitha inovacioneve me bot, lobi u krijua me dorë. Ne mblodhëm 10 reagime ndaj një mesazhi dhe mblodhëm manualisht një server, ose organizuam një lobi lokal.

Ne po shkruajmë mblesëri për Dota 2014

Natyra ime si programues nuk mund të përballonte kaq shumë punë manuale dhe brenda natës skicova versionin më të thjeshtë të botit, i cili ngriti automatikisht serverin kur kishte 10 persona.

Menjëherë vendosa të shkruaj në nodejs, sepse Python nuk më pëlqen shumë dhe ndihem më rehat në këtë mjedis.

Kjo është përvoja ime e parë duke shkruar një bot për Discord, por doli të ishte shumë e thjeshtë. Moduli zyrtar npm discord.js ofron një ndërfaqe të përshtatshme për të punuar me mesazhe, mbledhjen e reagimeve, etj.

Mohim përgjegjësie: Të gjithë shembujt e kodit janë "aktual", që do të thotë se ata kanë kaluar nëpër disa përsëritje të rishkrimit gjatë natës.

Baza e bërjes së ndeshjeve është një "radhë" në të cilën lojtarët që duan të luajnë vendosen dhe hiqen kur nuk duan ose nuk gjejnë një lojë.

Kështu duket thelbi i një "lojtari". Fillimisht ishte vetëm një id përdoruesi në Discord, por ka plane për të nisur/kërkuar lojëra nga faqja, por gjërat e para së pari.

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

Dhe këtu është ndërfaqja e radhës. Këtu, në vend të "lojtarëve", përdoret një abstraksion në formën e një "grupi". Për një lojtar të vetëm, grupi përbëhet nga ai vetë, dhe për lojtarët në një grup, përkatësisht, nga të gjithë lojtarët në 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
}

Vendosa të përdor ngjarjet për të shkëmbyer kontekstin. Ishte i përshtatshëm për raste - me ngjarjen "u gjet një lojë për 10 persona", mund t'u dërgoni lojtarëve mesazhin e nevojshëm në mesazhe private dhe të kryeni logjikën bazë të biznesit - filloni një detyrë për të kontrolluar gatishmërinë, përgatitni hollin për nisje, e kështu me radhë.

Për IOC unë përdor InversifyJS. Kam një përvojë të këndshme duke punuar me këtë bibliotekë. Shpejt dhe lehtë!

Ne kemi disa radhë në serverin tonë - kemi shtuar 1x1, normal/vlerësuar dhe disa mënyra të personalizuara. Prandaj, ekziston një RoomService i vetëm që shtrihet midis përdoruesit dhe kërkimit të lojës.

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

(Kodoni petë për të dhënë një ide se si duken përafërsisht proceset)

Këtu unë inicializoj radhën për secilën nga mënyrat e implementuara të lojës, dhe gjithashtu dëgjoj ndryshimet në "grupe" në mënyrë që të rregulloj radhët dhe të shmang disa konflikte.

Pra, bravo, kam futur copa kodi që nuk kanë të bëjnë me temën, dhe tani le të kalojmë drejtpërdrejt në mblesëri.

Le të shqyrtojmë rastin:

1) Përdoruesi dëshiron të luajë.

2) Për të filluar kërkimin, ai përdor Gateway=Discord, domethënë vendos një reagim ndaj mesazhit:

Ne po shkruajmë mblesëri për Dota 2014

3) Kjo portë shkon te RoomService dhe thotë "Një përdorues nga mosmarrëveshja dëshiron të hyjë në radhë, modaliteti: lojë e pavlerësuar".

4) RoomService pranon kërkesën e portës dhe e shtyn përdoruesin (më saktë, grupin e përdoruesve) në radhën e dëshiruar.

5) Radha kontrollon sa herë që ka mjaft lojtarë për të luajtur. Nëse është e mundur, lëshoni një ngjarje:

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

6) RoomService padyshim po dëgjon me kënaqësi çdo radhë në pritje të ankthit të kësaj ngjarje. Ne marrim një listë lojtarësh si hyrje, formojmë një "dhomë" virtuale prej tyre dhe, natyrisht, nxjerrim një ngjarje:

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) Kështu arritëm te autoriteti "më i lartë" - klasa bot. Në përgjithësi, ai merret me lidhjen midis portave (nuk mund ta kuptoj sa qesharake duket në rusisht) dhe logjikën e biznesit të bërjes së mblesërive. Bot dëgjon ngjarjen dhe urdhëron DiscordGateway të dërgojë një kontroll gatishmërie për të gjithë përdoruesit.

Ne po shkruajmë mblesëri për Dota 2014

8) Nëse dikush refuzon ose nuk e pranon lojën brenda 3 minutave, atëherë ne NUK e kthejmë atë në radhë. Ne i kthejmë të gjithë të tjerët në radhë dhe presim derisa të jenë përsëri 10 persona. Nëse të gjithë lojtarët e kanë pranuar lojën, atëherë fillon pjesa interesante.

Konfigurimi i serverit të dedikuar

Lojërat tona janë të pritura në VDS me Windows server 2012. Nga kjo mund të nxjerrim disa përfundime:

  1. Nuk ka doker në të, që më goditi në zemër
  2. Ne kursejmë në qira

Detyra është të ekzekutoni një proces në VDS nga një VPS në Linux. Kam shkruar një server të thjeshtë në Flask. Po, nuk më pëlqen Python, por çfarë mund të bësh? Është më e shpejtë dhe më e lehtë të shkruash këtë server në të.

Kryen 3 funksione:

  1. Nisja e një serveri me një konfigurim - zgjedhja e një harte, numri i lojtarëve për të filluar lojën dhe një grup shtojcash. Nuk do të shkruaj për shtojcat tani - kjo është një histori tjetër me litra kafe gjatë natës të përzier me lot dhe flokë të grisura.
  2. Ndalimi/rifillimi i serverit në rast të lidhjeve të pasuksesshme, të cilat ne mund t'i trajtojmë vetëm manualisht.

Gjithçka është e thjeshtë këtu, shembujt e kodit nuk janë as të përshtatshëm. Skenari me 100 rreshta

Kështu, kur 10 persona u mblodhën dhe pranuan lojën, serveri u hap dhe të gjithë ishin të etur për të luajtur, një lidhje për t'u lidhur me lojën u dërgua në mesazhe private.

Ne po shkruajmë mblesëri për Dota 2014

Duke klikuar në lidhjen, lojtari lidhet me serverin e lojës, dhe pastaj kjo është ajo. Pas ~25 minutash, "dhoma" virtuale me lojtarë pastrohet.

Kërkoj falje paraprakisht për ngathtësinë e artikullit, nuk kam shkruar këtu për një kohë të gjatë dhe ka shumë kod për të theksuar seksione të rëndësishme. Petë, me pak fjalë.

Nëse shoh interes për temën, do të ketë një pjesë të dytë - do të përmbajë mundimin tim me shtojcat për srcds (server i dedikuar burimi), dhe, me siguri, një sistem vlerësimi dhe mini-dotabuff, një faqe me statistika lojërash.

Disa lidhje:

  1. Faqja jonë e internetit (statistikat, tabela e drejtuesve, faqja e vogël e uljes dhe shkarkimi i klientit)
  2. Serveri i mosmarrëveshjes

Burimi: www.habr.com

Shto një koment