บัญชีผู้เล่น

มอบบัญชีให้ผู้เล่นเกมของคุณที่ใช้ได้ในทุกเกมของ Aukimi พร้อมเซฟที่ตามผู้เล่นไปได้ทุกเครื่อง ไม่ว่าจะบนบริการของ Aukimi หรือเซิร์ฟเวอร์ของคุณเอง

สรุปในประโยคเดียว#

ผู้เล่นเข้าสู่ระบบครั้งเดียวที่ play.aukimi.com แล้วพบบัญชีนั้นในทุกเกมที่สร้างด้วย Aukimi รวมถึงเซฟด้วย เกมของคุณขอใช้บัญชีเท่านั้น มันไม่เคยจับต้องรหัสผ่านเลย

ทำไมเกมของคุณไม่มีวันเห็นรหัสผ่าน#

ใครก็ตามสามารถเผยแพร่เกมได้ เกมที่ขอรหัสผ่านของ Aukimi จะเป็นหน้าฟิชชิ่งที่ น่าเชื่อถือมาก และไม่ว่าคุณจะมีเจตนาดีแค่ไหน สิ่งนั้นก็ไม่เปลี่ยนสิ่งที่นักพัฒนา คนอื่น สามารถส่งออกไปได้

ดังนั้นรหัสผ่านจะถูกพิมพ์บน play.aukimi.com เท่านั้น ไม่มีที่อื่นอีก เกมของคุณเรียก PlayerLoginAsync() หน้าต่างเบราว์เซอร์จะเปิดขึ้นด้วยสีสันของ Aukimi เอง ผู้เล่นกด ยืนยัน และหน้าต่างนั้นจะส่งโทเคนกลับมาให้เกมของคุณ

โทเคนนั้นออกให้สำหรับ เกมของคุณเท่านั้น โทเคนของเกม A ที่นำไปใช้กับเกม B จะถูก ปฏิเสธ ไม่ใช่แค่เพิกเฉย แต่ปฏิเสธ นั่นคือประเด็นสำคัญ: บัญชี ถูกแชร์ระหว่างเกม แต่ สิทธิ์เข้าถึง ไม่ได้ถูกแชร์ หากไม่มีสิ่งนี้ เกมประสงค์ร้ายเกมเดียวจะอ่านเซฟของ ผู้เล่นในเกมอื่นทั้งหมดได้

สิ่งที่คุณได้รับเกี่ยวกับผู้เล่น#

สองอย่าง ไม่มากไปกว่านั้น:

คุณได้รับคุณไม่มีวันได้รับ
ชื่อที่แสดง (PlayerName())ที่อยู่อีเมล
id ที่ไม่มีความหมาย ต่างกันในทุกเกม (PlayerID())สิ่งใดก็ตามที่ระบุตัวตนพวกเขาในที่อื่น

id เปลี่ยนไปในแต่ละเกมโดยตั้งใจ นักพัฒนาสองคนที่เทียบรายชื่อผู้เล่นของตนไม่สามารถ บอกได้ว่ากำลังดูคนเดียวกันอยู่ มันยังทำให้คุณเป็นเพียงผู้ประมวลผล ไม่ใช่ผู้ควบคุมข้อมูล นั้น ซึ่งเป็นข้อแตกต่างทางกฎหมาย ไม่ใช่แค่เรื่องตกแต่ง

ไม่มีอะไรบล็อกลูปของเกม#

ทุกคำสั่งที่คุยกับเครือข่ายจะคืนค่าเป็น หมายเลขงาน (job number) ไม่ใช่ผลลัพธ์ ลูปของคุณยังคงทำงานต่อที่หกสิบเฟรมต่อวินาทีในขณะที่คำขอกำลังเดินทาง ซึ่งเป็นเหตุผล ทั้งหมดที่เกมไม่สามารถแค่ "รอเซิร์ฟเวอร์" ได้

job = PlayerLoginAsync()

จากนั้นทุกเฟรม:

etat$ = PlatformJobState(job)
if etat$ = "done"
    resultat$ = PlatformJobResult(job)
    PlatformJobRelease(job)
endif
if etat$ = "error"
    Print(PlatformJobError(job))
    PlatformJobRelease(job)
endif

