Биз Dota 2014 үчүн дал келүүлөрдү жазып жатабыз

Баарына салам.

Ушул жазда мен бир долбоорго туш болдум, анда балдар Dota 2 серверинин 2014 версиясын кантип иштетүүнү жана ошого жараша аны ойноону үйрөнүштү. Мен бул оюндун чоң күйөрманымын жана мен өзүмдүн балалыгым менен сугаруу үчүн бул уникалдуу мүмкүнчүлүктү өткөрүп жибере алган жокмун.

Мен абдан терең көгүчкөндүм, ошондуктан мен Discord ботун жаздым, ал оюндун эски версиясында колдоого алынбаган дээрлик бардык функцияларга, тактап айтканда, дал келүүчүлүккө жооп берет.
Бот менен бардык инновациялардан мурун, лобби кол менен түзүлгөн. Биз билдирүүгө 10 реакцияны чогултуп, серверди кол менен чогулттук же жергиликтүү лобби уюштурдук.

Биз Dota 2014 үчүн дал келүүлөрдү жазып жатабыз

Менин программист катары табиятым мынчалык кол жумушуна туруштук бере алган жок, бир түндүн ичинде 10 адам болгондо серверди автоматтык түрдө көтөргөн боттун эң жөнөкөй версиясын чийдим.

Мен дароо nodejs жазууну чечтим, анткени мен чындап эле Pythonду жактырбайм жана бул чөйрөдө өзүмдү ыңгайлуу сезем.

Бул Discord үчүн бот жазуу менин биринчи тажрыйбам, бирок бул абдан жөнөкөй болуп чыкты. Расмий npm модулу discord.js билдирүүлөр менен иштөө, реакцияларды чогултуу ж.б. үчүн ыңгайлуу интерфейсти камсыз кылат.

Жоопкерчиликтен баш тартуу: Бардык код мисалдары "учурдагы", башкача айтканда, алар түн ичинде кайра жазуунун бир нече итерациясынан өткөн.

Дал келүүнүн негизи "кезекте" болуп саналат, анда ойногусу келген оюнчулар коюлуп, алар каалабаганда же оюнду таппай калганда алынып салынат.

“Оюнчунун” маңызы мына ушунда. Башында бул Discord'та жөн гана колдонуучунун идентификатору болчу, бирок сайттан оюндарды баштоо/издөө пландары бар, бирок биринчи кезекте.

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

Жана бул жерде кезек интерфейси. Бул жерде “оюнчулар” дегендин ордуна “топ” түрүндөгү абстракция колдонулат. Бир оюнчу үчүн топ өзүнөн, ал эми топтун оюнчулары үчүн, тиешелүүлүгүнө жараша, топтун бардык оюнчуларынан турат.

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
}

Мен контекстти алмашуу үчүн окуяларды колдонууну чечтим. Бул жагдайлар үчүн ылайыктуу болду - "10 кишилик оюн табылды" окуясында сиз жеке билдирүүлөр аркылуу оюнчуларга керектүү билдирүүнү жөнөтө аласыз жана негизги бизнес логикасын аткара аласыз - даярдыкты текшерүү, лобби даярдоо тапшырмасын ишке киргизиңиз. ишке киргизүү үчүн, жана башкалар.

IOC үчүн мен InversifyJS колдоном. Мен бул китепкана менен иштөөдө жагымдуу тажрыйбага ээ болдум. Тез жана оңой!

Биздин серверде бир нече кезек бар - биз 1x1, нормалдуу/бааланган жана бир нече ыңгайлаштырылган режимдерди коштук. Ошондуктан, колдонуучу менен оюн издөөнүн ортосунда жайгашкан синглтон RoomService бар.

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

(Процесстер болжол менен кандай экени жөнүндө түшүнүк берүү үчүн кесме коддору)

Бул жерде мен ар бир ишке ашырылган оюн режимдери үчүн кезекти инициализациялайм, ошондой эле кезектерди тууралоо жана кээ бир чыр-чатактарды болтурбоо үчүн "топтордогу" өзгөрүүлөрдү угам.

Ошентип, молодец, мен темага эч кандай тиешеси жок код бөлүктөрүн киргиздим, эми түз дал келүүгө өтөлү.

Келгиле, ишти карап көрөлү:

1) Колдонуучу ойногусу келет.

