Tài khoản người chơi

Cho người chơi trong game của bạn một tài khoản mà họ giữ xuyên suốt mọi game làm bằng Aukimi, với các bản lưu theo họ từ thiết bị này sang thiết bị khác, trên dịch vụ của Aukimi hoặc trên server của riêng bạn.

Trong một câu#

Một người chơi đăng nhập một lần trên play.aukimi.com và thấy tài khoản đó trong mọi game làm bằng Aukimi, kể cả các bản lưu. Game của bạn hỏi xin tài khoản; nó không bao giờ chạm vào mật khẩu.

Vì sao game của bạn không bao giờ thấy mật khẩu#

Ai cũng có thể xuất bản một game. Một game hỏi xin mật khẩu Aukimi sẽ là một trang phishing hoàn hảo đến mức thuyết phục, và dù bạn có thiện chí đến đâu cũng không thay đổi được điều một nhà phát triển khác có thể làm.

Vậy nên mật khẩu được gõ trên play.aukimi.com và không ở đâu khác. Game của bạn gọi PlayerLoginAsync(), một cửa sổ trình duyệt mở ra trên nền màu riêng của Aukimi, người chơi chấp thuận, và cửa sổ đó trao cho game của bạn một token.

Token đó được cấp riêng cho game của bạn mà thôi. Một token của game A đưa cho game B sẽ bị từ chối (không phải bị bỏ qua, mà bị từ chối). Đó chính là điểm mấu chốt: tài khoản được chia sẻ giữa các game, quyền truy cập thì không. Không có điều này, một game độc hại sẽ có thể đọc được bản lưu của người chơi ở mọi game khác.

Bạn nhận được gì về một người chơi#

Hai thứ, không hơn:

Bạn nhận đượcBạn không bao giờ nhận được
Một tên hiển thị (PlayerName())Địa chỉ email
Một id ẩn danh, khác nhau ở mỗi game (PlayerID())Bất cứ thứ gì có thể nhận diện họ ở nơi khác

Id thay đổi từ game này sang game khác một cách có chủ đích. Hai nhà phát triển so sánh danh sách người chơi của họ không thể biết họ đang nhìn vào cùng một người. Điều này cũng giữ cho bạn ở vai trò một bên xử lý dữ liệu chứ không phải một bên kiểm soát nó, một khác biệt về mặt pháp lý chứ không phải trang trí.

Không gì làm nghẽn vòng lặp game#

Mọi lệnh giao tiếp với mạng đều trả về một job number, không bao giờ trả về kết quả trực tiếp. Vòng lặp của bạn vẫn tiếp tục chạy ở sáu mươi khung hình mỗi giây trong khi yêu cầu đang được xử lý (đây chính là lý do vì sao một game không thể đơn giản là "chờ server").

job = PlayerLoginAsync()

Sau đó, mỗi khung hình một lần:

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

Giải phóng job ngay khi bạn đã đọc nó. Một job không bao giờ được giải phóng sẽ giữ kết quả của nó trong bộ nhớ suốt phần còn lại của phiên. Không gì bị lỗi, không gì cảnh báo bạn, và rò rỉ chỉ lộ ra trong một phiên chơi dài.

Chơi mà không cần tài khoản#

Không phải ai cũng muốn đăng ký trước khi thử một game. PlayerGuestAsync(name$) tạo một tài khoản không có email, giữ trong trình duyệt này.

Đó là một tài khoản thật: nó lưu, nó tải, và có thể được nhận (claim) sau này, khi người chơi thêm một email và một mật khẩu, và các bản lưu hiện có đi theo mà không phải di chuyển.

Cái giá thành thật: xoá dữ liệu trang của trình duyệt sẽ làm mất tài khoản đó, và không có cách nào khôi phục lại. Đó là cái giá của "không cần đăng ký", và game của bạn nên nói rõ điều đó thay vì để người chơi tự phát hiện ra. PlayerIsGuest() tồn tại chính xác cho câu nói đó.

Lưu game#

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

Bản lưu là JSON theo hình dạng của riêng bạn, được lưu trữ theo cặp (người chơi này, game này). Nó theo họ sang một trình duyệt khác, một máy khác, một nền tảng khác.

Với một số ít giá trị, SetCloudDataVariable()CloudDataVariable() đơn giản hơn nhiều (không cần job, không cần JSON). Kiểm tra CloudDataAllowed() trước: nó trả về 0 khi không có người chơi nào đăng nhập, và cứ ghi bừa sẽ âm thầm không đi đến đâu cả.

Vẽ màn hình#

Aukimi không vẽ bất kỳ form đăng nhập nào. Một form do engine soạn sẵn sẽ luôn trông như một trang web bị thả vào giữa một game pixel art, và nó sẽ là phần duy nhất trong game của bạn mà bạn không thể tạo lại giao diện riêng.

Bạn tự vẽ nó. Phần duy nhất bắt buộc phải đến từ trình duyệt là ô nhập chữ, nên CreateEditBox() cho bạn một ô nhập liệu thật mà bạn tự định vị:

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

Demo Player Account trong danh sách mẫu của Engine là một màn hình hoạt động hoàn chỉnh trong khoảng một trăm dòng. Mở nó ra, đọc nó, rồi thay từng Print() bằng hình ảnh của riêng bạn.

Trước khi tất cả những điều này hoạt động#

Game phải được khai báo từ tài khoản Aukimi của bạn, dưới mục My games (aukimi.com/app/games): một tiêu đề, địa chỉ nơi game có thể chơi được, và các địa chỉ mà game của bạn được phép quay về. Cho đến lúc đó PlayerAvailable() trả về 0, và một game tốt sẽ nói "tài khoản chưa khả dụng" thay vì trông như đang treo máy.

