move schemas to different iles

This commit is contained in:
Rokas Puzonas 2024-09-07 22:47:54 +03:00
parent dad53513c7
commit fdbf005126
30 changed files with 848 additions and 700 deletions

View File

@ -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");

View File

@ -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;

View 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)
};
}

View 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)
};
}

View File

@ -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;

View 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)
};
}

View 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)
};
}

View File

@ -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
View 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
View 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
View 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;
}

View 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
};
}

View File

@ -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
View 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
View 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
View 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);
}
}

View 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
View 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
View 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);
}

View 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
View 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 },
});

View 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)
};
}

View 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),
};
}

View File

@ -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();

View File

@ -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;

View File

@ -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
View 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
View 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
View 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)
};
}

View File

@ -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(