add equiping and unequiping actions
This commit is contained in:
parent
6eb89eae24
commit
56915df9ac
@ -23,6 +23,7 @@ token: ?[]u8 = null,
|
||||
item_codes: std.ArrayList([]u8),
|
||||
|
||||
pub const APIError = error {
|
||||
ServerUnavailable,
|
||||
RequestFailed,
|
||||
ParseFailed,
|
||||
OutOfMemory
|
||||
@ -103,6 +104,58 @@ pub const CraftError = APIError || error {
|
||||
WorkshopNotFound
|
||||
};
|
||||
|
||||
pub const UnequipError = APIError || error {
|
||||
ItemNotFound, // TODO: Can this really occur? maybe a bug in docs
|
||||
CharacterIsBusy,
|
||||
SlotIsEmpty,
|
||||
CharacterIsFull,
|
||||
CharacterNotFound,
|
||||
CharacterInCooldown,
|
||||
};
|
||||
|
||||
pub const EquipError = APIError || error {
|
||||
ItemNotFound,
|
||||
SlotIsFull,
|
||||
CharacterIsBusy,
|
||||
NotEnoughSkill,
|
||||
CharacterNotFound,
|
||||
CharacterInCooldown,
|
||||
};
|
||||
|
||||
pub const EquipmentSlot = enum {
|
||||
weapon,
|
||||
shield,
|
||||
helmet,
|
||||
body_armor,
|
||||
leg_armor,
|
||||
boots,
|
||||
ring1,
|
||||
ring2,
|
||||
amulet,
|
||||
artifact1,
|
||||
artifact2,
|
||||
consumable1,
|
||||
consumable2,
|
||||
|
||||
fn name(self: EquipmentSlot) []const u8 {
|
||||
return switch (self) {
|
||||
.weapon => "weapon",
|
||||
.shield => "shield",
|
||||
.helmet => "helmet",
|
||||
.body_armor => "body_armor",
|
||||
.leg_armor => "leg_armor",
|
||||
.boots => "boots",
|
||||
.ring1 => "ring1",
|
||||
.ring2 => "ring2",
|
||||
.amulet => "amulet",
|
||||
.artifact1 => "artifact1",
|
||||
.artifact2 => "artifact2",
|
||||
.consumable1 => "consumable1",
|
||||
.consumable2 => "consumable2",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const ServerStatus = struct {
|
||||
allocator: Allocator,
|
||||
status: []const u8,
|
||||
@ -298,12 +351,12 @@ pub const FightResult = struct {
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?FightError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
486 => return FightError.CharacterIsBusy,
|
||||
497 => return FightError.CharacterIsFull,
|
||||
498 => return FightError.CharacterNotFound,
|
||||
499 => return FightError.CharacterInCooldown,
|
||||
598 => return FightError.MonsterNotFound,
|
||||
else => return null
|
||||
486 => FightError.CharacterIsBusy,
|
||||
497 => FightError.CharacterIsFull,
|
||||
498 => FightError.CharacterNotFound,
|
||||
499 => FightError.CharacterInCooldown,
|
||||
598 => FightError.MonsterNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -353,12 +406,12 @@ pub const GatherResult = struct {
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?GatherError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
486 => return GatherError.CharacterIsBusy,
|
||||
493 => return GatherError.NotEnoughSkill,
|
||||
497 => return GatherError.CharacterIsFull,
|
||||
498 => return GatherError.CharacterNotFound,
|
||||
499 => return GatherError.CharacterInCooldown,
|
||||
598 => return GatherError.ResourceNotFound,
|
||||
486 => GatherError.CharacterIsBusy,
|
||||
493 => GatherError.NotEnoughSkill,
|
||||
497 => GatherError.CharacterIsFull,
|
||||
498 => GatherError.CharacterNotFound,
|
||||
499 => GatherError.CharacterInCooldown,
|
||||
598 => GatherError.ResourceNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
@ -379,11 +432,11 @@ pub const MoveResult = struct {
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?MoveError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => return MoveError.MapNotFound,
|
||||
486 => return MoveError.CharacterIsBusy,
|
||||
490 => return MoveError.CharacterAtDestination,
|
||||
498 => return MoveError.CharacterNotFound,
|
||||
499 => return MoveError.CharacterInCooldown,
|
||||
404 => MoveError.MapNotFound,
|
||||
486 => MoveError.CharacterIsBusy,
|
||||
490 => MoveError.CharacterAtDestination,
|
||||
498 => MoveError.CharacterNotFound,
|
||||
499 => MoveError.CharacterInCooldown,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
@ -407,26 +460,26 @@ pub const GoldTransactionResult = struct {
|
||||
|
||||
pub fn parseDepositError(status: std.http.Status) ?BankDepositGoldError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
461 => return BankDepositGoldError.BankIsBusy,
|
||||
478 => return BankDepositGoldError.NotEnoughGold, // TODO: This should maybe be removed
|
||||
486 => return BankDepositGoldError.CharacterIsBusy,
|
||||
492 => return BankDepositGoldError.NotEnoughGold,
|
||||
498 => return BankDepositGoldError.CharacterNotFound,
|
||||
499 => return BankDepositGoldError.CharacterInCooldown,
|
||||
598 => return BankDepositGoldError.BankNotFound,
|
||||
else => return null
|
||||
461 => BankDepositGoldError.BankIsBusy,
|
||||
478 => BankDepositGoldError.NotEnoughGold, // TODO: This should maybe be removed
|
||||
486 => BankDepositGoldError.CharacterIsBusy,
|
||||
492 => BankDepositGoldError.NotEnoughGold,
|
||||
498 => BankDepositGoldError.CharacterNotFound,
|
||||
499 => BankDepositGoldError.CharacterInCooldown,
|
||||
598 => BankDepositGoldError.BankNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseWithdrawError(status: std.http.Status) ?BankWithdrawGoldError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
460 => return BankWithdrawGoldError.NotEnoughGold,
|
||||
461 => return BankWithdrawGoldError.BankIsBusy,
|
||||
486 => return BankWithdrawGoldError.CharacterIsBusy,
|
||||
498 => return BankWithdrawGoldError.CharacterNotFound,
|
||||
499 => return BankWithdrawGoldError.CharacterInCooldown,
|
||||
598 => return BankWithdrawGoldError.BankNotFound,
|
||||
else => return null
|
||||
460 => BankWithdrawGoldError.NotEnoughGold,
|
||||
461 => BankWithdrawGoldError.BankIsBusy,
|
||||
486 => BankWithdrawGoldError.CharacterIsBusy,
|
||||
498 => BankWithdrawGoldError.CharacterNotFound,
|
||||
499 => BankWithdrawGoldError.CharacterInCooldown,
|
||||
598 => BankWithdrawGoldError.BankNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
|
||||
@ -449,28 +502,28 @@ pub const ItemTransactionResult = struct {
|
||||
|
||||
pub fn parseDepositError(status: std.http.Status) ?BankDepositItemError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => return BankDepositItemError.ItemNotFound,
|
||||
461 => return BankDepositItemError.BankIsBusy,
|
||||
478 => return BankDepositItemError.NotEnoughItems,
|
||||
486 => return BankDepositItemError.CharacterIsBusy,
|
||||
498 => return BankDepositItemError.CharacterNotFound,
|
||||
499 => return BankDepositItemError.CharacterInCooldown,
|
||||
598 => return BankDepositItemError.BankNotFound,
|
||||
else => return null
|
||||
404 => BankDepositItemError.ItemNotFound,
|
||||
461 => BankDepositItemError.BankIsBusy,
|
||||
478 => BankDepositItemError.NotEnoughItems,
|
||||
486 => BankDepositItemError.CharacterIsBusy,
|
||||
498 => BankDepositItemError.CharacterNotFound,
|
||||
499 => BankDepositItemError.CharacterInCooldown,
|
||||
598 => BankDepositItemError.BankNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseWithdrawError(status: std.http.Status) ?BankWithdrawItemError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => return BankWithdrawItemError.ItemNotFound,
|
||||
461 => return BankWithdrawItemError.BankIsBusy,
|
||||
478 => return BankWithdrawItemError.NotEnoughItems,
|
||||
486 => return BankWithdrawItemError.CharacterIsBusy,
|
||||
497 => return BankWithdrawItemError.CharacterIsFull,
|
||||
498 => return BankWithdrawItemError.CharacterNotFound,
|
||||
499 => return BankWithdrawItemError.CharacterInCooldown,
|
||||
598 => return BankWithdrawItemError.BankNotFound,
|
||||
else => return null
|
||||
404 => BankWithdrawItemError.ItemNotFound,
|
||||
461 => BankWithdrawItemError.BankIsBusy,
|
||||
478 => BankWithdrawItemError.NotEnoughItems,
|
||||
486 => BankWithdrawItemError.CharacterIsBusy,
|
||||
497 => BankWithdrawItemError.CharacterIsFull,
|
||||
498 => BankWithdrawItemError.CharacterNotFound,
|
||||
499 => BankWithdrawItemError.CharacterInCooldown,
|
||||
598 => BankWithdrawItemError.BankNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
|
||||
@ -495,14 +548,76 @@ pub const CraftResult = struct {
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?CraftError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => return CraftError.RecipeNotFound,
|
||||
478 => return CraftError.NotEnoughItems,
|
||||
486 => return CraftError.CharacterIsBusy,
|
||||
493 => return CraftError.NotEnoughSkill,
|
||||
497 => return CraftError.CharacterIsFull,
|
||||
498 => return CraftError.CharacterNotFound,
|
||||
499 => return CraftError.CharacterInCooldown,
|
||||
598 => return CraftError.WorkshopNotFound,
|
||||
404 => CraftError.RecipeNotFound,
|
||||
478 => CraftError.NotEnoughItems,
|
||||
486 => CraftError.CharacterIsBusy,
|
||||
493 => CraftError.NotEnoughSkill,
|
||||
497 => CraftError.CharacterIsFull,
|
||||
498 => CraftError.CharacterNotFound,
|
||||
499 => CraftError.CharacterInCooldown,
|
||||
598 => CraftError.WorkshopNotFound,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const UnequipResult = struct {
|
||||
cooldown: Cooldown,
|
||||
item: ItemId,
|
||||
|
||||
pub fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !UnequipResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
|
||||
const item = json_utils.getObject(obj, "item") orelse return error.MissingProperty;
|
||||
const item_code = json_utils.getString(item, "code") orelse return error.MissingProperty;
|
||||
|
||||
const item_id = try api.getItemId(item_code);
|
||||
|
||||
// TODO: Might as well save information about time, because full details about it are given
|
||||
|
||||
return UnequipResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.item = item_id
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?UnequipError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => UnequipError.ItemNotFound,
|
||||
486 => UnequipError.CharacterIsBusy,
|
||||
491 => UnequipError.SlotIsEmpty,
|
||||
497 => UnequipError.CharacterIsFull,
|
||||
498 => UnequipError.CharacterNotFound,
|
||||
499 => UnequipError.CharacterInCooldown,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const EquipResult = struct {
|
||||
cooldown: Cooldown,
|
||||
|
||||
pub fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !EquipResult {
|
||||
_ = api;
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
|
||||
// TODO: Might as well save information about time, because full details about it are given
|
||||
|
||||
return EquipResult{
|
||||
.cooldown = try Cooldown.parse(cooldown)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseError(status: std.http.Status) ?EquipError {
|
||||
return switch (@intFromEnum(status)) {
|
||||
404 => EquipError.ItemNotFound,
|
||||
478 => EquipError.ItemNotFound, // TODO: What is the difference between 404 and 478?
|
||||
485 => EquipError.SlotIsFull,
|
||||
486 => EquipError.CharacterIsBusy,
|
||||
491 => EquipError.SlotIsFull, // TODO: What is the difference between 485 and 491?
|
||||
496 => EquipError.NotEnoughSkill,
|
||||
498 => EquipError.CharacterNotFound,
|
||||
499 => EquipError.CharacterInCooldown,
|
||||
else => null
|
||||
};
|
||||
}
|
||||
@ -548,7 +663,7 @@ const FetchOptions = struct {
|
||||
payload: ?[]const u8 = null
|
||||
};
|
||||
|
||||
fn fetch(self: *ArtifactsAPI, options: FetchOptions) !ArtifactsFetchResult {
|
||||
fn fetch(self: *ArtifactsAPI, options: FetchOptions) APIError!ArtifactsFetchResult {
|
||||
const method = options.method;
|
||||
const path = options.path;
|
||||
const payload = options.payload;
|
||||
@ -573,23 +688,25 @@ fn fetch(self: *ArtifactsAPI, options: FetchOptions) !ArtifactsFetchResult {
|
||||
defer if (authorization_header) |str| self.allocator.free(str);
|
||||
|
||||
if (self.token) |token| {
|
||||
authorization_header = try std.fmt.allocPrint(self.allocator, "Bearer {s}", .{token});
|
||||
authorization_header = std.fmt.allocPrint(self.allocator, "Bearer {s}", .{token}) catch return APIError.OutOfMemory;
|
||||
opts.headers.authorization = .{ .override = authorization_header.? };
|
||||
}
|
||||
|
||||
const result = try self.client.fetch(opts);
|
||||
const result = self.client.fetch(opts) catch return APIError.RequestFailed;
|
||||
const response_body = response_storage.items;
|
||||
|
||||
std.log.debug("fetch result {}", .{result.status});
|
||||
|
||||
if (result.status != .ok) {
|
||||
if (result.status == .service_unavailable) {
|
||||
return APIError.ServerUnavailable;
|
||||
} else if (result.status != .ok) {
|
||||
return ArtifactsFetchResult{
|
||||
.arena = arena,
|
||||
.status = result.status
|
||||
};
|
||||
}
|
||||
|
||||
const parsed = try json.parseFromSliceLeaky(json.Value, arena.allocator(), response_body, .{ .allocate = .alloc_if_needed });
|
||||
const parsed = json.parseFromSliceLeaky(json.Value, arena.allocator(), response_body, .{ .allocate = .alloc_if_needed }) catch return APIError.ParseFailed;
|
||||
if (parsed != json.Value.object) {
|
||||
return APIError.ParseFailed;
|
||||
}
|
||||
@ -614,7 +731,7 @@ fn fetchOptionalObject(
|
||||
@compileError("`parseObject` must be a function");
|
||||
}
|
||||
|
||||
const result = self.fetch(fetchOptions) catch return APIError.RequestFailed;
|
||||
const result = try self.fetch(fetchOptions);
|
||||
defer result.deinit();
|
||||
|
||||
if (result.status != .ok) {
|
||||
@ -913,6 +1030,47 @@ pub fn actionCraft(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn actionUnequip(
|
||||
self: *ArtifactsAPI,
|
||||
name: []const u8,
|
||||
slot: EquipmentSlot
|
||||
) UnequipError!UnequipResult {
|
||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/unequip", .{name});
|
||||
defer self.allocator.free(path);
|
||||
|
||||
const payload = try std.fmt.allocPrint(self.allocator, "{{ \"slot\":\"{s}\" }}", .{slot.name()});
|
||||
defer self.allocator.free(payload);
|
||||
|
||||
return try self.fetchObject(
|
||||
UnequipError,
|
||||
UnequipResult.parseError,
|
||||
UnequipResult,
|
||||
UnequipResult.parse, .{ },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
}
|
||||
|
||||
pub fn actionEquip(
|
||||
self: *ArtifactsAPI,
|
||||
name: []const u8,
|
||||
slot: EquipmentSlot,
|
||||
code: []const u8
|
||||
) EquipError!EquipResult {
|
||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/equip", .{name});
|
||||
defer self.allocator.free(path);
|
||||
|
||||
const payload = try std.fmt.allocPrint(self.allocator, "{{ \"slot\":\"{s}\",\"code\":\"{s}\" }}", .{slot.name(), code});
|
||||
defer self.allocator.free(payload);
|
||||
|
||||
return try self.fetchObject(
|
||||
EquipError,
|
||||
EquipResult.parseError,
|
||||
EquipResult,
|
||||
EquipResult.parse, .{ },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
}
|
||||
|
||||
test "parse date time" {
|
||||
try std.testing.expectEqual(1723069394.105, parseDateTime("2024-08-07T22:23:14.105Z").?);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ fn getItemId(api: *ArtifactsAPI, object: json.ObjectMap, name: []const u8) !?Ite
|
||||
return try api.getItemId(code);
|
||||
}
|
||||
|
||||
|
||||
pub const SkillStats = struct {
|
||||
level: i64,
|
||||
xp: i64,
|
||||
|
10
src/main.zig
10
src/main.zig
@ -202,6 +202,12 @@ pub fn main() !void {
|
||||
var manager = Manager.init(allocator, &api);
|
||||
defer manager.deinit();
|
||||
|
||||
const status = try api.getServerStatus();
|
||||
defer status.deinit();
|
||||
|
||||
std.log.info("Server status: {s} v{s}", .{ status.status, status.version });
|
||||
std.log.info("Characters online: {}", .{ status.characters_online });
|
||||
|
||||
const characters = try api.listMyCharacters();
|
||||
defer characters.deinit();
|
||||
|
||||
@ -209,11 +215,7 @@ pub fn main() !void {
|
||||
try manager.addCharacter(character);
|
||||
}
|
||||
|
||||
const status = try api.getServerStatus();
|
||||
defer status.deinit();
|
||||
|
||||
std.log.info("Server status: {s} v{s}", .{ status.status, status.version });
|
||||
std.log.info("Characters online: {}", .{ status.characters_online });
|
||||
|
||||
std.log.info("Starting main loop", .{});
|
||||
while (manager.poll()) |char| {
|
||||
|
Loading…
Reference in New Issue
Block a user