Chuyển tới nội dung chính

Alliance

Màn Alliance hiện các đồng minh (ally) mà người chơi sở hữu, cho người chơi chọn đồng minh mang vào trận, cho đồng minh lên cấp bằng vật phẩm EXP, nâng cấp Weapon của nó và đặt lại cấp. Cấp, chi phí, chỉ số và phần hoàn trả do server quyết định.

Bạn dùngNó cho bạn
IProjectVAllianceScreenScreen contract: theo dõi các đồng minh, chọn, lên cấp, nâng cấp, đặt lại
ProjectVAllianceViewNhững gì cần vẽ: trạng thái đang tải, các đồng minh, đồng minh đang chọn, vật phẩm EXP
ProjectVAllyViewMột đồng minh: cấp, EXP, chỉ số, kỹ năng Weapon, các bản xem trước
ProjectVXpItemViewMột vật phẩm EXP và số lượng người chơi đang có
ProjectVCharacterXpItemSelectionCác vật phẩm EXP và số lượng sẽ dùng
ProjectVResultKết quả của một command (lệnh)

Đồng minh dùng cùng chỉ số, vật phẩm EXP và kỹ năng Weapon như màn Character.

Bắt đầu nhanh​

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SilverTiger.ProjectV.Unity.Presentation;
using SilverTiger.ProjectV.Unity.Presentation.Alliance;
using SilverTiger.ProjectV.Unity.Presentation.Character;
using UnityEngine;
using VContainer;

public sealed class AlliancePage : MonoBehaviour
{
private IProjectVAllianceScreen alliance = null!;
private IDisposable? observation;

[Inject]
public void Construct(IProjectVAllianceScreen screen) => alliance = screen;

private void OnEnable() => observation = alliance.Observe(Render);

private void OnDisable()
{
observation?.Dispose();
observation = null;
}

private void Render(ProjectVAllianceView view)
{
if (view.IsLoading)
{
ShowLoading(view.LoadError); // LoadError is null while the first load is running
return;
}
ShowAllies(view.Allies, view.SelectedAllyId);
ShowXpItems(view.XpItems);
}

public void OnSelectClicked(string allyId) => _ = RunAsync(alliance.SelectAllyAsync(allyId));

// The "+1" button; use XpForMaximumLevel() for "Max".
public void OnLevelUpClicked(ProjectVAllyView ally) => _ = RunAsync(alliance.LevelUpAsync(ally.Id, ally.XpForNextLevel()));

public void OnWeaponUpgradeClicked(string allyId) => _ = RunAsync(alliance.UpgradeWeaponSkillAsync(allyId));

public void OnResetClicked(string allyId) => _ = RunAsync(alliance.ResetLevelAsync(allyId));

private async Task RunAsync(Task<ProjectVResult> command)
{
var result = await command;
if (this != null && !result.IsSuccess)
{
ShowMessage(result.Message);
}
}

private void ShowLoading(string? error) { }
private void ShowAllies(IReadOnlyList<ProjectVAllyView> allies, string? selectedAllyId) { }
private void ShowXpItems(IReadOnlyList<ProjectVXpItemView> items) { }
private void ShowMessage(string message) { }
}

Đó là toàn bộ trang: theo dõi, vẽ, gọi command. Sau khi thành công bạn không cần làm gì; Render được gọi lại với dữ liệu mới.

Cần vẽ gì​

Render nhận một ProjectVAllianceView:

MemberKiểuDùng để
IsLoadingboolTrue cho tới khi các đồng minh về lần đầu. Hiện spinner
LoadErrorstring?Có giá trị khi lần tải đầu đó thất bại. Hiện nó cùng nút thử lại (Retry) đóng rồi mở lại trang
AlliesIReadOnlyList<ProjectVAllyView>Các đồng minh người chơi sở hữu
SelectedAllyIdstring?Đồng minh người chơi mang vào trận; null khi chưa chọn ai. Đánh dấu (highlight) theo giá trị này, không theo cờ cục bộ
XpItemsIReadOnlyList<ProjectVXpItemView>Vật phẩm EXP: ItemId, Experience (EXP mỗi vật phẩm), Owned
PendingUpgradeAllyIdstring?Đồng minh có lượt lên cấp chưa được xác nhận
Find(allyId)ProjectVAllyView?Tra một đồng minh, ví dụ để làm mới panel nâng cấp đang mở