Cùng màn hình đó là nơi bạn thấy ai đang chơi. Hãy đọc các con số đúng như bản chất của chúng: nó đếm người chơi đã đăng nhậpphiên đã bắt đầu, không bao giờ là số lượt chơi. Một game không bao giờ yêu cầu ai đăng nhập sẽ không hiện gì ở đó, và màn hình nói rõ điều đó thay vì hiện một con số 0 âm thầm.

Dùng server tài khoản của riêng bạn#

Mọi thứ ở trên nói chuyện với dịch vụ tài khoản của Aukimi. Nếu bạn tự host game trên server của riêng mình, cùng mười hai lệnh đó có thể nói chuyện với dịch vụ của bạn thay vào đó, và script của bạn không cần đổi một dòng nào.

Trong Engine: panel Multiplayer → mục Player accounts → chọn My own server → điền vào một trường duy nhất, địa chỉ server của bạn. Địa chỉ đó là một cài đặt của scene, nên hai game có thể dùng hai dịch vụ khác nhau.

Hai cách đăng nhập một người chơi#

Lựa chọn được thực hiện trong script của bạn, không phải trong một cài đặt. Cả hai dạng đều tồn tại bất kể bạn trỏ đến server nào.

Cửa sổ (điều bạn đã biết)#

job = PlayerLoginAsync()

Một cửa sổ mở ra, người chơi đăng nhập ở đó, và nó trao cho game của bạn quyền hành động thay mặt họ. Với dịch vụ của Aukimi, cửa sổ đó là play.aukimi.com. Với server của riêng bạn, trang đó là của bạn để dựng lên.

Trực tiếp, với tên đăng nhập và mật khẩu#

job = PlayerLoginAsync(username$, password$)

Không cửa sổ. Game của bạn đọc những gì người chơi gõ trên màn hình của riêng bạn và gửi nó đến server của bạn. Đơn giản hơn để viết, và nó cho phép bạn giữ nguyên diện mạo của game từ đầu đến cuối.

Cảnh báo: trong dạng này, mật khẩu đi từ game của bạn đến server của bạn đúng như đã gõ. Hai hệ quả, cả hai đều chắc chắn: địa chỉ server của bạn phải bắt đầu bằng https:// (chỉ được miễn trừ khi thử nghiệm trên chính máy của bạn), và dạng này chỉ dành cho một server bạn sở hữu.

play.aukimi.com từ chối nó, có chủ đích. Aukimi không bao giờ muốn ở vị trí có thể nhìn thấy mật khẩu của một người chơi, và một game bạn không tự viết cũng không nên như vậy.

Hai lựa chọn này độc lập với cài đặt: một server tự dựng hoàn toàn có thể chỉ cung cấp cửa sổ mà thôi, và không bao giờ chấp nhận mật khẩu trực tiếp.

Một ví dụ cụ thể#

Một game với màn hình "Đăng nhập" của riêng nó: hai ô nhập chữ do game vẽ ra, một nút bấm, và đoạn này đứng sau nút bấm đó.

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

Mọi thứ sau bước đăng nhập đều giống hệt phần còn lại của trang này: PlayerSaveAsync, PlayerLoadAsync, PlayerName và những lệnh khác không biết, và không quan tâm, server nào đã trả lời.

Server của bạn phải trả lời những gì#

Bốn địa chỉ là bắt buộc, dù bạn cung cấp hình thức đăng nhập nào:

Dùng để làm gìGame mong đợi gì
Chơi với tư cách kháchTrả về một tài khoản không có email
Người chơi này là aiTên hiển thị, id, có phải là khách hay không
Đọc bản lưuDữ liệu đã lưu
Ghi bản lưuLưu lại những gì game gửi lên

Sau đó, tuỳ vào những gì bạn chọn cung cấp:

  • Dạng cửa sổ cần một trang đăng nhập trên server của bạn, trang này báo cho game biết ai vừa đăng nhập khi xong.
  • Dạng trực tiếp cần thêm một địa chỉ nữa, nhận vào một tên đăng nhập và một mật khẩu rồi trả lời có hoặc không.

Các địa chỉ chính xác, hình dạng của mỗi câu trả lời và các mã lỗi nằm trong repository, ở file docs/engine-player-accounts.md. File đó là hợp đồng; trang này là bản đồ.

Lưu ý: không cái nào trong số này hoạt động trong một bản xuất native. Các lệnh Player* cần một server để nói chuyện cùng và một trình duyệt để nói chuyện qua đó, và một bản build native không có cả hai.

Các lệnh#

LệnhNó làm gì
PlayerAvailable()Dịch vụ tài khoản đã được cấu hình cho game này chưa
PlayerLoginAsync()Mở cửa sổ đăng nhập. Trả về một job
PlayerLoginAsync(user, pass)Đăng nhập trực tiếp, chỉ trên server của riêng bạn. Trả về một job
PlayerGuestAsync()Tạo một tài khoản không có email. Trả về một job
PlayerLoggedIn()Có ai đang đăng nhập ngay lúc này không
PlayerName()Tên hiển thị của họ
PlayerID()Id ẩn danh của họ, riêng cho game này
PlayerIsGuest()Đây có phải một tài khoản không có email hay không
PlayerSaveAsync()Ghi bản lưu. Trả về một job
PlayerLoadAsync()Đọc nó lại. Trả về một job
PlayerRefreshAsync()Gia hạn token trước khi nó hết hạn
PlayerLogout()Đăng xuất trên thiết bị này
PlayerLastError()Vì sao lệnh gọi gần nhất thất bại