2) Издөөнү баштоо үчүн, ал Gateway=Discord колдонот, башкача айтканда, билдирүүгө реакция жасайт:

Биз Dota 2014 үчүн дал келүүлөрдү жазып жатабыз

3) Бул шлюз RoomService'ке барат жана "Талаш-тартыштан келген колдонуучу кезекке киргиси келет, режим: рейтинги жок оюн" дейт.

4) RoomService шлюздун өтүнүчүн кабыл алып, колдонуучуну (тагыраак айтканда, колдонуучу тобун) каалаган кезекке түртөт.

5) Кезекте ойноо үчүн жетиштүү оюнчулар болгон сайын текшерилет. Мүмкүн болсо, окуяны чыгарыңыз:

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

6) RoomService бул окуяны чыдамсыздык менен күтүү менен ар бир кезекти кубануу менен угат. Биз оюнчулардын тизмесин киргизүү катары алабыз, алардан виртуалдык "бөлмө" түзөбүз жана, албетте, окуяны чыгарабыз:

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) Ошентип, биз "эң жогорку" бийликке - класска жеттик Bot. Жалпысынан алганда, ал шлюздардын (орусча канчалык күлкүлүү экенин түшүнө албайм) жана матчтык бизнес логикасынын ортосундагы байланыш менен алектенет. Бот окуяны угуп, DiscordGatewayге бардык колдонуучуларга даярдыгын текшерүүсүн жөнөтүүнү буйруйт.

Биз Dota 2014 үчүн дал келүүлөрдү жазып жатабыз

8) Эгерде кимдир бирөө 3 мүнөттүн ичинде оюндан баш тартса же кабыл албаса, анда биз аларды кезекке КАЙТАРБАЙБЫЗ. Калгандардын баарын кезекке кайтарып, кайра 10 адам келгенче күтөбүз. Эгерде бардык оюнчулар оюнду кабыл алышкан болсо, анда кызыктуу бөлүк башталат.

Арналган сервер конфигурациясы

Биздин оюндар Windows Server 2012 менен VDS жайгаштырылат. Мындан биз бир нече жыйынтык чыгарсак болот:

  1. Жүрөгүмө тийген докер жок
  2. Биз ижара акысын үнөмдөйбүз

Милдет Linux'тагы VPSтен VDS'те процессти иштетүү. Мен Flaskта жөнөкөй сервер жаздым. Ооба, мага Python жакпайт, бирок сиз эмне кылсаңыз болот?Бул серверди ага жазуу тезирээк жана оңой.

Ал 3 функцияны аткарат:

  1. Конфигурация менен серверди баштоо - картаны, оюнду баштоо үчүн оюнчулардын санын жана плагиндердин топтомун тандоо. Мен азыр плагиндер жөнүндө жазбай эле коёюн - бул түнү көз жаш жана жыртылган чач аралаш литр кофе менен башка окуя.
  2. Ийгиликсиз туташуулар болгондо серверди токтотуу/кайра баштоо, биз аны кол менен гана чече алабыз.

Бул жерде баары жөнөкөй, код мисалдары да ылайыктуу эмес. 100 сап скрипт

Ошентип, 10 адам чогулуп, оюнду кабыл алганда, сервер ишке киргизилип, баары ойноого ынтызар болуп, жеке билдирүүлөргө оюнга кошулуу үчүн шилтеме жөнөтүлгөн.

Биз Dota 2014 үчүн дал келүүлөрдү жазып жатабыз

Шилтемени чыкылдатуу менен, оюнчу оюн серверине туташат, анан бүттү. ~25 мүнөттөн кийин, оюнчулар менен виртуалдык "бөлмө" тазаланат.

Макаланын ыңгайсыздыгы үчүн алдын ала кечирим сурайм, мен бул жерде көптөн бери жазган эмесмин жана маанилүү бөлүмдөрдү бөлүп көрсөтүү үчүн өтө көп код бар. Кыскасы кесме.

Эгер мен темага кызыгууну көрсөм, анда экинчи бөлүк болот - анда менин srcds үчүн плагиндер (Булак арналган сервер) жана, балким, рейтинг системасы жана мини-дотабуфф, оюн статистикасы бар сайт бар.

Кээ бир шилтемелер:

  1. Биздин веб-сайт (статистика, лидер тактасы, кичинекей десанттык бет жана кардар жүктөп алуу)
  2. Discord сервери

Source: www.habr.com

Комментарий кошуу