ปล่อยงาน (release) ทันทีที่คุณอ่านมันแล้ว งานที่ไม่เคยถูกปล่อยจะเก็บผลลัพธ์ของ มันไว้ในหน่วยความจำตลอดที่เหลือของเซสชัน ไม่มีอะไรพัง ไม่มีอะไรเตือนคุณ และการรั่วไหล นี้จะปรากฏให้เห็นก็ต่อเมื่อเล่นเซสชันยาว ๆ เท่านั้น

เล่นโดยไม่มีบัญชี#

ไม่ใช่ทุกคนที่อยากสมัครสมาชิกก่อนลองเล่นเกม PlayerGuestAsync(name$) สร้างบัญชี ที่ไม่มีอีเมล เก็บไว้ในเบราว์เซอร์นี้

มันเป็นบัญชีจริง: มันเซฟได้ โหลดได้ และสามารถ claim ได้ในภายหลัง โดยผู้เล่น เพิ่มอีเมลและรหัสผ่าน แล้วเซฟที่มีอยู่จะติดตามไปโดยไม่ต้องย้ายข้อมูล

ข้อเสียตรงไปตรงมา: การล้างข้อมูลเว็บไซต์ในเบราว์เซอร์จะทำให้เสียบัญชีนั้นไป และไม่มี ทางกู้คืนได้ นั่นคือราคาของ "ไม่ต้องสมัครสมาชิก" และเกมของคุณควรบอกเรื่องนี้ แทนที่ จะปล่อยให้ผู้เล่นค้นพบเอง PlayerIsGuest() มีไว้เพื่อประโยคนั้นโดยเฉพาะ

การเซฟ#

job = PlayerSaveAsync(donnees$)
job = PlayerLoadAsync()

เซฟคือ JSON ในรูปแบบของคุณเอง เก็บไว้ตามคู่ (ผู้เล่นนี้, เกมนี้) มันตามผู้เล่นไปยัง เบราว์เซอร์อื่น เครื่องอื่น แพลตฟอร์มอื่นได้

สำหรับค่าไม่กี่ค่า SetCloudDataVariable() และ CloudDataVariable() ใช้งานง่ายกว่า ไม่ต้องมีงาน ไม่ต้องมี JSON ตรวจสอบ CloudDataAllowed() ก่อนเสมอ: มันจะคืนค่า 0 เมื่อไม่มีผู้เล่นล็อกอินอยู่ และการเขียนต่อไปเงียบ ๆ จะไม่ไปไหนเลย

การวาดหน้าจอ#

Aukimi ไม่ วาดฟอร์มล็อกอินให้ ฟอร์มที่เอนจินสร้างขึ้นจะดูเหมือนหน้าเว็บที่ถูก วางทับลงบนเกมพิกเซลอาร์ตเสมอ และมันจะเป็นส่วนเดียวในเกมของคุณที่คุณปรับสไตล์เองไม่ได้

คุณวาดมันเอง ส่วนเดียวที่ต้องมาจากเบราว์เซอร์คือการรับข้อความ ดังนั้น CreateEditBox() จะให้ช่องอินพุตจริงที่คุณจัดตำแหน่งเอง:

CreateEditBox(1)
EditBoxPosition(1, 20, 42)
EditBoxSize(1, 60, 8)
nom$ = EditBoxText(1)

ตัวอย่าง Player Account ในรายการตัวอย่างของ Engine เป็นหน้าจอที่ทำงานได้ครบ สมบูรณ์ในโค้ดประมาณร้อยบรรทัด เปิดมันขึ้นมา อ่านมัน แล้วแทนที่ Print() ทุกตัว ด้วยงานศิลป์ของคุณเอง

ก่อนที่สิ่งนี้ทั้งหมดจะทำงานได้#

เกมต้องถูกประกาศไว้จากบัญชี Aukimi ของคุณ ภายใต้ My games (aukimi.com/app/games): ชื่อเรื่อง ที่อยู่ที่จะเล่นเกมได้ และที่อยู่ที่เกมของคุณได้รับ อนุญาตให้กลับไปหา จนกว่าจะทำสิ่งนี้ PlayerAvailable() จะคืนค่า 0 และเกมที่ดีควร บอกว่า "บัญชีไม่พร้อมใช้งาน" แทนที่จะดูเหมือนค้าง