Với mỗi ProjectVAllyView:

Để hiệnĐọc
Cấp và EXPLevel, Experience; Upgrade cho những gì cấp tiếp theo cần
Chỉ sốStats (máu, tấn công, giáp, v.v.), như ở Character
Cấp tối đaIsMaxLevel
Lựa chọn "+1" và "Max"XpForNextLevel(), XpForMaximumLevel(); rỗng khi không thể đạt thêm cấp nào
Một lựa chọn sẽ làm gìPreviewXp(items): CanSubmit, Message, GrantedExperience, TargetLevel
Nâng cấp WeaponWeaponSkill: Level, MaxLevel, Costs, CanUpgrade, BlockedMessage
Phần hoàn trả khi đặt lạiLevelReset: CanReset, Message, Refunds
"Đang hoàn tất nâng cấp"HasPendingUpgrade: lượt lên cấp của đồng minh này chưa được xác nhận
Tắt các nút lên cấpIsBlockedByPendingUpgrade: lượt lên cấp của một đồng minh khác chưa được xác nhận

View luôn được dựng từ dữ liệu đã xác nhận gần nhất, nên bản xem trước không đổi trong lúc một command đang chạy. Ghép đồng minh với art và text của bạn bằng Id trong một bảng của riêng bạn.

Chọn đồng minh​

Task<ProjectVResult> SelectAllyAsync(string allyId)
Tham sốKiểuGiá trị
allyIdstringally.Id của một đồng minh trong view hiện tại

Trả về một ProjectVResult:

IsSuccessMessageChuyện gì đã xảy ra
truerỗngServer đã xác nhận lựa chọn, hoặc đồng minh đã được chọn từ trước. Highlight chuyển khi Render được gọi
falselý do, sẵn để hiệnLựa chọn không xảy ra, hoặc không xác nhận được (xem bên dưới)

Khi thất bại — hiện Message nguyên văn:

Tình huốngNgười chơi thấy gì
Server từ chối lựa chọnThông báo của server
allyId null hoặc rỗng"The request was not confirmed. Please try again."
Mất kết nối hoặc hết thời gian chờMột thông báo mạng. Đừng tự động chọn lại

SelectAllyAsync không ném exception khi allyId sai; nó trả về kết quả thất bại.

Mỗi lần một lựa chọn. Trong khi một lựa chọn đang chạy, mọi lời gọi SelectAllyAsync khác đều nhận kết quả của lời gọi đầu tiên, kể cả cho một đồng minh khác, và đồng minh khác đó không được chọn. Chờ kết quả đầu tiên rồi mới chọn tiếp.

Lên cấp​

Task<ProjectVResult> LevelUpAsync(string allyId, IReadOnlyList<ProjectVCharacterXpItemSelection> items)
Tham sốKiểuGiá trị
allyIdstringally.Id của một đồng minh trong view hiện tại
itemsIReadOnlyList<ProjectVCharacterXpItemSelection>Các vật phẩm EXP sẽ dùng, thường là ally.XpForNextLevel() hoặc ally.XpForMaximumLevel(). Bị bỏ qua khi đồng minh có lượt nâng cấp đang chờ

Các vật phẩm được dùng trong một request và đồng minh nhận mọi cấp mà chúng đủ để đạt. Phần EXP chưa đủ cho cấp tiếp theo được giữ lại.

Ném exception ngay lập tức, trước khi gửi bất cứ thứ gì:

ExceptionKhi nào
ArgumentExceptionallyId null hoặc rỗng, hoặc items có phần tử null hay không hợp lệ
ArgumentNullExceptionitems là null

