move schemas to different iles
This commit is contained in:
parent
dad53513c7
commit
fdbf005126
@ -1,5 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
// TODO: Maybe it would be good to move date time parsing to separate module
|
||||
|
||||
pub fn parseDateTime(datetime: []const u8) ?f64 {
|
||||
const time_h = @cImport({
|
||||
@cDefine("_XOPEN_SOURCE", "700");
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
pub const parseDateTime = @import("./date_time/parse.zig").parseDateTime;
|
||||
|
||||
pub const Server = @import("server.zig");
|
||||
pub const Position = @import("position.zig");
|
||||
pub const BoundedSlotsArray = @import("slot_array.zig").BoundedSlotsArray;
|
||||
pub const BoundedSlotsArray = @import("schemas/slot_array.zig").BoundedSlotsArray;
|
||||
|
||||
pub const Slot = Server.Slot;
|
||||
pub const ItemId = Server.ItemId;
|
||||
|
23
api/schemas/bank_gold_transaction.zig
Normal file
23
api/schemas/bank_gold_transaction.zig
Normal file
@ -0,0 +1,23 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
|
||||
const BankGoldTransaction = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !BankGoldTransaction {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return BankGoldTransaction{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
23
api/schemas/bank_item_transaction.zig
Normal file
23
api/schemas/bank_item_transaction.zig
Normal file
@ -0,0 +1,23 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
|
||||
const BankItemTransaction = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !BankItemTransaction {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return BankItemTransaction{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const Server = @import("./server.zig");
|
||||
const Position = @import("./position.zig");
|
||||
const parseDateTime = Server.parseDateTime;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const Position = @import("../position.zig");
|
||||
const parseDateTime = @import("../date_time/parse.zig").parseDateTime;
|
||||
const ItemId = Server.ItemId;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const json = std.json;
|
27
api/schemas/character_fight.zig
Normal file
27
api/schemas/character_fight.zig
Normal file
@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Fight = @import("./fight.zig");
|
||||
const Character = @import("./character.zig");
|
||||
|
||||
const CharacterFight = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
fight: Fight,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !CharacterFight {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const fight = json_utils.getObject(obj, "fight") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return CharacterFight{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.fight = try Fight.parse(api, fight),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
23
api/schemas/character_movement.zig
Normal file
23
api/schemas/character_movement.zig
Normal file
@ -0,0 +1,23 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
|
||||
const CharacterMovement = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !CharacterMovement {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return CharacterMovement{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
|
||||
const CombatStats = @This();
|
53
api/schemas/cooldown.zig
Normal file
53
api/schemas/cooldown.zig
Normal file
@ -0,0 +1,53 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
pub const parseDateTime = @import("../date_time/parse.zig").parseDateTime;
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json = std.json;
|
||||
|
||||
const Cooldown = @This();
|
||||
|
||||
const ReasonUtils = EnumStringUtils(Reason, .{
|
||||
.{ "movement" , Reason.movement },
|
||||
.{ "fight" , Reason.fight },
|
||||
.{ "crafting" , Reason.crafting },
|
||||
.{ "gathering" , Reason.gathering },
|
||||
.{ "buy_ge" , Reason.buy_ge },
|
||||
.{ "sell_ge" , Reason.sell_ge },
|
||||
.{ "delete_item" , Reason.delete_item },
|
||||
.{ "deposit_bank" , Reason.deposit_bank },
|
||||
.{ "withdraw_bank", Reason.withdraw_bank },
|
||||
.{ "equip" , Reason.equip },
|
||||
.{ "unequip" , Reason.unequip },
|
||||
.{ "task" , Reason.task },
|
||||
.{ "recycling" , Reason.recycling },
|
||||
});
|
||||
pub const Reason = enum {
|
||||
movement,
|
||||
fight,
|
||||
crafting,
|
||||
gathering,
|
||||
buy_ge,
|
||||
sell_ge,
|
||||
delete_item,
|
||||
deposit_bank,
|
||||
withdraw_bank,
|
||||
equip,
|
||||
unequip,
|
||||
task,
|
||||
recycling,
|
||||
|
||||
const parse = ReasonUtils.fromString;
|
||||
};
|
||||
|
||||
expiration: f64,
|
||||
reason: Reason,
|
||||
|
||||
pub fn parse(obj: json.ObjectMap) !Cooldown {
|
||||
const reason = try json_utils.getStringRequired(obj, "reason");
|
||||
const expiration = try json_utils.getStringRequired(obj, "expiration");
|
||||
|
||||
return Cooldown{
|
||||
.expiration = parseDateTime(expiration) orelse return error.InvalidDateTime,
|
||||
.reason = Reason.parse(reason) orelse return error.UnknownReason
|
||||
};
|
||||
}
|
35
api/schemas/craft.zig
Normal file
35
api/schemas/craft.zig
Normal file
@ -0,0 +1,35 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json = std.json;
|
||||
|
||||
const Skill = @import("./skill.zig").Skill;
|
||||
const SkillUtils = @import("./skill.zig").SkillUtils;
|
||||
|
||||
const Items = BoundedSlotsArray(8);
|
||||
|
||||
const Craft = @This();
|
||||
|
||||
skill: Skill,
|
||||
level: u64,
|
||||
quantity: u64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Craft {
|
||||
const skill = json_utils.getString(obj, "skill") orelse return error.MissingProperty;
|
||||
const level = json_utils.getInteger(obj, "level") orelse return error.MissingProperty;
|
||||
if (level < 1) return error.InvalidLevel;
|
||||
|
||||
const quantity = json_utils.getInteger(obj, "quantity") orelse return error.MissingProperty;
|
||||
if (quantity < 1) return error.InvalidQuantity;
|
||||
|
||||
const items = json_utils.getArray(obj, "items") orelse return error.MissingProperty;
|
||||
|
||||
return Craft{
|
||||
.skill = SkillUtils.fromString(skill) orelse return error.InvalidSkill,
|
||||
.level = @intCast(level),
|
||||
.quantity = @intCast(quantity),
|
||||
.items = try Items.parse(api, items)
|
||||
};
|
||||
}
|
59
api/schemas/drop_rate.zig
Normal file
59
api/schemas/drop_rate.zig
Normal file
@ -0,0 +1,59 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const json = std.json;
|
||||
|
||||
const DropRate = @This();
|
||||
|
||||
item_id: ItemId,
|
||||
rate: u64,
|
||||
min_quantity: u64,
|
||||
max_quantity: u64,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !DropRate {
|
||||
const rate = try json_utils.getIntegerRequired(obj, "rate");
|
||||
if (rate < 1) {
|
||||
return error.InvalidRate;
|
||||
}
|
||||
|
||||
const min_quantity = try json_utils.getIntegerRequired(obj, "min_quantity");
|
||||
if (min_quantity < 1) {
|
||||
return error.InvalidMinQuantity;
|
||||
}
|
||||
|
||||
const max_quantity = try json_utils.getIntegerRequired(obj, "max_quantity");
|
||||
if (max_quantity < 1) {
|
||||
return error.InvalidMinQuantity;
|
||||
}
|
||||
|
||||
const code_str = try json_utils.getStringRequired(obj, "code");
|
||||
const item_id = try api.getItemId(code_str);
|
||||
|
||||
return DropRate{
|
||||
.item_id = item_id,
|
||||
.rate = @intCast(rate),
|
||||
.min_quantity = @intCast(min_quantity),
|
||||
.max_quantity = @intCast(max_quantity)
|
||||
};
|
||||
}
|
||||
|
||||
pub const DropRates = std.BoundedArray(DropRate, 8); // TODO: Maybe rename to "List"?
|
||||
|
||||
pub fn parseList(api: *Server, array: json.Array) !DropRates {
|
||||
var drops = DropRates.init(0) catch unreachable;
|
||||
for (array.items) |drop_value| {
|
||||
const drop_obj = json_utils.asObject(drop_value) orelse return error.InvalidObject;
|
||||
try drops.append(try DropRate.parse(api, drop_obj));
|
||||
}
|
||||
return drops;
|
||||
}
|
||||
|
||||
pub fn doesListContain(drops: *DropRates, item_id: ItemId) bool {
|
||||
for (drops.constSlice()) |drop| {
|
||||
if (drop.item_id == item_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
28
api/schemas/equip_request.zig
Normal file
28
api/schemas/equip_request.zig
Normal file
@ -0,0 +1,28 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const ItemId = Server.ItemId;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
|
||||
const EquipRequest = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
item: ItemId,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !EquipRequest {
|
||||
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 EquipRequest{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.item = item_id
|
||||
};
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const Server = @import("./server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const json = std.json;
|
||||
|
46
api/schemas/fight.zig
Normal file
46
api/schemas/fight.zig
Normal file
@ -0,0 +1,46 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
|
||||
const Fight = @This();
|
||||
|
||||
pub const Drops = BoundedSlotsArray(8);
|
||||
|
||||
xp: u64,
|
||||
gold: u64,
|
||||
drops: Drops,
|
||||
won: bool,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Fight {
|
||||
const result = try json_utils.getStringRequired(obj, "result");
|
||||
|
||||
var won = false;
|
||||
if (std.mem.eql(u8, result, "win")) {
|
||||
won = true;
|
||||
} else if (std.mem.eql(u8, result, "lose")) {
|
||||
won = false;
|
||||
} else {
|
||||
return error.InvalidProperty;
|
||||
}
|
||||
|
||||
const drops_obj = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
const xp = try json_utils.getIntegerRequired(obj, "xp");
|
||||
if (xp < 0) {
|
||||
return error.InvalidXp;
|
||||
}
|
||||
|
||||
const gold = try json_utils.getIntegerRequired(obj, "gold");
|
||||
if (gold < 0) {
|
||||
return error.InvalidGold;
|
||||
}
|
||||
|
||||
return Fight{
|
||||
.xp = @intCast(xp),
|
||||
.gold = @intCast(gold),
|
||||
.drops = try Drops.parse(api, drops_obj),
|
||||
.won = won,
|
||||
};
|
||||
}
|
75
api/schemas/item.zig
Normal file
75
api/schemas/item.zig
Normal file
@ -0,0 +1,75 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
|
||||
const Craft = @import("./craft.zig");
|
||||
|
||||
const Item = @This();
|
||||
|
||||
pub const Type = enum {
|
||||
consumable,
|
||||
body_armor,
|
||||
weapon,
|
||||
resource,
|
||||
leg_armor,
|
||||
helmet,
|
||||
boots,
|
||||
shield,
|
||||
amulet,
|
||||
ring,
|
||||
artifact,
|
||||
currency,
|
||||
};
|
||||
pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
.{ "consumable", .consumable },
|
||||
.{ "body_armor", .body_armor },
|
||||
.{ "weapon" , .weapon },
|
||||
.{ "resource" , .resource },
|
||||
.{ "leg_armor" , .leg_armor },
|
||||
.{ "helmet" , .helmet },
|
||||
.{ "boots" , .boots },
|
||||
.{ "shield" , .shield },
|
||||
.{ "amulet" , .amulet },
|
||||
.{ "ring" , .ring },
|
||||
.{ "artifact" , .artifact },
|
||||
.{ "currency" , .currency },
|
||||
});
|
||||
|
||||
allocator: Allocator,
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
level: u64,
|
||||
type: Type,
|
||||
subtype: []u8,
|
||||
description: []u8,
|
||||
craft: ?Craft,
|
||||
// TODO: effects
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Item {
|
||||
const level = json_utils.getInteger(obj, "level") orelse return error.MissingProperty;
|
||||
if (level < 1) return error.InvalidLevel;
|
||||
|
||||
const craft = json_utils.getObject(obj, "craft");
|
||||
const item_type_str = try json_utils.getStringRequired(obj, "type");
|
||||
|
||||
return Item{
|
||||
.allocator = allocator,
|
||||
.name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty,
|
||||
.code = (try json_utils.dupeString(allocator, obj, "code")) orelse return error.MissingProperty,
|
||||
.level = @intCast(level),
|
||||
.type = TypeUtils.fromString(item_type_str) orelse return error.InvalidType,
|
||||
.subtype = (try json_utils.dupeString(allocator, obj, "subtype")) orelse return error.MissingProperty,
|
||||
.description = (try json_utils.dupeString(allocator, obj, "description")) orelse return error.MissingProperty,
|
||||
.craft = if (craft != null) try Craft.parse(api, craft.?) else null
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Item) void {
|
||||
self.allocator.free(self.name);
|
||||
self.allocator.free(self.code);
|
||||
self.allocator.free(self.subtype);
|
||||
self.allocator.free(self.description);
|
||||
}
|
37
api/schemas/map.zig
Normal file
37
api/schemas/map.zig
Normal file
@ -0,0 +1,37 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Position = @import("../position.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Map = @This();
|
||||
|
||||
const MapContent = @import("./map_content.zig");
|
||||
|
||||
name: []u8,
|
||||
skin: []u8,
|
||||
position: Position,
|
||||
content: ?MapContent,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Map {
|
||||
const content = json_utils.getObject(obj, "content");
|
||||
|
||||
const x = json_utils.getInteger(obj, "x") orelse return error.MissingProperty;
|
||||
const y = json_utils.getInteger(obj, "y") orelse return error.MissingProperty;
|
||||
|
||||
return Map{
|
||||
.name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty,
|
||||
.skin = (try json_utils.dupeString(allocator, obj, "skin")) orelse return error.MissingProperty,
|
||||
.position = Position.init(x, y),
|
||||
.content = try MapContent.parse(api, content, allocator)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Map, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.skin);
|
||||
if (self.content) |content| {
|
||||
content.deinit(allocator);
|
||||
}
|
||||
}
|
43
api/schemas/map_content.zig
Normal file
43
api/schemas/map_content.zig
Normal file
@ -0,0 +1,43 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
|
||||
const MapContent = @This();
|
||||
|
||||
pub const Type = enum {
|
||||
monster,
|
||||
resource,
|
||||
workshop,
|
||||
bank,
|
||||
grand_exchange,
|
||||
tasks_master,
|
||||
};
|
||||
pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
.{ "monster" , Type.monster },
|
||||
.{ "resource" , Type.resource },
|
||||
.{ "workshop" , Type.workshop },
|
||||
.{ "bank" , Type.bank },
|
||||
.{ "grand_exchange", Type.grand_exchange },
|
||||
.{ "tasks_master" , Type.tasks_master },
|
||||
});
|
||||
|
||||
type: Type,
|
||||
code: []u8,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) MapContent {
|
||||
_ = api;
|
||||
|
||||
const content_type = json_utils.getString(obj, "type") orelse return error.MissingProperty;
|
||||
|
||||
return MapContent{
|
||||
.type = TypeUtils.fromString(content_type) orelse return error.InvalidContentType,
|
||||
.code = (try json_utils.dupeString(allocator, obj, "code")) orelse return error.MissingProperty,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: MapContent, allocator: Allocator) void {
|
||||
allocator.free(self.code);
|
||||
}
|
81
api/schemas/monster.zig
Normal file
81
api/schemas/monster.zig
Normal file
@ -0,0 +1,81 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const DropRate = @import("./drop_rate.zig");
|
||||
const DropRates = DropRate.DropRates;
|
||||
|
||||
const Monster = @This();
|
||||
|
||||
pub const ElementalStats = struct {
|
||||
attack: i64,
|
||||
resistance: i64,
|
||||
|
||||
pub fn parse(object: json.ObjectMap, attack: []const u8, resistance: []const u8) !ElementalStats {
|
||||
return ElementalStats{
|
||||
.attack = try json_utils.getIntegerRequired(object, attack),
|
||||
.resistance = try json_utils.getIntegerRequired(object, resistance),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
level: u64,
|
||||
hp: u64,
|
||||
min_gold: u64,
|
||||
max_gold: u64,
|
||||
|
||||
fire: ElementalStats,
|
||||
earth: ElementalStats,
|
||||
water: ElementalStats,
|
||||
air: ElementalStats,
|
||||
|
||||
drops: DropRates,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Monster {
|
||||
const drops_array = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
const min_gold = try json_utils.getIntegerRequired(obj, "min_gold");
|
||||
if (min_gold < 0) {
|
||||
return error.InvalidMinGold;
|
||||
}
|
||||
|
||||
const max_gold = try json_utils.getIntegerRequired(obj, "max_gold");
|
||||
if (max_gold < 0) {
|
||||
return error.InvalidMaxGold;
|
||||
}
|
||||
|
||||
const level = try json_utils.getIntegerRequired(obj, "level");
|
||||
if (level < 0) {
|
||||
return error.InvalidLevel;
|
||||
}
|
||||
|
||||
const hp = try json_utils.getIntegerRequired(obj, "hp");
|
||||
if (hp < 0) {
|
||||
return error.InvalidHp;
|
||||
}
|
||||
|
||||
return Monster{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.level = @intCast(level),
|
||||
.hp = @intCast(hp),
|
||||
|
||||
.fire = try ElementalStats.parse(obj, "attack_fire" , "res_fire" ),
|
||||
.earth = try ElementalStats.parse(obj, "attack_earth", "res_earth"),
|
||||
.water = try ElementalStats.parse(obj, "attack_water", "res_water"),
|
||||
.air = try ElementalStats.parse(obj, "attack_air" , "res_air" ),
|
||||
|
||||
.min_gold = @intCast(min_gold),
|
||||
.max_gold = @intCast(max_gold),
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Monster, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
52
api/schemas/resource.zig
Normal file
52
api/schemas/resource.zig
Normal file
@ -0,0 +1,52 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const DropRate = @import("./drop_rate.zig");
|
||||
const DropRates = DropRate.DropRates;
|
||||
|
||||
const Resource = @This();
|
||||
|
||||
pub const Skill = enum {
|
||||
mining,
|
||||
woodcutting,
|
||||
fishing,
|
||||
};
|
||||
pub const SkillUtils = EnumStringUtils(Skill, .{
|
||||
.{ "mining" , .mining },
|
||||
.{ "woodcutting", .woodcutting },
|
||||
.{ "fishing" , .fishing },
|
||||
});
|
||||
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
skill: Skill,
|
||||
level: u64,
|
||||
drops: DropRates,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Resource {
|
||||
const drops_array = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
const level = try json_utils.getIntegerRequired(obj, "level");
|
||||
if (level < 0) {
|
||||
return error.InvalidLevel;
|
||||
}
|
||||
|
||||
const skill_str = try json_utils.getStringRequired(obj, "skill");
|
||||
|
||||
return Resource{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.level = @intCast(level),
|
||||
.skill = SkillUtils.fromString(skill_str) orelse return error.InvalidSkill,
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Resource, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
22
api/schemas/single_item.zig
Normal file
22
api/schemas/single_item.zig
Normal file
@ -0,0 +1,22 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Item = @import("./item.zig");
|
||||
|
||||
const SingleItem = @This();
|
||||
|
||||
item: Item,
|
||||
// TODO: Grand exchange
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !SingleItem {
|
||||
const item_obj = json_utils.getObject(obj, "item") orelse return error.MissingProperty;
|
||||
const ge_obj = json_utils.getObject(obj, "ge") orelse return error.MissingProperty;
|
||||
_ = ge_obj;
|
||||
|
||||
return SingleItem{
|
||||
.item = try Item.parse(api, item_obj, allocator),
|
||||
};
|
||||
}
|
18
api/schemas/skill.zig
Normal file
18
api/schemas/skill.zig
Normal file
@ -0,0 +1,18 @@
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
|
||||
pub const Skill = enum {
|
||||
weaponcrafting,
|
||||
gearcrafting,
|
||||
jewelrycrafting,
|
||||
cooking,
|
||||
woodcutting,
|
||||
mining,
|
||||
};
|
||||
pub const SkillUtils = EnumStringUtils(Skill, .{
|
||||
.{ "weaponcrafting" , Skill.weaponcrafting },
|
||||
.{ "gearcrafting" , Skill.gearcrafting },
|
||||
.{ "jewelrycrafting", Skill.jewelrycrafting },
|
||||
.{ "cooking" , Skill.cooking },
|
||||
.{ "woodcutting" , Skill.woodcutting },
|
||||
.{ "mining" , Skill.mining },
|
||||
});
|
27
api/schemas/skill_data.zig
Normal file
27
api/schemas/skill_data.zig
Normal file
@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
const SkillInfo = @import("./skill_info.zig");
|
||||
|
||||
const SkillData = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
details: SkillInfo,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !SkillData {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const details = json_utils.getObject(obj, "details") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return SkillData{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.details = try SkillInfo.parse(api, details),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
21
api/schemas/skill_info.zig
Normal file
21
api/schemas/skill_info.zig
Normal file
@ -0,0 +1,21 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
|
||||
const Items = BoundedSlotsArray(8);
|
||||
|
||||
const SkillInfo = @This();
|
||||
|
||||
xp: i64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !SkillInfo {
|
||||
const items = json_utils.getArray(obj, "items") orelse return error.MissingProperty;
|
||||
|
||||
return SkillInfo{
|
||||
.xp = try json_utils.getIntegerRequired(obj, "xp"),
|
||||
.items = try Items.parse(api, items),
|
||||
};
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("./json_utils.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
|
||||
const SkillStats = @This();
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const Server = @import("./server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const json = std.json;
|
||||
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const Server = @import("./server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const assert = std.debug.assert;
|
||||
const json = std.json;
|
32
api/schemas/status.zig
Normal file
32
api/schemas/status.zig
Normal file
@ -0,0 +1,32 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const ServerStatus = @This();
|
||||
|
||||
allocator: Allocator,
|
||||
status: []const u8,
|
||||
version: []const u8,
|
||||
characters_online: u64,
|
||||
|
||||
pub fn parse(api: *Server, object: json.ObjectMap, allocator: Allocator) !ServerStatus {
|
||||
_ = api;
|
||||
const characters_online = json_utils.getInteger(object, "characters_online") orelse return error.MissingProperty;
|
||||
if (characters_online < 0) {
|
||||
return error.InvalidCharactersOnline;
|
||||
}
|
||||
|
||||
return ServerStatus{
|
||||
.allocator = allocator,
|
||||
.characters_online = @intCast(characters_online),
|
||||
.status = (try json_utils.dupeString(allocator, object, "status")) orelse return error.MissingStatus,
|
||||
.version = (try json_utils.dupeString(allocator, object, "version")) orelse return error.MissingVersion
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: ServerStatus) void {
|
||||
self.allocator.free(self.status);
|
||||
self.allocator.free(self.version);
|
||||
}
|
40
api/schemas/task.zig
Normal file
40
api/schemas/task.zig
Normal file
@ -0,0 +1,40 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json = std.json;
|
||||
const ItemId = Server.ItemId;
|
||||
|
||||
const Task = @This();
|
||||
|
||||
pub const Type = enum {
|
||||
monsters,
|
||||
resources,
|
||||
crafts
|
||||
};
|
||||
pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
.{ "monsters" , Type.monsters },
|
||||
.{ "resources", Type.resources },
|
||||
.{ "crafts" , Type.crafts },
|
||||
});
|
||||
|
||||
id: ItemId, // TODO: Refactor `ItemId` to include other object types
|
||||
type: Type,
|
||||
total: u64,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Task {
|
||||
const task_type = try json_utils.getStringRequired(obj, "type");
|
||||
const total = try json_utils.getIntegerRequired(obj, "total");
|
||||
if (total < 0) {
|
||||
return error.InvalidTaskTotal;
|
||||
}
|
||||
|
||||
const code = json_utils.getStringRequired(obj, "code");
|
||||
const id = try api.getItemId(code);
|
||||
|
||||
return Task{
|
||||
.id = id,
|
||||
.type = TypeUtils.fromString(task_type) orelse return error.InvalidTaskType,
|
||||
.total = @intCast(total)
|
||||
};
|
||||
}
|
27
api/schemas/task_data.zig
Normal file
27
api/schemas/task_data.zig
Normal file
@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
const Task = @import("./task.zig");
|
||||
|
||||
const TaskData = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
task: Task,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !TaskData {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
const task = json_utils.getObject(obj, "task") orelse return error.MissingProperty;
|
||||
|
||||
return TaskData{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator),
|
||||
.task = try Task.parse(api, task)
|
||||
};
|
||||
}
|
726
api/server.zig
726
api/server.zig
@ -3,14 +3,9 @@ const assert = std.debug.assert;
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
// TODO: Maybe it would be good to move date time parsing to separate module
|
||||
pub const parseDateTime = @import("./date_time/parse.zig").parseDateTime;
|
||||
|
||||
const json_utils = @import("json_utils.zig");
|
||||
pub const Character = @import("character.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
pub const Character = @import("./schemas/character.zig");
|
||||
const EnumStringUtils = @import("./enum_string_utils.zig").EnumStringUtils;
|
||||
pub const Slot = @import("./slot.zig");
|
||||
pub const Position = @import("./position.zig");
|
||||
|
||||
const errors = @import("./errors.zig");
|
||||
@ -46,147 +41,28 @@ prefetched_items: bool = false,
|
||||
|
||||
// ------------------------- API result structs ------------------------
|
||||
|
||||
pub const EquipmentSlot = @import("./equipment.zig").Slot;
|
||||
|
||||
pub const Skill = enum {
|
||||
weaponcrafting,
|
||||
gearcrafting,
|
||||
jewelrycrafting,
|
||||
cooking,
|
||||
woodcutting,
|
||||
mining,
|
||||
};
|
||||
pub const SkillUtils = EnumStringUtils(Skill, .{
|
||||
.{ "weaponcrafting" , Skill.weaponcrafting },
|
||||
.{ "gearcrafting" , Skill.gearcrafting },
|
||||
.{ "jewelrycrafting", Skill.jewelrycrafting },
|
||||
.{ "cooking" , Skill.cooking },
|
||||
.{ "woodcutting" , Skill.woodcutting },
|
||||
.{ "mining" , Skill.mining },
|
||||
});
|
||||
|
||||
const ServerStatus = struct {
|
||||
allocator: Allocator,
|
||||
status: []const u8,
|
||||
version: []const u8,
|
||||
characters_online: i64,
|
||||
|
||||
pub fn parse(api: *Server, object: json.ObjectMap, allocator: Allocator) !ServerStatus {
|
||||
_ = api;
|
||||
|
||||
return ServerStatus{
|
||||
.allocator = allocator,
|
||||
.characters_online = json_utils.getInteger(object, "characters_online") orelse return error.MissingProperty,
|
||||
.status = (try json_utils.dupeString(allocator, object, "status")) orelse return error.MissingStatus,
|
||||
.version = (try json_utils.dupeString(allocator, object, "version")) orelse return error.MissingVersion
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: ServerStatus) void {
|
||||
self.allocator.free(self.status);
|
||||
self.allocator.free(self.version);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Cooldown = struct {
|
||||
pub const Reason = enum {
|
||||
movement,
|
||||
fight,
|
||||
crafting,
|
||||
gathering,
|
||||
buy_ge,
|
||||
sell_ge,
|
||||
delete_item,
|
||||
deposit_bank,
|
||||
withdraw_bank,
|
||||
equip,
|
||||
unequip,
|
||||
task,
|
||||
recycling,
|
||||
|
||||
fn parse(str: []const u8) ?Reason {
|
||||
const Mapping = std.ComptimeStringMap(Reason, .{
|
||||
.{ "movement" , .movement },
|
||||
.{ "fight" , .fight },
|
||||
.{ "crafting" , .crafting },
|
||||
.{ "gathering" , .gathering },
|
||||
.{ "buy_ge" , .buy_ge },
|
||||
.{ "sell_ge" , .sell_ge },
|
||||
.{ "delete_item" , .delete_item },
|
||||
.{ "deposit_bank" , .deposit_bank },
|
||||
.{ "withdraw_bank", .withdraw_bank },
|
||||
.{ "equip" , .equip },
|
||||
.{ "unequip" , .unequip },
|
||||
.{ "task" , .task },
|
||||
.{ "recycling" , .recycling },
|
||||
});
|
||||
|
||||
return Mapping.get(str);
|
||||
}
|
||||
};
|
||||
|
||||
expiration: f64,
|
||||
reason: Reason,
|
||||
|
||||
pub fn parse(obj: json.ObjectMap) !Cooldown {
|
||||
const reason = try json_utils.getStringRequired(obj, "reason");
|
||||
const expiration = try json_utils.getStringRequired(obj, "expiration");
|
||||
|
||||
return Cooldown{
|
||||
.expiration = parseDateTime(expiration) orelse return error.InvalidDateTime,
|
||||
.reason = Reason.parse(reason) orelse return error.UnknownReason
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const FightResult = struct {
|
||||
const Details = struct {
|
||||
const Result = enum { win, lose };
|
||||
const Drops = BoundedSlotsArray(8);
|
||||
|
||||
xp: i64,
|
||||
gold: i64,
|
||||
drops: Drops,
|
||||
result: Result,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap) !Details {
|
||||
const result = try json_utils.getStringRequired(obj, "result");
|
||||
var result_enum: Result = undefined;
|
||||
if (std.mem.eql(u8, result, "win")) {
|
||||
result_enum = .win;
|
||||
} else if (std.mem.eql(u8, result, "win")) {
|
||||
result_enum = .lose;
|
||||
} else {
|
||||
return error.InvalidProperty;
|
||||
}
|
||||
|
||||
const drops_obj = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
return Details{
|
||||
.xp = try json_utils.getIntegerRequired(obj, "xp"),
|
||||
.gold = try json_utils.getIntegerRequired(obj, "gold"),
|
||||
.drops = try Drops.parse(api, drops_obj),
|
||||
.result = result_enum,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
cooldown: Cooldown,
|
||||
fight: Details,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !FightResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const fight = json_utils.getObject(obj, "fight") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return FightResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.fight = try Details.parse(api, fight),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
pub const Slot = @import("./schemas/slot.zig");
|
||||
const BoundedSlotsArray = @import("./schemas/slot_array.zig").BoundedSlotsArray;
|
||||
pub const EquipmentSlot = @import("./schemas/equipment.zig").Slot;
|
||||
pub const ServerStatus = @import("./schemas/status.zig");
|
||||
pub const Cooldown = @import("./schemas/cooldown.zig");
|
||||
pub const FightResult = @import("./schemas/character_fight.zig");
|
||||
pub const Skill = @import("./schemas/skill.zig").Skill;
|
||||
pub const GatherResult = @import("./schemas/skill_data.zig");
|
||||
pub const MoveResult = @import("./schemas/character_movement.zig");
|
||||
pub const GoldTransactionResult = @import("./schemas/bank_gold_transaction.zig");
|
||||
pub const ItemTransactionResult = @import("./schemas/bank_item_transaction.zig");
|
||||
pub const CraftResult = @import("./schemas/skill_data.zig");
|
||||
pub const UnequipResult = @import("./schemas/equip_request.zig");
|
||||
pub const EquipResult = @import("./schemas/equip_request.zig");
|
||||
const DropRate = @import("./schemas/drop_rate.zig");
|
||||
pub const AcceptTaskResult = @import("./schemas/task_data.zig");
|
||||
pub const MapContent = @import("./schemas/map_content.zig");
|
||||
pub const MapTile = @import("./schemas/map.zig");
|
||||
pub const Item = @import("./schemas/item.zig");
|
||||
pub const ItemWithGE = @import("./schemas/single_item.zig");
|
||||
pub const Resource = @import("./schemas/resource.zig");
|
||||
pub const Monster = @import("./schemas/monster.zig");
|
||||
|
||||
// TODO: Replace this with ItemSlot struct
|
||||
pub const ItemIdQuantity = struct {
|
||||
@ -212,530 +88,6 @@ pub const ItemIdQuantity = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const SkillResultDetails = struct {
|
||||
const Items = BoundedSlotsArray(8);
|
||||
|
||||
xp: i64,
|
||||
items: Items,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap) !SkillResultDetails {
|
||||
const items = json_utils.getArray(obj, "items") orelse return error.MissingProperty;
|
||||
|
||||
return SkillResultDetails{
|
||||
.xp = try json_utils.getIntegerRequired(obj, "xp"),
|
||||
.items = try Items.parse(api, items),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const GatherResult = struct {
|
||||
cooldown: Cooldown,
|
||||
details: SkillResultDetails,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !GatherResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const details = json_utils.getObject(obj, "details") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return GatherResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.details = try SkillResultDetails.parse(api, details),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const MoveResult = struct {
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !MoveResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return MoveResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const GoldTransactionResult = struct {
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !GoldTransactionResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return GoldTransactionResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const ItemTransactionResult = struct {
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !ItemTransactionResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return ItemTransactionResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const CraftResult = struct {
|
||||
cooldown: Cooldown,
|
||||
details: SkillResultDetails,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !CraftResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const details = json_utils.getObject(obj, "details") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
|
||||
return CraftResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.details = try SkillResultDetails.parse(api, details),
|
||||
.character = try Character.parse(api, character, allocator)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const UnequipResult = struct {
|
||||
cooldown: Cooldown,
|
||||
item: ItemId,
|
||||
|
||||
pub fn parse(api: *Server, 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 const EquipResult = struct {
|
||||
cooldown: Cooldown,
|
||||
|
||||
pub fn parse(api: *Server, 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 const TaskType = enum {
|
||||
monsters,
|
||||
resources,
|
||||
crafts
|
||||
};
|
||||
pub const TaskTypeUtils = EnumStringUtils(TaskType, .{
|
||||
.{ "monsters" , TaskType.monsters },
|
||||
.{ "resources", TaskType.resources },
|
||||
.{ "crafts" , TaskType.crafts },
|
||||
});
|
||||
|
||||
pub const Task = struct {
|
||||
id: ItemId, // TODO: Refactor `ItemId` to include other object types
|
||||
type: TaskType,
|
||||
total: u64,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Task {
|
||||
const task_type = try json_utils.getStringRequired(obj, "type");
|
||||
const total = try json_utils.getIntegerRequired(obj, "total");
|
||||
if (total < 0) {
|
||||
return error.InvalidTaskTotal;
|
||||
}
|
||||
|
||||
const code = json_utils.getStringRequired(obj, "code");
|
||||
const id = try api.getItemId(code);
|
||||
|
||||
return Task{
|
||||
.id = id,
|
||||
.type = TaskTypeUtils.fromString(task_type) orelse return error.InvalidTaskType,
|
||||
.total = @intCast(total)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const AcceptTaskResult = struct {
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
task: Task,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !AcceptTaskResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
const task = json_utils.getObject(obj, "task") orelse return error.MissingProperty;
|
||||
|
||||
return EquipResult{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(api, character, allocator),
|
||||
.task = try Task.parse(api, task)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const MapContentType = enum {
|
||||
monster,
|
||||
resource,
|
||||
workshop,
|
||||
bank,
|
||||
grand_exchange,
|
||||
tasks_master,
|
||||
};
|
||||
pub const MapContentTypeUtils = EnumStringUtils(MapContentType, .{
|
||||
.{ "monster" , MapContentType.monster },
|
||||
.{ "resource" , MapContentType.resource },
|
||||
.{ "workshop" , MapContentType.workshop },
|
||||
.{ "bank" , MapContentType.bank },
|
||||
.{ "grand_exchange", MapContentType.grand_exchange },
|
||||
.{ "tasks_master" , MapContentType.tasks_master },
|
||||
});
|
||||
|
||||
pub const MapTile = struct {
|
||||
pub const MapContent = struct {
|
||||
type: MapContentType,
|
||||
code: []u8,
|
||||
};
|
||||
|
||||
name: []u8,
|
||||
skin: []u8,
|
||||
position: Position,
|
||||
content: ?MapContent,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !MapTile {
|
||||
_ = api;
|
||||
|
||||
var content: ?MapContent = null;
|
||||
if (json_utils.getObject(obj, "content")) |content_obj| {
|
||||
const content_type = json_utils.getString(content_obj, "type") orelse return error.MissingProperty;
|
||||
|
||||
content = MapContent{
|
||||
.type = MapContentTypeUtils.fromString(content_type) orelse return error.InvalidContentType,
|
||||
.code = (try json_utils.dupeString(allocator, content_obj, "code")) orelse return error.MissingProperty,
|
||||
};
|
||||
}
|
||||
|
||||
const x = json_utils.getInteger(obj, "x") orelse return error.MissingProperty;
|
||||
const y = json_utils.getInteger(obj, "y") orelse return error.MissingProperty;
|
||||
|
||||
return MapTile{
|
||||
.name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty,
|
||||
.skin = (try json_utils.dupeString(allocator, obj, "skin")) orelse return error.MissingProperty,
|
||||
.position = Position.init(x, y),
|
||||
.content = content
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: MapTile, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.skin);
|
||||
if (self.content) |content| {
|
||||
allocator.free(content.code);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ItemType = enum {
|
||||
consumable,
|
||||
body_armor,
|
||||
weapon,
|
||||
resource,
|
||||
leg_armor,
|
||||
helmet,
|
||||
boots,
|
||||
shield,
|
||||
amulet,
|
||||
ring,
|
||||
artifact,
|
||||
currency,
|
||||
};
|
||||
const ItemTypeUtils = EnumStringUtils(ItemType, .{
|
||||
.{ "consumable", .consumable },
|
||||
.{ "body_armor", .body_armor },
|
||||
.{ "weapon" , .weapon },
|
||||
.{ "resource" , .resource },
|
||||
.{ "leg_armor" , .leg_armor },
|
||||
.{ "helmet" , .helmet },
|
||||
.{ "boots" , .boots },
|
||||
.{ "shield" , .shield },
|
||||
.{ "amulet" , .amulet },
|
||||
.{ "ring" , .ring },
|
||||
.{ "artifact" , .artifact },
|
||||
.{ "currency" , .currency },
|
||||
});
|
||||
|
||||
pub const Item = struct {
|
||||
pub const Recipe = struct {
|
||||
const Items = BoundedSlotsArray(8);
|
||||
|
||||
skill: Skill,
|
||||
level: u64,
|
||||
quantity: u64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Recipe {
|
||||
const skill = json_utils.getString(obj, "skill") orelse return error.MissingProperty;
|
||||
const level = json_utils.getInteger(obj, "level") orelse return error.MissingProperty;
|
||||
if (level < 1) return error.InvalidLevel;
|
||||
|
||||
const quantity = json_utils.getInteger(obj, "quantity") orelse return error.MissingProperty;
|
||||
if (quantity < 1) return error.InvalidQuantity;
|
||||
|
||||
const items = json_utils.getArray(obj, "items") orelse return error.MissingProperty;
|
||||
|
||||
return Recipe{
|
||||
.skill = SkillUtils.fromString(skill) orelse return error.InvalidSkill,
|
||||
.level = @intCast(level),
|
||||
.quantity = @intCast(quantity),
|
||||
.items = try Items.parse(api, items)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
allocator: Allocator,
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
level: u64,
|
||||
type: ItemType,
|
||||
subtype: []u8,
|
||||
description: []u8,
|
||||
craft: ?Recipe,
|
||||
// TODO: effects
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Item {
|
||||
const level = json_utils.getInteger(obj, "level") orelse return error.MissingProperty;
|
||||
if (level < 1) return error.InvalidLevel;
|
||||
|
||||
const craft = json_utils.getObject(obj, "craft");
|
||||
const item_type_str = try json_utils.getStringRequired(obj, "type");
|
||||
|
||||
return Item{
|
||||
.allocator = allocator,
|
||||
.name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty,
|
||||
.code = (try json_utils.dupeString(allocator, obj, "code")) orelse return error.MissingProperty,
|
||||
.level = @intCast(level),
|
||||
.type = ItemTypeUtils.fromString(item_type_str) orelse return error.InvalidType,
|
||||
.subtype = (try json_utils.dupeString(allocator, obj, "subtype")) orelse return error.MissingProperty,
|
||||
.description = (try json_utils.dupeString(allocator, obj, "description")) orelse return error.MissingProperty,
|
||||
.craft = if (craft != null) try Recipe.parse(api, craft.?) else null
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Item) void {
|
||||
self.allocator.free(self.name);
|
||||
self.allocator.free(self.code);
|
||||
self.allocator.free(self.subtype);
|
||||
self.allocator.free(self.description);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ItemWithGE = struct {
|
||||
item: Item,
|
||||
// TODO: Grand exchange
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !ItemWithGE {
|
||||
const item_obj = json_utils.getObject(obj, "item") orelse return error.MissingProperty;
|
||||
const ge_obj = json_utils.getObject(obj, "ge") orelse return error.MissingProperty;
|
||||
_ = ge_obj;
|
||||
|
||||
return ItemWithGE{
|
||||
.item = try Item.parse(api, item_obj, allocator),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const ResourceSkill = enum {
|
||||
mining,
|
||||
woodcutting,
|
||||
fishing,
|
||||
};
|
||||
const ResourceSkillUtils = EnumStringUtils(ResourceSkill, .{
|
||||
.{ "mining" , .mining },
|
||||
.{ "woodcutting", .woodcutting },
|
||||
.{ "fishing" , .fishing },
|
||||
});
|
||||
|
||||
const DropRates = std.BoundedArray(DropRate, 8);
|
||||
const DropRate = struct {
|
||||
item_id: ItemId,
|
||||
rate: u64,
|
||||
min_quantity: u64,
|
||||
max_quantity: u64,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap) !DropRate {
|
||||
const rate = try json_utils.getIntegerRequired(obj, "rate");
|
||||
if (rate < 1) {
|
||||
return error.InvalidRate;
|
||||
}
|
||||
|
||||
const min_quantity = try json_utils.getIntegerRequired(obj, "min_quantity");
|
||||
if (min_quantity < 1) {
|
||||
return error.InvalidMinQuantity;
|
||||
}
|
||||
|
||||
const max_quantity = try json_utils.getIntegerRequired(obj, "max_quantity");
|
||||
if (max_quantity < 1) {
|
||||
return error.InvalidMinQuantity;
|
||||
}
|
||||
|
||||
const code_str = try json_utils.getStringRequired(obj, "code");
|
||||
const item_id = try api.getItemId(code_str);
|
||||
|
||||
return DropRate{
|
||||
.item_id = item_id,
|
||||
.rate = @intCast(rate),
|
||||
.min_quantity = @intCast(min_quantity),
|
||||
.max_quantity = @intCast(max_quantity)
|
||||
};
|
||||
}
|
||||
|
||||
fn parseList(api: *Server, array: json.Array) !DropRates {
|
||||
var drops = DropRates.init(0) catch unreachable;
|
||||
for (array.items) |drop_value| {
|
||||
const drop_obj = json_utils.asObject(drop_value) orelse return error.InvalidObject;
|
||||
try drops.append(try DropRate.parse(api, drop_obj));
|
||||
}
|
||||
return drops;
|
||||
}
|
||||
|
||||
fn doesListContain(drops: *DropRates, item_id: ItemId) bool {
|
||||
for (drops.constSlice()) |drop| {
|
||||
if (drop.item_id == item_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Resource = struct {
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
skill: ResourceSkill,
|
||||
level: u64,
|
||||
drops: DropRates,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Resource {
|
||||
const drops_array = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
const level = try json_utils.getIntegerRequired(obj, "level");
|
||||
if (level < 0) {
|
||||
return error.InvalidLevel;
|
||||
}
|
||||
|
||||
const skill_str = try json_utils.getStringRequired(obj, "skill");
|
||||
|
||||
return Resource{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.level = @intCast(level),
|
||||
.skill = ResourceSkillUtils.fromString(skill_str) orelse return error.InvalidSkill,
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: Resource, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Monster = struct {
|
||||
const ElementalStats = struct {
|
||||
attack: i64,
|
||||
resistance: i64,
|
||||
|
||||
pub fn parse(object: json.ObjectMap, attack: []const u8, resistance: []const u8) !ElementalStats {
|
||||
return ElementalStats{
|
||||
.attack = try json_utils.getIntegerRequired(object, attack),
|
||||
.resistance = try json_utils.getIntegerRequired(object, resistance),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
level: u64,
|
||||
hp: u64,
|
||||
min_gold: u64,
|
||||
max_gold: u64,
|
||||
|
||||
fire: ElementalStats,
|
||||
earth: ElementalStats,
|
||||
water: ElementalStats,
|
||||
air: ElementalStats,
|
||||
|
||||
drops: DropRates,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Monster {
|
||||
const drops_array = json_utils.getArray(obj, "drops") orelse return error.MissingProperty;
|
||||
|
||||
const min_gold = try json_utils.getIntegerRequired(obj, "min_gold");
|
||||
if (min_gold < 0) {
|
||||
return error.InvalidMinGold;
|
||||
}
|
||||
|
||||
const max_gold = try json_utils.getIntegerRequired(obj, "max_gold");
|
||||
if (max_gold < 0) {
|
||||
return error.InvalidMaxGold;
|
||||
}
|
||||
|
||||
const level = try json_utils.getIntegerRequired(obj, "level");
|
||||
if (level < 0) {
|
||||
return error.InvalidLevel;
|
||||
}
|
||||
|
||||
const hp = try json_utils.getIntegerRequired(obj, "hp");
|
||||
if (hp < 0) {
|
||||
return error.InvalidHp;
|
||||
}
|
||||
|
||||
return Monster{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.level = @intCast(level),
|
||||
.hp = @intCast(hp),
|
||||
|
||||
.fire = try ElementalStats.parse(obj, "attack_fire" , "res_fire" ),
|
||||
.earth = try ElementalStats.parse(obj, "attack_earth", "res_earth"),
|
||||
.water = try ElementalStats.parse(obj, "attack_water", "res_water"),
|
||||
.air = try ElementalStats.parse(obj, "attack_air" , "res_air" ),
|
||||
|
||||
.min_gold = @intCast(min_gold),
|
||||
.max_gold = @intCast(max_gold),
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: Monster, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ArtifactsFetchResult = struct {
|
||||
arena: std.heap.ArenaAllocator,
|
||||
status: std.http.Status,
|
||||
@ -746,16 +98,6 @@ pub const ArtifactsFetchResult = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn appendQueryParam(query: *std.ArrayList(u8), key: []const u8, value: []const u8) !void {
|
||||
if (query.items.len > 0) {
|
||||
try query.appendSlice("&");
|
||||
}
|
||||
|
||||
try query.appendSlice(key);
|
||||
try query.appendSlice("=");
|
||||
try query.appendSlice(value);
|
||||
}
|
||||
|
||||
// ------------------------- General API methods ------------------------
|
||||
|
||||
pub fn init(allocator: Allocator) !Server {
|
||||
@ -829,6 +171,16 @@ const FetchOptions = struct {
|
||||
paginated: bool = false
|
||||
};
|
||||
|
||||
fn appendQueryParam(query: *std.ArrayList(u8), key: []const u8, value: []const u8) !void {
|
||||
if (query.items.len > 0) {
|
||||
try query.appendSlice("&");
|
||||
}
|
||||
|
||||
try query.appendSlice(key);
|
||||
try query.appendSlice("=");
|
||||
try query.appendSlice(value);
|
||||
}
|
||||
|
||||
fn allocPaginationParams(allocator: Allocator, page: u64, page_size: ?u64) ![]u8 {
|
||||
if (page_size) |size| {
|
||||
return try std.fmt.allocPrint(allocator, "page={}&size={}", .{page, size});
|
||||
@ -1609,7 +961,7 @@ pub fn getMap(self: *Server, x: i64, y: i64) FetchError!?MapTile {
|
||||
|
||||
pub const MapOptions = struct {
|
||||
code: ?[]const u8 = null,
|
||||
type: ?MapContentType = null,
|
||||
type: ?MapContent.Type = null,
|
||||
};
|
||||
|
||||
pub fn getMaps(self: *Server, opts: MapOptions) FetchError!std.ArrayList(MapTile) {
|
||||
@ -1638,7 +990,7 @@ pub fn getMaps(self: *Server, opts: MapOptions) FetchError!std.ArrayList(MapTile
|
||||
try appendQueryParam(&query, "content_code", code);
|
||||
}
|
||||
if (opts.type) |map_type| {
|
||||
try appendQueryParam(&query, "content_type", MapContentTypeUtils.toString(map_type));
|
||||
try appendQueryParam(&query, "content_type", MapContent.TypeUtils.toString(map_type));
|
||||
}
|
||||
|
||||
const result = try self.fetchArray(
|
||||
@ -1697,7 +1049,7 @@ pub const ItemOptions = struct {
|
||||
min_level: ?u64 = null,
|
||||
max_level: ?u64 = null,
|
||||
name: ?[]const u8 = null,
|
||||
type: ?ItemType = null,
|
||||
type: ?Item.Type = null,
|
||||
};
|
||||
|
||||
pub fn getItems(self: *Server, opts: ItemOptions) FetchError!std.ArrayList(Item) {
|
||||
@ -1756,7 +1108,7 @@ pub fn getItems(self: *Server, opts: ItemOptions) FetchError!std.ArrayList(Item)
|
||||
try appendQueryParam(&query, "name", name);
|
||||
}
|
||||
if (opts.type) |item_type| {
|
||||
try appendQueryParam(&query, "type", ItemTypeUtils.toString(item_type));
|
||||
try appendQueryParam(&query, "type", Item.TypeUtils.toString(item_type));
|
||||
}
|
||||
|
||||
const result = try self.fetchArray(
|
||||
@ -1807,7 +1159,7 @@ pub const ResourceOptions = struct {
|
||||
drop: ?[]const u8 = null,
|
||||
max_level: ?u64 = null,
|
||||
min_level: ?u64 = null,
|
||||
skill: ?ResourceSkill = null,
|
||||
skill: ?Resource.Skill = null,
|
||||
};
|
||||
|
||||
pub fn getResources(self: *Server, opts: ResourceOptions) FetchError!std.ArrayList(Resource) {
|
||||
@ -1851,7 +1203,7 @@ pub fn getResources(self: *Server, opts: ResourceOptions) FetchError!std.ArrayLi
|
||||
try appendQueryParam(&query, "max_level", max_level_str);
|
||||
}
|
||||
if (opts.skill) |skill| {
|
||||
try appendQueryParam(&query, "skill", ResourceSkillUtils.toString(skill));
|
||||
try appendQueryParam(&query, "skill", Resource.SkillUtils.toString(skill));
|
||||
}
|
||||
|
||||
const result = try self.fetchArray(
|
||||
|
Loading…
Reference in New Issue
Block a user