หน้าจอเดียวกันนั้นคือที่ที่คุณเห็นว่าใครกำลังเล่นอยู่ อ่านตัวเลขตามความหมายจริงของ มัน: มันนับ ผู้เล่นที่ล็อกอินแล้ว และ เซสชันที่เริ่มต้น ไม่เคยนับจำนวนครั้งที่ เกมถูกเล่น เกมที่ไม่เคยขอให้ใครล็อกอินเลยจะไม่แสดงอะไรตรงนั้น และหน้าจอก็บอกเช่นนั้น แทนที่จะแสดงเลขศูนย์แบบเงียบ ๆ

การใช้เซิร์ฟเวอร์บัญชีของคุณเอง#

ทุกอย่างข้างต้นคุยกับบริการบัญชีของ Aukimi หากคุณโฮสต์เกมของคุณเองบนเซิร์ฟเวอร์ ของคุณ คำสั่งสิบสองคำสั่งเดียวกันนี้สามารถคุยกับบริการ ของคุณ แทนได้ และสคริปต์ ของคุณไม่ต้องเปลี่ยนแม้แต่บรรทัดเดียว

ใน Engine: พาเนล Multiplayer → ส่วน Player accounts → เลือก My own server → กรอกช่องเดียว คือที่อยู่ของเซิร์ฟเวอร์คุณ ที่อยู่นั้นเป็นการตั้งค่าของฉาก ดังนั้นเกมสองเกมสามารถใช้บริการที่ต่างกันสองบริการได้

สองวิธีในการล็อกอินผู้เล่น#

ทางเลือกนี้ทำ ในสคริปต์ของคุณ ไม่ใช่ในการตั้งค่า ทั้งสองรูปแบบมีอยู่ไม่ว่าคุณจะ ชี้ไปที่เซิร์ฟเวอร์ใด

หน้าต่าง (สิ่งที่คุณรู้จักอยู่แล้ว)#

job = PlayerLoginAsync()

หน้าต่างจะเปิดขึ้น ผู้เล่นล็อกอินที่นั่น แล้วมันมอบสิทธิ์ให้เกมของคุณกระทำการแทนพวกเขา กับบริการของ Aukimi หน้าต่างนั้นคือ play.aukimi.com ส่วนกับเซิร์ฟเวอร์ของคุณเอง หน้านั้นเป็นของคุณที่ต้องสร้างเอง

โดยตรง ด้วยชื่อผู้ใช้และรหัสผ่าน#

job = PlayerLoginAsync(username$, password$)

ไม่มีหน้าต่าง เกมของคุณอ่านสิ่งที่ผู้เล่นพิมพ์บนหน้าจอของคุณเองแล้วส่งไปยังเซิร์ฟเวอร์ ของคุณ เขียนง่ายกว่า และช่วยให้คุณคงรูปลักษณ์ของเกมไว้ได้ตลอดทาง

คำเตือน: ในรูปแบบนี้ รหัสผ่านเดินทางจากเกมของคุณไปยังเซิร์ฟเวอร์ของคุณ ตามที่พิมพ์ สองผลที่ตามมา ทั้งสองข้อเด็ดขาด: ที่อยู่ของเซิร์ฟเวอร์คุณต้องขึ้นต้นด้วย https:// (ยกเว้นการทดสอบบนเครื่องของคุณเองเท่านั้น) และรูปแบบนี้มีไว้สำหรับ เซิร์ฟเวอร์ ที่คุณเป็นเจ้าของ เท่านั้น

play.aukimi.com ปฏิเสธรูปแบบนี้โดยตั้งใจ Aukimi ไม่ต้องการอยู่ในตำแหน่งที่เห็น รหัสผ่านของผู้เล่นเลย และเกมที่คุณไม่ได้เขียนเองก็ไม่ควรเห็นเช่นกัน

สองทางเลือกนี้เป็นอิสระจากการตั้งค่า: เซิร์ฟเวอร์ที่สร้างเองอาจเสนอแค่หน้าต่างอย่างเดียว และไม่เคยรับรหัสผ่านโดยตรงเลยก็ได้

ตัวอย่างที่เป็นรูปธรรม#