Trả về một ProjectVResult:

IsSuccessMessageChuyện gì đã xảy ra
truerỗngServer đã xác nhận lượt lên cấp. Trang tự vẽ lại
falselý do, sẵn để hiệnLượt lên cấp không xảy ra, hoặc không xác nhận được (xem bên dưới)

Khi thất bại — hiện Message nguyên văn. Các lý do thường gặp:

Tình huốngNgười chơi thấy gì
Một đồng minh khác hoặc nhân vật có lượt lên cấp chưa được xác nhận"Another ally or character has an upgrade pending."
Không chọn vật phẩm nào và không đủ EXP cho cấp tiếp theo"Select enough EXP for the next level."
Không đủ tiền tệ cho cấp tiếp theo"Not enough currency for the next level."
Đồng minh đã ở cấp tối đa"Maximum level reached."
Các vật phẩm không thuộc sở hữu hoặc không phải vật phẩm EXP của đồng minh"The selected EXP items are unavailable for this character kind."
Server từ chối lượt lên cấpThông báo của server
Mất kết nối hoặc hết thời gian chờMột thông báo mạng. Lượt lên cấp có thể vẫn đã thành công (xem bên dưới)

Khi không rõ kết quả — ví dụ kết nối bị rớt — lượt lên cấp ở trạng thái chờ. Đồng minh đó hiện HasPendingUpgrade và các đồng minh khác hiện IsBlockedByPendingUpgrade. Lần LevelUpAsync tiếp theo cho đồng minh đó sẽ hoàn tất lượt lên cấp đang chờ với chính các vật phẩm cũ trước khi làm gì mới. Lượt lên cấp đang chờ được dùng chung với màn Character.

Bấm lần thứ hai vào cùng đồng minh trong lúc lượt lên cấp đang chạy sẽ nhận cùng kết quả thay vì tiêu hai lần.

Nâng cấp Weapon​

Task<ProjectVResult> UpgradeWeaponSkillAsync(string allyId)
Tham sốKiểuGiá trị
allyIdstringally.Id của một đồng minh trong view hiện tại

Hiện chi phí và bật nút theo ally.WeaponSkill: Costs cho các dòng giá và CanUpgrade cho nút.

Ném ArgumentException ngay lập tức khi allyId null hoặc rỗng.

Trả về một ProjectVResult:

IsSuccessMessageChuyện gì đã xảy ra
truerỗngServer đã xác nhận nâng cấp. Trang tự vẽ lại
falselý do, sẵn để hiệnNâng cấp không xảy ra, hoặc không xác nhận được (xem bên dưới)

Khi thất bại — hiện Message nguyên văn. Các lý do thường gặp:

Tình huốngNgười chơi thấy gì
Weapon hiện không thể nâng cấpWeaponSkill.BlockedMessage, ví dụ "Maximum level reached."
Các đồng minh chưa được tải"Skill data unavailable."
Server từ chối nâng cấpThông báo của server
Mất kết nối hoặc hết thời gian chờMột thông báo mạng. Đừng tự động nâng cấp lại

Bấm lần thứ hai trong lúc nâng cấp đang chạy sẽ nhận cùng kết quả.

Đặt lại cấp​

Task<ProjectVResult> ResetLevelAsync(string allyId)
Tham sốKiểuGiá trị
allyIdstringally.Id của một đồng minh trong view hiện tại

Đồng minh quay về cấp 1 với 0 EXP, và các vật phẩm EXP nó đã dùng được trả lại. Bậc Weapon và kỹ năng được giữ nguyên. Hiện phần hoàn trả từ ally.LevelReset.Refunds và bật nút theo ally.LevelReset.CanReset.

Ném ArgumentException ngay lập tức khi allyId null hoặc rỗng.

Trả về một ProjectVResult:

IsSuccessMessageChuyện gì đã xảy ra
truerỗngServer đã xác nhận đặt lại. Trang tự vẽ lại
falselý do, sẵn để hiệnĐặt lại không xảy ra, hoặc không xác nhận được (xem bên dưới)

Khi thất bại — hiện Message nguyên văn. Các lý do thường gặp:

Tình huốngNgười chơi thấy gì
Hiện không được phép đặt lạiLevelReset.Message, lý do của server
Đồng minh không thuộc sở hữu"This character is not owned."
Mất kết nối hoặc hết thời gian chờMột thông báo mạng. Đừng tự động đặt lại lần nữa

Bấm lần thứ hai trong lúc đặt lại đang chạy sẽ nhận cùng kết quả.

Quy tắc​

  • Các command chạy lần lượt. Bấm một command khác sẽ chờ cho tới khi command đang chạy kết thúc.
  • Màn tự đồng bộ lại. Sau một kết quả không xác nhận được, hoặc khi dữ liệu đang hiện đã cũ, màn sẽ tải lại các đồng minh ở nền. Lên cấp, nâng cấp Weapon và đặt lại sẽ chờ lần tải lại đó. Bạn không cần nút Refresh.
  • Phần hoàn trả đến từ server. Đặt lại trả về đúng các vật phẩm EXP mà đồng minh đã dùng; EXP nhận bằng cách khác không được hoàn lại gì.
  • Server kiểm tra mọi command. CanUpgrade, CanReset và các bản xem trước của view chỉ dùng để định hình các nút.

Lỗi thường gặp​

  • Chọn đồng minh thứ hai trước khi lựa chọn đầu tiên xong. Lời gọi thứ hai trả về kết quả của lời gọi đầu và không chọn đồng minh thứ hai.
  • Tự tính chi phí, chỉ số hoặc phần hoàn trả trong Client. Dùng view; chỉ dùng asset cục bộ cho hình ảnh và animation.
  • Tự trừ vật phẩm hoặc tiền tệ sau một command. Trang tự cập nhật; số của bạn sẽ sai.
  • Highlight đồng minh đang chọn theo cờ cục bộ. Dùng SelectedAllyId.
  • Truyền ID rỗng hoặc null cho các command lên cấp, Weapon hoặc đặt lại. Chúng ném exception; hãy truyền ally.Id từ view hiện tại.
  • Dùng kết quả sau khi trang đã đóng. Kiểm tra this != null sau await.
  • Không dispose (giải phóng) observation. Giữ IDisposable trả về từ Observe và dispose nó trong OnDisable hoặc OnDestroy.

Presenter​

IProjectVAlliancePresenter là interface cấp thấp hơn nằm sau screen contract. Chỉ dùng nó nếu bạn cần thứ mà màn không cung cấp:

MemberDùng để
SubscribeAsync(listener)Mọi ProjectVAllianceSnapshot: Status, Recovery, RequiresUpgradeSync, và một Error có Code và RequestId
PendingProgressionLượt lên cấp chưa được xác nhận, dùng chung với Character
GetUpgradeState(allyId)Đồng minh có thể lên cấp ngay không, và nếu không thì vì sao
GetXpUpgradePreview(allyId, items)Cấp, EXP và chỉ số mà các vật phẩm này sẽ cho
GetLevelResetPreview(allyId)Có được phép đặt lại không và vật phẩm EXP nào được trả lại
SynchronizeAsync(token)Tải lại từ server, cho một nút Sync rõ ràng
RetryPendingProgressionAsync(token)Hoàn tất lượt lên cấp chưa được xác nhận

Các command của presenter nhận một ProjectVCharacterId và một CancellationToken rồi trả về một ProjectVAllianceCommandResult. UpgradeAllyWithXpItemsAsync và UpgradeWeaponSkillAsync của nó ném ArgumentException khi đồng minh không thuộc sở hữu.

Listener của SubscribeAsync có thể chạy ngoài main thread của Unity; hãy chuyển về main thread trước khi đụng tới object Unity. Observe của màn luôn vẽ (render) trên main thread.