ہم ڈوٹا 2014 کے لیے میچ میکنگ لکھ رہے ہیں۔

سب کو سلام۔

اس موسم بہار میں میں نے ایک پروجیکٹ دیکھا جس میں لڑکوں نے سیکھا کہ ڈوٹا 2 سرور ورژن 2014 کو کیسے چلانا ہے اور اس کے مطابق اس پر کھیلنا ہے۔ میں اس کھیل کا بہت بڑا پرستار ہوں، اور میں اپنے بچپن میں اپنے آپ کو غرق کرنے کا یہ منفرد موقع ہاتھ سے نہیں چھوڑ سکتا۔

میں نے بہت گہرائی سے کبوتر کیا، اور ایسا ہوا کہ میں نے ایک Discord بوٹ لکھا جو تقریباً تمام فنکشنلٹی کے لیے ذمہ دار ہے جو گیم کے پرانے ورژن میں تعاون یافتہ نہیں ہے، یعنی میچ میکنگ۔
بوٹ کے ساتھ تمام اختراعات سے پہلے، لابی دستی طور پر بنائی گئی تھی۔ ہم نے ایک پیغام پر 10 ردعمل جمع کیے اور دستی طور پر ایک سرور کو جمع کیا، یا مقامی لابی کی میزبانی کی۔

ہم ڈوٹا 2014 کے لیے میچ میکنگ لکھ رہے ہیں۔

ایک پروگرامر کے طور پر میری فطرت اتنے دستی کام کو برداشت نہیں کر سکتی تھی، اور راتوں رات میں نے بوٹ کا سب سے آسان ورژن تیار کیا، جس نے سرور کو خود بخود بڑھا دیا جب 10 افراد تھے۔

میں نے فوری طور پر نوڈجز میں لکھنے کا فیصلہ کیا، کیونکہ میں واقعی میں ازگر کو پسند نہیں کرتا، اور میں اس ماحول میں زیادہ آرام دہ محسوس کرتا ہوں۔

ڈسکارڈ کے لیے بوٹ لکھنے کا یہ میرا پہلا تجربہ ہے، لیکن یہ بہت آسان نکلا۔ آفیشل 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، نارمل/ریٹیڈ، اور کچھ حسب ضرورت موڈز شامل کیے ہیں۔ لہذا، ایک سنگلٹن روم سروس ہے جو صارف اور گیم سرچ کے درمیان ہے۔

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 استعمال کرتا ہے، یعنی پیغام پر ردعمل ظاہر کرتا ہے:

ہم ڈوٹا 2014 کے لیے میچ میکنگ لکھ رہے ہیں۔

3) یہ گیٹ وے RoomService پر جاتا ہے اور کہتا ہے کہ "Discord سے ایک صارف قطار میں داخل ہونا چاہتا ہے، موڈ: غیر ریٹیڈ گیم۔"

4) روم سروس گیٹ وے کی درخواست کو قبول کرتی ہے اور صارف (زیادہ واضح طور پر، صارف گروپ) کو مطلوبہ قطار میں دھکیل دیتی ہے۔

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) تو ہم "اعلیٰ ترین" اتھارٹی - کلاس تک پہنچ گئے۔ بوٹ. عام طور پر، وہ گیٹ ویز (میں سمجھ نہیں سکتا کہ یہ روسی زبان میں کتنا مضحکہ خیز لگتا ہے) اور میچ میکنگ کی کاروباری منطق کے درمیان تعلق کا معاملہ کرتا ہے۔ بوٹ ایونٹ کو سنتا ہے اور DiscordGateway کو حکم دیتا ہے کہ وہ تمام صارفین کو تیاری کا چیک بھیجے۔

ہم ڈوٹا 2014 کے لیے میچ میکنگ لکھ رہے ہیں۔

8) اگر کوئی 3 منٹ کے اندر کھیل کو مسترد کرتا ہے یا قبول نہیں کرتا ہے، تو ہم انہیں قطار میں واپس نہیں کرتے ہیں۔ ہم باقی سب کو قطار میں واپس کرتے ہیں اور 10 افراد کے دوبارہ ہونے تک انتظار کرتے ہیں۔ اگر تمام کھلاڑیوں نے کھیل کو قبول کر لیا ہے، تو دلچسپ حصہ شروع ہوتا ہے۔

سرشار سرور کی ترتیب

ہمارے گیمز وی ڈی ایس پر ونڈوز سرور 2012 کے ساتھ ہوسٹ کیے گئے ہیں۔ اس سے ہم کئی نتائج اخذ کر سکتے ہیں:

  1. اس پر کوئی ڈوکر نہیں، جو میرے دل میں مارے
  2. ہم کرایہ پر بچت کرتے ہیں۔

کام لینکس پر VPS سے VDS پر عمل چلانا ہے۔ میں نے فلاسک میں ایک سادہ سرور لکھا۔ ہاں، مجھے Python پسند نہیں ہے، لیکن آپ کیا کر سکتے ہیں؟ اس سرور کو اس پر لکھنا تیز اور آسان ہے۔

یہ 3 افعال انجام دیتا ہے:

  1. کنفیگریشن کے ساتھ سرور شروع کرنا - ایک نقشہ منتخب کرنا، گیم شروع کرنے والے کھلاڑیوں کی تعداد، اور پلگ انز کا ایک سیٹ۔ میں ابھی پلگ انز کے بارے میں نہیں لکھوں گا - یہ ایک مختلف کہانی ہے جس میں رات کو کافی کے لیٹر آنسو اور پھٹے بالوں کے ساتھ ملا ہوا ہے۔
  2. ناکام کنکشن کی صورت میں سرور کو روکنا/دوبارہ شروع کرنا، جسے ہم صرف دستی طور پر ہینڈل کر سکتے ہیں۔

یہاں سب کچھ آسان ہے، کوڈ کی مثالیں بھی مناسب نہیں ہیں۔ 100 لائن اسکرپٹ

چنانچہ، جب 10 لوگوں نے اکٹھے ہو کر گیم کو قبول کیا، سرور لانچ ہوا اور ہر کوئی کھیلنے کے لیے بے تاب تھا، پرائیویٹ میسجز میں گیم سے منسلک ہونے کا لنک بھیجا گیا۔

ہم ڈوٹا 2014 کے لیے میچ میکنگ لکھ رہے ہیں۔

لنک پر کلک کرنے سے، کھلاڑی گیم سرور سے جڑ جاتا ہے، اور پھر بس۔ ~25 منٹ کے بعد، کھلاڑیوں کے ساتھ ورچوئل "کمرہ" صاف ہو جاتا ہے۔

میں مضمون کی ناگواری کے لیے پیشگی معذرت خواہ ہوں، میں نے یہاں کافی عرصے سے نہیں لکھا، اور اہم حصوں کو نمایاں کرنے کے لیے بہت زیادہ کوڈ موجود ہے۔ نوڈلس، مختصر میں.

اگر میں موضوع میں دلچسپی دیکھتا ہوں، تو ایک دوسرا حصہ ہوگا - اس میں میرا عذاب srcds کے لیے پلگ انز کے ساتھ ہوگا (ماخذ سرشار سرور)، اور، شاید، ایک ریٹنگ سسٹم اور منی ڈاٹابف، گیم کے اعدادوشمار والی سائٹ۔

کچھ لنکس:

  1. ہماری ویب سائٹ (اعداد و شمار، لیڈر بورڈ، چھوٹا لینڈنگ پیج اور کلائنٹ ڈاؤن لوڈ)
  2. ڈسکارڈ سرور

ماخذ: www.habr.com

نیا تبصرہ شامل کریں