เกมที่มีหน้าจอ "Sign in" ของตัวเอง: ช่องข้อความสองช่องที่เกมวาดเอง ปุ่มหนึ่งปุ่ม และสิ่งนี้อยู่หลังปุ่มนั้น

job = PlayerLoginAsync(typedName$, typedPassword$)
DO
    etat$ = PlatformJobState(job)
    if etat$ = "done"
        PlatformJobRelease(job)
        Print("Welcome " + PlayerName())
    endif
    if etat$ = "error"
        PlatformJobRelease(job)
        Print(PlayerLastError())
    endif
    Sync()
LOOP

ทุกอย่างหลังจากล็อกอินเหมือนกับส่วนที่เหลือของหน้านี้ทุกประการ: PlayerSaveAsync, PlayerLoadAsync, PlayerName และคำสั่งอื่น ๆ ไม่รู้และไม่สนใจ ว่าเซิร์ฟเวอร์ไหนเป็นผู้ตอบ

สิ่งที่เซิร์ฟเวอร์ของคุณต้องตอบให้ได้#

จำเป็นต้องมีสี่ที่อยู่ ไม่ว่าคุณจะเสนอการล็อกอินแบบไหน:

มีไว้เพื่ออะไรเกมคาดหวังอะไร
เล่นในฐานะแขกส่งบัญชีที่ไม่มีอีเมลกลับมา
ผู้เล่นคนนี้คือใครชื่อที่แสดง, id, และว่าเป็นแขกหรือไม่
อ่านเซฟข้อมูลที่บันทึกไว้
เขียนเซฟเก็บสิ่งที่เกมส่งมา

จากนั้น ขึ้นอยู่กับสิ่งที่คุณเลือกจะเสนอ:

  • รูปแบบหน้าต่าง ต้องการหน้าล็อกอินบนเซิร์ฟเวอร์ของคุณ ซึ่งจะบอกเกมว่าใครล็อกอิน เข้ามาเมื่อเสร็จสิ้น
  • รูปแบบโดยตรง ต้องการอีกหนึ่งที่อยู่ ที่รับชื่อผู้ใช้และรหัสผ่านแล้วตอบว่าใช่หรือไม่

ที่อยู่ที่แน่นอน รูปแบบของแต่ละคำตอบ และรหัสข้อผิดพลาด อยู่ในรีโพซิทอรี ที่ docs/engine-player-accounts.md ไฟล์นั้นคือสัญญา ส่วนหน้านี้คือแผนที่

หมายเหตุ: ไม่มีสิ่งใดในนี้ทำงานในการส่งออกแบบเนทีฟ คำสั่ง Player* ต้องการ เซิร์ฟเวอร์ให้คุยด้วยและเบราว์เซอร์ให้คุยผ่าน และการบิลด์แบบเนทีฟไม่มีทั้งสองอย่าง

คำสั่งทั้งหมด#

คำสั่งทำอะไร
PlayerAvailable()บริการบัญชีถูกตั้งค่าไว้สำหรับเกมนี้หรือไม่
PlayerLoginAsync()เปิดหน้าต่างล็อกอิน คืนค่าเป็นงาน
PlayerLoginAsync(user, pass)ล็อกอินโดยตรง บนเซิร์ฟเวอร์ของคุณเองเท่านั้น คืนค่าเป็นงาน
PlayerGuestAsync()สร้างบัญชีที่ไม่มีอีเมล คืนค่าเป็นงาน
PlayerLoggedIn()มีใครล็อกอินอยู่ตอนนี้หรือไม่
PlayerName()ชื่อที่แสดงของพวกเขา
PlayerID()id ที่ไม่มีความหมายของพวกเขา เฉพาะเกมนี้
PlayerIsGuest()นี่คือบัญชีที่ไม่มีอีเมลหรือไม่
PlayerSaveAsync()เขียนเซฟ คืนค่าเป็นงาน
PlayerLoadAsync()อ่านเซฟกลับมา
PlayerRefreshAsync()ต่ออายุโทเคนก่อนมันจะหมดอายุ
PlayerLogout()ล็อกเอาต์บนอุปกรณ์นี้
PlayerLastError()เหตุผลที่การเรียกครั้งล่าสุดล้มเหลว