add api store for static data
This commit is contained in:
parent
fdbf005126
commit
cc289194a8
@ -2,12 +2,14 @@
|
||||
pub const parseDateTime = @import("./date_time/parse.zig").parseDateTime;
|
||||
|
||||
pub const Server = @import("server.zig");
|
||||
pub const Store = @import("store.zig");
|
||||
pub const Character = @import("./schemas/character.zig");
|
||||
pub const Position = @import("position.zig");
|
||||
pub const BoundedSlotsArray = @import("schemas/slot_array.zig").BoundedSlotsArray;
|
||||
|
||||
pub const Slot = Server.Slot;
|
||||
pub const ItemId = Server.ItemId;
|
||||
pub const ItemIdQuantity = Server.ItemIdQuantity;
|
||||
pub const CodeId = Store.CodeId;
|
||||
pub const ItemQuantity = @import("./schemas/item_quantity.zig");
|
||||
|
||||
const errors = @import("errors.zig");
|
||||
pub const FetchError = errors.FetchError;
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -12,12 +12,12 @@ const BankGoldTransaction = @This();
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !BankGoldTransaction {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.character = try Character.parse(store, character, allocator)
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -12,12 +12,12 @@ const BankItemTransaction = @This();
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !BankItemTransaction {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.character = try Character.parse(store, character, allocator)
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.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;
|
||||
const assert = std.debug.assert;
|
||||
@ -56,7 +55,7 @@ inventory: Inventory,
|
||||
|
||||
task: ?TaskMasterTask,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Character {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !Character {
|
||||
const inventory = json_utils.getArray(obj, "inventory") orelse return error.MissingProperty;
|
||||
const cooldown_expiration = json_utils.getString(obj, "cooldown_expiration") orelse return error.MissingProperty;
|
||||
|
||||
@ -119,10 +118,10 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Character
|
||||
.earth = try CombatStats.parse(obj, "attack_earth", "dmg_earth", "res_earth"),
|
||||
.air = try CombatStats.parse(obj, "attack_air", "dmg_air", "res_air"),
|
||||
|
||||
.equipment = try Equipment.parse(api, obj),
|
||||
.equipment = try Equipment.parse(store, obj),
|
||||
|
||||
.inventory_max_items = @intCast(inventory_max_items),
|
||||
.inventory = try Inventory.parse(api, inventory),
|
||||
.inventory = try Inventory.parse(store, inventory),
|
||||
|
||||
.task = task
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -14,14 +14,14 @@ cooldown: Cooldown,
|
||||
fight: Fight,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !CharacterFight {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.fight = try Fight.parse(store, fight),
|
||||
.character = try Character.parse(store, character, allocator)
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -12,12 +12,12 @@ const CharacterMovement = @This();
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !CharacterMovement {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.character = try Character.parse(store, character, allocator)
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json = std.json;
|
||||
@ -16,7 +16,7 @@ level: u64,
|
||||
quantity: u64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Craft {
|
||||
pub fn parse(store: *Store, 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;
|
||||
@ -30,6 +30,6 @@ pub fn parse(api: *Server, obj: json.ObjectMap) !Craft {
|
||||
.skill = SkillUtils.fromString(skill) orelse return error.InvalidSkill,
|
||||
.level = @intCast(level),
|
||||
.quantity = @intCast(quantity),
|
||||
.items = try Items.parse(api, items)
|
||||
.items = try Items.parse(store, items)
|
||||
};
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const json = std.json;
|
||||
|
||||
const DropRate = @This();
|
||||
|
||||
item_id: ItemId,
|
||||
item_id: Store.CodeId,
|
||||
rate: u64,
|
||||
min_quantity: u64,
|
||||
max_quantity: u64,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !DropRate {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) !DropRate {
|
||||
const rate = try json_utils.getIntegerRequired(obj, "rate");
|
||||
if (rate < 1) {
|
||||
return error.InvalidRate;
|
||||
@ -28,7 +27,7 @@ pub fn parse(api: *Server, obj: json.ObjectMap) !DropRate {
|
||||
}
|
||||
|
||||
const code_str = try json_utils.getStringRequired(obj, "code");
|
||||
const item_id = try api.getItemId(code_str);
|
||||
const item_id = try store.getItemId(code_str);
|
||||
|
||||
return DropRate{
|
||||
.item_id = item_id,
|
||||
@ -40,16 +39,16 @@ pub fn parse(api: *Server, obj: json.ObjectMap) !DropRate {
|
||||
|
||||
pub const DropRates = std.BoundedArray(DropRate, 8); // TODO: Maybe rename to "List"?
|
||||
|
||||
pub fn parseList(api: *Server, array: json.Array) !DropRates {
|
||||
pub fn parseList(store: *Store, 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));
|
||||
try drops.append(try DropRate.parse(store, drop_obj));
|
||||
}
|
||||
return drops;
|
||||
}
|
||||
|
||||
pub fn doesListContain(drops: *DropRates, item_id: ItemId) bool {
|
||||
pub fn doesListContain(drops: *DropRates, item_id: Store.CodeId) bool {
|
||||
for (drops.constSlice()) |drop| {
|
||||
if (drop.item_id == item_id) {
|
||||
return true;
|
||||
|
@ -1,8 +1,8 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const ItemId = Server.ItemId;
|
||||
const ItemId = Store.ItemId;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
|
||||
@ -11,13 +11,13 @@ const EquipRequest = @This();
|
||||
cooldown: Cooldown,
|
||||
item: ItemId,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !EquipRequest {
|
||||
pub fn parse(store: *Store, 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);
|
||||
const item_id = try store.getItemId(item_code);
|
||||
|
||||
// TODO: Might as well save information about time, because full details about it are given
|
||||
|
||||
|
@ -1,18 +1,19 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const Store = @import("../store.zig");
|
||||
const json = std.json;
|
||||
|
||||
const Equipment = @This();
|
||||
|
||||
const CodeId = Store.CodeId;
|
||||
|
||||
pub const Consumable = struct {
|
||||
id: ?ItemId,
|
||||
code_id: ?CodeId,
|
||||
quantity: i64,
|
||||
|
||||
fn parse(api: *Server, obj: json.ObjectMap, name: []const u8, quantity: []const u8) !Consumable {
|
||||
fn parse(store: *Store, obj: json.ObjectMap, name: []const u8, quantity: []const u8) !Consumable {
|
||||
return Consumable{
|
||||
.id = try api.getItemIdJson(obj, name),
|
||||
.code_id = try store.getCodeIdJson(obj, name),
|
||||
.quantity = try json_utils.getIntegerRequired(obj, quantity),
|
||||
};
|
||||
}
|
||||
@ -52,39 +53,39 @@ pub const Slot = enum {
|
||||
}
|
||||
};
|
||||
|
||||
weapon: ?ItemId,
|
||||
shield: ?ItemId,
|
||||
helmet: ?ItemId,
|
||||
body_armor: ?ItemId,
|
||||
leg_armor: ?ItemId,
|
||||
boots: ?ItemId,
|
||||
weapon: ?CodeId,
|
||||
shield: ?CodeId,
|
||||
helmet: ?CodeId,
|
||||
body_armor: ?CodeId,
|
||||
leg_armor: ?CodeId,
|
||||
boots: ?CodeId,
|
||||
|
||||
ring1: ?ItemId,
|
||||
ring2: ?ItemId,
|
||||
amulet: ?ItemId,
|
||||
ring1: ?CodeId,
|
||||
ring2: ?CodeId,
|
||||
amulet: ?CodeId,
|
||||
|
||||
artifact1: ?ItemId,
|
||||
artifact2: ?ItemId,
|
||||
artifact3: ?ItemId,
|
||||
artifact1: ?CodeId,
|
||||
artifact2: ?CodeId,
|
||||
artifact3: ?CodeId,
|
||||
|
||||
consumable1: Consumable,
|
||||
consumable2: Consumable,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Equipment {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) !Equipment {
|
||||
return Equipment{
|
||||
.weapon = try api.getItemIdJson(obj, "weapon_slot"),
|
||||
.shield = try api.getItemIdJson(obj, "shield_slot"),
|
||||
.helmet = try api.getItemIdJson(obj, "helmet_slot"),
|
||||
.body_armor = try api.getItemIdJson(obj, "body_armor_slot"),
|
||||
.leg_armor = try api.getItemIdJson(obj, "leg_armor_slot"),
|
||||
.boots = try api.getItemIdJson(obj, "boots_slot"),
|
||||
.ring1 = try api.getItemIdJson(obj, "ring1_slot"),
|
||||
.ring2 = try api.getItemIdJson(obj, "ring2_slot"),
|
||||
.amulet = try api.getItemIdJson(obj, "amulet_slot"),
|
||||
.artifact1 = try api.getItemIdJson(obj, "artifact1_slot"),
|
||||
.artifact2 = try api.getItemIdJson(obj, "artifact2_slot"),
|
||||
.artifact3 = try api.getItemIdJson(obj, "artifact3_slot"),
|
||||
.consumable1 = try Consumable.parse(api, obj, "consumable1_slot", "consumable1_slot_quantity"),
|
||||
.consumable2 = try Consumable.parse(api, obj, "consumable2_slot", "consumable2_slot_quantity"),
|
||||
.weapon = try store.getCodeIdJson(obj, "weapon_slot"),
|
||||
.shield = try store.getCodeIdJson(obj, "shield_slot"),
|
||||
.helmet = try store.getCodeIdJson(obj, "helmet_slot"),
|
||||
.body_armor = try store.getCodeIdJson(obj, "body_armor_slot"),
|
||||
.leg_armor = try store.getCodeIdJson(obj, "leg_armor_slot"),
|
||||
.boots = try store.getCodeIdJson(obj, "boots_slot"),
|
||||
.ring1 = try store.getCodeIdJson(obj, "ring1_slot"),
|
||||
.ring2 = try store.getCodeIdJson(obj, "ring2_slot"),
|
||||
.amulet = try store.getCodeIdJson(obj, "amulet_slot"),
|
||||
.artifact1 = try store.getCodeIdJson(obj, "artifact1_slot"),
|
||||
.artifact2 = try store.getCodeIdJson(obj, "artifact2_slot"),
|
||||
.artifact3 = try store.getCodeIdJson(obj, "artifact3_slot"),
|
||||
.consumable1 = try Consumable.parse(store, obj, "consumable1_slot", "consumable1_slot_quantity"),
|
||||
.consumable2 = try Consumable.parse(store, obj, "consumable2_slot", "consumable2_slot_quantity"),
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
@ -13,7 +13,7 @@ gold: u64,
|
||||
drops: Drops,
|
||||
won: bool,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Fight {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) !Fight {
|
||||
const result = try json_utils.getStringRequired(obj, "result");
|
||||
|
||||
var won = false;
|
||||
@ -40,7 +40,7 @@ pub fn parse(api: *Server, obj: json.ObjectMap) !Fight {
|
||||
return Fight{
|
||||
.xp = @intCast(xp),
|
||||
.gold = @intCast(gold),
|
||||
.drops = try Drops.parse(api, drops_obj),
|
||||
.drops = try Drops.parse(store, drops_obj),
|
||||
.won = won,
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -48,7 +48,7 @@ description: []u8,
|
||||
craft: ?Craft,
|
||||
// TODO: effects
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Item {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !Item {
|
||||
const level = json_utils.getInteger(obj, "level") orelse return error.MissingProperty;
|
||||
if (level < 1) return error.InvalidLevel;
|
||||
|
||||
@ -63,7 +63,7 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Item {
|
||||
.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
|
||||
.craft = if (craft != null) try Craft.parse(store, craft.?) else null
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,29 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const Store = @import("../store.zig");
|
||||
const json = std.json;
|
||||
|
||||
const ItemSlot = @This();
|
||||
const ItemQuantity = @This();
|
||||
|
||||
id: ItemId,
|
||||
id: Store.CodeId,
|
||||
quantity: u64,
|
||||
|
||||
pub fn parse(api: *Server, slot_obj: json.ObjectMap) !?ItemSlot {
|
||||
pub fn init(id: Store.CodeId, quantity: u64) ItemQuantity {
|
||||
return ItemQuantity{
|
||||
.id = id,
|
||||
.quantity = quantity
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(store: *Store, slot_obj: json.ObjectMap) !?ItemQuantity {
|
||||
const code = try json_utils.getStringRequired(slot_obj, "code");
|
||||
if (code.len == 0) return null;
|
||||
|
||||
const quantity = try json_utils.getIntegerRequired(slot_obj, "quantity");
|
||||
if (quantity < 0) return error.InvalidQuantity;
|
||||
|
||||
return ItemSlot{
|
||||
.id = try api.getItemId(code),
|
||||
return ItemQuantity{
|
||||
.id = try store.getCodeId(code),
|
||||
.quantity = @intCast(quantity),
|
||||
};
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const Position = @import("../position.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
@ -14,7 +14,7 @@ skin: []u8,
|
||||
position: Position,
|
||||
content: ?MapContent,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Map {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !Map {
|
||||
const content = json_utils.getObject(obj, "content");
|
||||
|
||||
const x = json_utils.getInteger(obj, "x") orelse return error.MissingProperty;
|
||||
@ -24,14 +24,11 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !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)
|
||||
.content = try MapContent.parse(store, content)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Map, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.skin);
|
||||
if (self.content) |content| {
|
||||
content.deinit(allocator);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -25,19 +25,13 @@ pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
});
|
||||
|
||||
type: Type,
|
||||
code: []u8,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) MapContent {
|
||||
_ = api;
|
||||
code_id: Store.CodeId,
|
||||
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) MapContent {
|
||||
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,
|
||||
.code = (try store.getCodeIdJson(obj, "code")) orelse return error.MissingProperty
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: MapContent, allocator: Allocator) void {
|
||||
allocator.free(self.code);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -22,7 +22,7 @@ pub const ElementalStats = struct {
|
||||
};
|
||||
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
code_id: Store.CodeId,
|
||||
level: u64,
|
||||
hp: u64,
|
||||
min_gold: u64,
|
||||
@ -35,7 +35,7 @@ air: ElementalStats,
|
||||
|
||||
drops: DropRates,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Monster {
|
||||
pub fn parse(store: *Store, 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");
|
||||
@ -60,7 +60,7 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Monster {
|
||||
|
||||
return Monster{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.code = (try store.getCodeIdJson(allocator, obj, "code")) orelse return error.MissingProperty,
|
||||
.level = @intCast(level),
|
||||
.hp = @intCast(hp),
|
||||
|
||||
@ -71,11 +71,10 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Monster {
|
||||
|
||||
.min_gold = @intCast(min_gold),
|
||||
.max_gold = @intCast(max_gold),
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
.drops = try DropRate.parseList(store, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Monster, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
@ -22,12 +22,12 @@ pub const SkillUtils = EnumStringUtils(Skill, .{
|
||||
});
|
||||
|
||||
name: []u8,
|
||||
code: []u8,
|
||||
code_id: Store.CodeId,
|
||||
skill: Skill,
|
||||
level: u64,
|
||||
drops: DropRates,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Resource {
|
||||
pub fn parse(store: *Store, 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");
|
||||
@ -39,14 +39,13 @@ pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Resource
|
||||
|
||||
return Resource{
|
||||
.name = try json_utils.dupeStringRequired(allocator, obj, "name"),
|
||||
.code = try json_utils.dupeStringRequired(allocator, obj, "code"),
|
||||
.code = (try store.getCodeIdJson(allocator, obj, "code")) orelse return error.MissingProperty,
|
||||
.level = @intCast(level),
|
||||
.skill = SkillUtils.fromString(skill_str) orelse return error.InvalidSkill,
|
||||
.drops = try DropRate.parseList(api, drops_array)
|
||||
.drops = try DropRate.parseList(store, drops_array)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Resource, allocator: Allocator) void {
|
||||
allocator.free(self.name);
|
||||
allocator.free(self.code);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -11,12 +11,12 @@ const SingleItem = @This();
|
||||
item: Item,
|
||||
// TODO: Grand exchange
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !SingleItem {
|
||||
pub fn parse(store: *Store, 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),
|
||||
.item = try Item.parse(store, item_obj, allocator),
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -14,14 +14,14 @@ cooldown: Cooldown,
|
||||
details: SkillInfo,
|
||||
character: Character,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !SkillData {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.details = try SkillInfo.parse(store, details),
|
||||
.character = try Character.parse(store, character, allocator)
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
@ -11,11 +11,11 @@ const SkillInfo = @This();
|
||||
xp: i64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !SkillInfo {
|
||||
pub fn parse(store: *Store, 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),
|
||||
.items = try Items.parse(store, items),
|
||||
};
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Server = @import("../server.zig");
|
||||
const ItemId = Server.ItemId;
|
||||
const Store = @import("../store.zig");
|
||||
const assert = std.debug.assert;
|
||||
const json = std.json;
|
||||
|
||||
const Slot = @import("./slot.zig");
|
||||
const ItemQuantity = @import("./item_quantity.zig");
|
||||
|
||||
pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
const Slots = std.BoundedArray(Slot, slot_count);
|
||||
const Slots = std.BoundedArray(ItemQuantity, slot_count);
|
||||
const CodeId = Store.CodeId;
|
||||
|
||||
return struct {
|
||||
slots: Slots,
|
||||
@ -19,13 +19,13 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(api: *Server, slots_array: json.Array) !@This() {
|
||||
pub fn parse(api: *Store, slots_array: json.Array) !@This() {
|
||||
var slots = Slots.init(0) catch unreachable;
|
||||
|
||||
for (slots_array.items) |slot_value| {
|
||||
const slot_obj = json_utils.asObject(slot_value) orelse return error.InvalidType;
|
||||
|
||||
if (try Slot.parse(api, slot_obj)) |slot| {
|
||||
if (try ItemQuantity.parse(api, slot_obj)) |slot| {
|
||||
try slots.append(slot);
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,7 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
return @This(){ .slots = slots };
|
||||
}
|
||||
|
||||
fn findSlotIndex(self: *const @This(), id: ItemId) ?usize {
|
||||
fn findSlotIndex(self: *const @This(), id: CodeId) ?usize {
|
||||
for (0.., self.slots.slice()) |i, *slot| {
|
||||
if (slot.id == id) {
|
||||
return i;
|
||||
@ -43,7 +43,7 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn findSlot(self: *@This(), id: ItemId) ?*Slot {
|
||||
fn findSlot(self: *@This(), id: CodeId) ?*ItemQuantity {
|
||||
if (self.findSlotIndex(id)) |index| {
|
||||
return &self.slots.buffer[index];
|
||||
}
|
||||
@ -51,7 +51,7 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn remove(self: *@This(), id: ItemId, quantity: u64) void {
|
||||
pub fn remove(self: *@This(), id: CodeId, quantity: u64) void {
|
||||
const slot_index = self.findSlotIndex(id) orelse unreachable;
|
||||
const slot = self.slots.get(slot_index);
|
||||
assert(slot.quantity >= quantity);
|
||||
@ -62,29 +62,29 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(self: *@This(), id: ItemId, quantity: u64) !void {
|
||||
pub fn add(self: *@This(), id: CodeId, quantity: u64) !void {
|
||||
if (quantity == 0) return;
|
||||
|
||||
if (self.findSlot(id)) |slot| {
|
||||
slot.quantity += quantity;
|
||||
} else {
|
||||
try self.slots.append(Slot{ .id = id, .quantity = quantity });
|
||||
try self.slots.append(ItemQuantity.init(id, quantity));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addSlice(self: *@This(), items: []const Server.ItemIdQuantity) void {
|
||||
pub fn addSlice(self: *@This(), items: []const ItemQuantity) void {
|
||||
for (items) |item| {
|
||||
self.add(item.id, item.quantity);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn removeSlice(self: *@This(), items: []const Server.ItemIdQuantity) void {
|
||||
pub fn removeSlice(self: *@This(), items: []const ItemQuantity) void {
|
||||
for (items) |item| {
|
||||
self.remove(item.id, item.quantity);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getQuantity(self: *const @This(), id: ItemId) u64 {
|
||||
pub fn getQuantity(self: *const @This(), id: CodeId) u64 {
|
||||
if (self.findSlotIndex(id)) |index| {
|
||||
return self.slots.get(index).quantity;
|
||||
}
|
||||
@ -100,7 +100,7 @@ pub fn BoundedSlotsArray(comptime slot_count: u32) type {
|
||||
return count;
|
||||
}
|
||||
|
||||
pub fn slice(self: *@This()) []Slot {
|
||||
pub fn slice(self: *@This()) []ItemQuantity {
|
||||
return self.slots.slice();
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -11,8 +11,8 @@ status: []const u8,
|
||||
version: []const u8,
|
||||
characters_online: u64,
|
||||
|
||||
pub fn parse(api: *Server, object: json.ObjectMap, allocator: Allocator) !ServerStatus {
|
||||
_ = api;
|
||||
pub fn parse(store: *Store, object: json.ObjectMap, allocator: Allocator) !ServerStatus {
|
||||
_ = store;
|
||||
const characters_online = json_utils.getInteger(object, "characters_online") orelse return error.MissingProperty;
|
||||
if (characters_online < 0) {
|
||||
return error.InvalidCharactersOnline;
|
||||
|
@ -1,9 +1,8 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.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();
|
||||
|
||||
@ -18,22 +17,19 @@ pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
.{ "crafts" , Type.crafts },
|
||||
});
|
||||
|
||||
id: ItemId, // TODO: Refactor `ItemId` to include other object types
|
||||
code_id: Store.CodeId,
|
||||
type: Type,
|
||||
total: u64,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !Task {
|
||||
pub fn parse(store: *Store, 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,
|
||||
.code_id = (try store.getCodeIdJson(obj, "code")) orelse return error.MissingProperty,
|
||||
.type = TypeUtils.fromString(task_type) orelse return error.InvalidTaskType,
|
||||
.total = @intCast(total)
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
const Server = @import("../server.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -14,14 +14,14 @@ cooldown: Cooldown,
|
||||
character: Character,
|
||||
task: Task,
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !TaskData {
|
||||
pub fn parse(store: *Store, 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)
|
||||
.character = try Character.parse(store, character, allocator),
|
||||
.task = try Task.parse(store, task)
|
||||
};
|
||||
}
|
||||
|
415
api/server.zig
415
api/server.zig
@ -1,12 +1,13 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const assert = std.debug.assert;
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const json_utils = @import("json_utils.zig");
|
||||
pub const Character = @import("./schemas/character.zig");
|
||||
const Character = @import("./schemas/character.zig");
|
||||
const EnumStringUtils = @import("./enum_string_utils.zig").EnumStringUtils;
|
||||
pub const Position = @import("./position.zig");
|
||||
const Position = @import("./position.zig");
|
||||
const Store = @import("./store.zig");
|
||||
|
||||
const errors = @import("./errors.zig");
|
||||
const FetchError = errors.FetchError;
|
||||
@ -16,33 +17,20 @@ const FetchError = errors.FetchError;
|
||||
const Server = @This();
|
||||
|
||||
const log = std.log.scoped(.api);
|
||||
pub const ItemId = u32;
|
||||
|
||||
allocator: Allocator,
|
||||
client: std.http.Client,
|
||||
|
||||
server: []u8,
|
||||
server_uri: std.Uri,
|
||||
|
||||
token: ?[]u8 = null,
|
||||
|
||||
item_codes: std.ArrayList([]u8),
|
||||
characters: std.ArrayList(Character),
|
||||
|
||||
items: std.StringHashMap(Item),
|
||||
maps: std.AutoHashMap(Position, MapTile),
|
||||
resources: std.StringHashMap(Resource),
|
||||
monsters: std.StringHashMap(Monster),
|
||||
|
||||
prefetched_resources: bool = false,
|
||||
prefetched_maps: bool = false,
|
||||
prefetched_monsters: bool = false,
|
||||
prefetched_items: bool = false,
|
||||
store: Store,
|
||||
prefetched: bool = false,
|
||||
|
||||
// ------------------------- API result structs ------------------------
|
||||
|
||||
pub const Slot = @import("./schemas/slot.zig");
|
||||
const BoundedSlotsArray = @import("./schemas/slot_array.zig").BoundedSlotsArray;
|
||||
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");
|
||||
@ -64,29 +52,7 @@ 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 {
|
||||
id: ItemId,
|
||||
quantity: u64,
|
||||
|
||||
pub fn init(id: ItemId, quantity: u64) ItemIdQuantity {
|
||||
return ItemIdQuantity{
|
||||
.id = id,
|
||||
.quantity = quantity
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(api: *Server, obj: json.ObjectMap) !ItemIdQuantity {
|
||||
const code = try json_utils.getStringRequired(obj, "code");
|
||||
const quantity = try json_utils.getIntegerRequired(obj, "quantity");
|
||||
if (quantity < 1) return error.InvalidQuantity;
|
||||
|
||||
return ItemIdQuantity{
|
||||
.id = try api.getItemId(code),
|
||||
.quantity = @intCast(quantity)
|
||||
};
|
||||
}
|
||||
};
|
||||
const ItemQuantity = @import("./schemas/item_quantity.zig");
|
||||
|
||||
pub const ArtifactsFetchResult = struct {
|
||||
arena: std.heap.ArenaAllocator,
|
||||
@ -110,12 +76,7 @@ pub fn init(allocator: Allocator) !Server {
|
||||
.server = url,
|
||||
.server_uri = uri,
|
||||
|
||||
.item_codes = std.ArrayList([]u8).init(allocator),
|
||||
.characters = std.ArrayList(Character).init(allocator),
|
||||
.items = std.StringHashMap(Item).init(allocator),
|
||||
.maps = std.AutoHashMap(Position, MapTile).init(allocator),
|
||||
.resources = std.StringHashMap(Resource).init(allocator),
|
||||
.monsters = std.StringHashMap(Monster).init(allocator),
|
||||
.store = Store.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
@ -124,39 +85,7 @@ pub fn deinit(self: *Server) void {
|
||||
self.allocator.free(self.server);
|
||||
if (self.token) |str| self.allocator.free(str);
|
||||
|
||||
for (self.item_codes.items) |code| {
|
||||
self.allocator.free(code);
|
||||
}
|
||||
self.item_codes.deinit();
|
||||
|
||||
for (self.characters.items) |*char| {
|
||||
char.deinit();
|
||||
}
|
||||
self.characters.deinit();
|
||||
|
||||
var itemsIter = self.items.valueIterator();
|
||||
while (itemsIter.next()) |item| {
|
||||
item.deinit();
|
||||
}
|
||||
self.items.deinit();
|
||||
|
||||
var mapsIter = self.maps.valueIterator();
|
||||
while (mapsIter.next()) |map| {
|
||||
map.deinit(self.allocator);
|
||||
}
|
||||
self.maps.deinit();
|
||||
|
||||
var resourcesIter = self.resources.valueIterator();
|
||||
while (resourcesIter.next()) |resource| {
|
||||
resource.deinit(self.allocator);
|
||||
}
|
||||
self.resources.deinit();
|
||||
|
||||
var monstersIter = self.monsters.valueIterator();
|
||||
while (monstersIter.next()) |monster| {
|
||||
monster.deinit(self.allocator);
|
||||
}
|
||||
self.monsters.deinit();
|
||||
self.store.deinit();
|
||||
}
|
||||
|
||||
const FetchOptions = struct {
|
||||
@ -354,7 +283,7 @@ fn fetchOptionalObject(
|
||||
}
|
||||
|
||||
const body = json_utils.asObject(result.body.?) orelse return FetchError.ParseFailed;
|
||||
return @call(.auto, parseObject, .{ self, body } ++ parseObjectArgs) catch return FetchError.ParseFailed;
|
||||
return @call(.auto, parseObject, .{ &self.store, body } ++ parseObjectArgs) catch return FetchError.ParseFailed;
|
||||
}
|
||||
|
||||
fn fetchObject(
|
||||
@ -417,7 +346,7 @@ fn fetchOptionalArray(
|
||||
for (result_data.items) |result_item| {
|
||||
const item_obj = json_utils.asObject(result_item) orelse return FetchError.ParseFailed;
|
||||
|
||||
const parsed_item = @call(.auto, parseObject, .{ self, item_obj } ++ parseObjectArgs) catch return FetchError.ParseFailed;
|
||||
const parsed_item = @call(.auto, parseObject, .{ &self.store, item_obj } ++ parseObjectArgs) catch return FetchError.ParseFailed;
|
||||
array.append(parsed_item) catch return FetchError.OutOfMemory;
|
||||
}
|
||||
|
||||
@ -459,154 +388,22 @@ pub fn setToken(self: *Server, token: ?[]const u8) !void {
|
||||
self.token = new_token;
|
||||
}
|
||||
|
||||
pub fn getItemId(self: *Server, code: []const u8) !ItemId {
|
||||
assert(code.len != 0);
|
||||
|
||||
for (0.., self.item_codes.items) |i, item_code| {
|
||||
if (std.mem.eql(u8, code, item_code)) {
|
||||
return @intCast(i);
|
||||
}
|
||||
}
|
||||
|
||||
const code_dupe = try self.allocator.dupe(u8, code);
|
||||
errdefer self.allocator.free(code_dupe);
|
||||
try self.item_codes.append(code_dupe);
|
||||
|
||||
return @intCast(self.item_codes.items.len - 1);
|
||||
}
|
||||
|
||||
pub fn getItemCode(self: *const Server, id: ItemId) ?[]const u8 {
|
||||
if (id >= self.item_codes.items.len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self.item_codes.items[id];
|
||||
}
|
||||
|
||||
pub fn getItemIdJson(self: *Server, object: json.ObjectMap, name: []const u8) !?ItemId {
|
||||
const code = try json_utils.getStringRequired(object, name);
|
||||
if (code.len == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return try self.getItemId(code);
|
||||
}
|
||||
|
||||
fn findCharacterIndex(self: *const Server, name: []const u8) ?usize {
|
||||
for (0.., self.characters.items) |i, character| {
|
||||
if (std.mem.eql(u8, character.name, name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn addOrUpdateCharacter(self: *Server, character: Character) !void {
|
||||
if (self.findCharacterIndex(character.name)) |found| {
|
||||
self.characters.items[found].deinit();
|
||||
self.characters.items[found] = character;
|
||||
} else {
|
||||
try self.characters.append(character);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn findCharacter(self: *const Server, name: []const u8) ?Character {
|
||||
if (self.findCharacterIndex(name)) |index| {
|
||||
return self.characters.items[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn findCharacterPtr(self: *Server, name: []const u8) ?*Character {
|
||||
if (self.findCharacterIndex(name)) |index| {
|
||||
return &self.characters.items[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Remove this function
|
||||
pub fn findItem(self: *const Server, name: []const u8) ?Item {
|
||||
return self.items.get(name);
|
||||
}
|
||||
|
||||
// TODO: Remove this function
|
||||
pub fn findMap(self: *const Server, position: Position) ?MapTile {
|
||||
return self.maps.get(position);
|
||||
}
|
||||
|
||||
fn addOrUpdateItem(self: *Server, item: Item) !void {
|
||||
var entry = try self.items.getOrPut(item.code);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit();
|
||||
}
|
||||
entry.value_ptr.* = item;
|
||||
}
|
||||
|
||||
fn addOrUpdateMap(self: *Server, map: MapTile) !void {
|
||||
var entry = try self.maps.getOrPut(map.position);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = map;
|
||||
}
|
||||
|
||||
fn addOrUpdateResource(self: *Server, resource: Resource) !void {
|
||||
var entry = try self.resources.getOrPut(resource.code);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = resource;
|
||||
}
|
||||
|
||||
fn addOrUpdateMonster(self: *Server, monster: Monster) !void {
|
||||
var entry = try self.monsters.getOrPut(monster.code);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = monster;
|
||||
}
|
||||
|
||||
pub fn prefetch(self: *Server) !void {
|
||||
self.prefetched_resources = false;
|
||||
self.prefetched_maps = false;
|
||||
self.prefetched_monsters = false;
|
||||
self.prefetched_items = false;
|
||||
self.prefetched = false;
|
||||
|
||||
try self.prefetchResources();
|
||||
try self.prefetchMaps();
|
||||
try self.prefetchMonsters();
|
||||
try self.prefetchItems();
|
||||
}
|
||||
|
||||
pub fn prefetchResources(self: *Server) !void {
|
||||
var resources = try self.getResources(.{});
|
||||
const resources = try self.getResources(.{});
|
||||
defer resources.deinit();
|
||||
|
||||
self.prefetched_resources = true;
|
||||
}
|
||||
|
||||
pub fn prefetchMaps(self: *Server) !void {
|
||||
var maps = try self.getMaps(.{});
|
||||
const maps = try self.getMaps(.{});
|
||||
defer maps.deinit();
|
||||
|
||||
self.prefetched_maps = true;
|
||||
}
|
||||
|
||||
pub fn prefetchMonsters(self: *Server) !void {
|
||||
var monsters = try self.getMonsters(.{});
|
||||
const monsters = try self.getMonsters(.{});
|
||||
defer monsters.deinit();
|
||||
|
||||
self.prefetched_monsters = true;
|
||||
}
|
||||
|
||||
pub fn prefetchItems(self: *Server) !void {
|
||||
var items = try self.getItems(.{});
|
||||
const items = try self.getItems(.{});
|
||||
defer items.deinit();
|
||||
|
||||
self.prefetched_items = true;
|
||||
self.prefetched = true;
|
||||
}
|
||||
|
||||
// ------------------------- Endpoints ------------------------
|
||||
@ -635,7 +432,7 @@ pub fn getCharacter(self: *Server, name: []const u8) FetchError!?Character {
|
||||
|
||||
if (maybe_character) |*character| {
|
||||
errdefer character.deinit();
|
||||
try self.addOrUpdateCharacter(character.*);
|
||||
try self.store.putCharacter(character.*);
|
||||
return character.*;
|
||||
} else {
|
||||
return null;
|
||||
@ -653,7 +450,7 @@ pub fn listMyCharacters(self: *Server) FetchError!std.ArrayList(Character) {
|
||||
);
|
||||
errdefer characters.deinit();
|
||||
for (characters.items) |character| {
|
||||
try self.addOrUpdateCharacter(character);
|
||||
try self.store.putCharacter(character);
|
||||
}
|
||||
|
||||
return characters;
|
||||
@ -670,7 +467,7 @@ pub fn actionFight(self: *Server, name: []const u8) errors.FightError!FightResul
|
||||
FightResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -686,7 +483,7 @@ pub fn actionGather(self: *Server, name: []const u8) errors.GatherError!GatherRe
|
||||
GatherResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -705,7 +502,7 @@ pub fn actionMove(self: *Server, name: []const u8, x: i64, y: i64) errors.MoveEr
|
||||
MoveResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -728,7 +525,7 @@ pub fn actionBankDepositGold(
|
||||
GoldTransactionResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -752,7 +549,7 @@ pub fn actionBankDepositItem(
|
||||
ItemTransactionResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -775,7 +572,7 @@ pub fn actionBankWithdrawGold(
|
||||
GoldTransactionResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -799,7 +596,7 @@ pub fn actionBankWithdrawItem(
|
||||
ItemTransactionResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -823,7 +620,7 @@ pub fn actionCraft(
|
||||
CraftResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -846,7 +643,7 @@ pub fn actionUnequip(
|
||||
UnequipResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -870,7 +667,7 @@ pub fn actionEquip(
|
||||
EquipResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path, .payload = payload }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -893,13 +690,13 @@ pub fn getBankGold(self: *Server) FetchError!u64 {
|
||||
return @intCast(quantity);
|
||||
}
|
||||
|
||||
pub fn getBankItems(self: *Server, allocator: Allocator) FetchError!std.ArrayList(ItemIdQuantity) {
|
||||
pub fn getBankItems(self: *Server, allocator: Allocator) FetchError!std.ArrayList(ItemQuantity) {
|
||||
return self.fetchArray(
|
||||
allocator,
|
||||
FetchError,
|
||||
null,
|
||||
ItemIdQuantity,
|
||||
ItemIdQuantity.parse, .{},
|
||||
ItemQuantity,
|
||||
ItemQuantity.parse, .{},
|
||||
.{ .method = .GET, .path = "/my/bank/items", .paginated = true }
|
||||
);
|
||||
}
|
||||
@ -912,8 +709,8 @@ pub fn getBankItemQuantity(self: *Server, code: []const u8) FetchError!?u64 {
|
||||
self.allocator,
|
||||
FetchError,
|
||||
null,
|
||||
ItemIdQuantity,
|
||||
ItemIdQuantity.parse, .{},
|
||||
ItemQuantity,
|
||||
ItemQuantity.parse, .{},
|
||||
.{ .method = .GET, .path = "/my/bank/items", .query = query, .paginated = true }
|
||||
);
|
||||
if (maybe_items == null) {
|
||||
@ -931,13 +728,11 @@ pub fn getBankItemQuantity(self: *Server, code: []const u8) FetchError!?u64 {
|
||||
}
|
||||
|
||||
pub fn getMap(self: *Server, x: i64, y: i64) FetchError!?MapTile {
|
||||
const position = Position.init(x, y);
|
||||
|
||||
if (self.findMap(position)) |map| {
|
||||
if (self.store.getMap(x, y)) |map| {
|
||||
return map;
|
||||
}
|
||||
|
||||
if (self.prefetched_maps) {
|
||||
if (self.prefetched) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -953,7 +748,7 @@ pub fn getMap(self: *Server, x: i64, y: i64) FetchError!?MapTile {
|
||||
);
|
||||
|
||||
if (result) |map| {
|
||||
self.addOrUpdateMap(map);
|
||||
self.store.putMap(map);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -965,22 +760,8 @@ pub const MapOptions = struct {
|
||||
};
|
||||
|
||||
pub fn getMaps(self: *Server, opts: MapOptions) FetchError!std.ArrayList(MapTile) {
|
||||
if (self.prefetched_maps) {
|
||||
var found = std.ArrayList(MapTile).init(self.allocator);
|
||||
var mapIter = self.maps.valueIterator();
|
||||
while (mapIter.next()) |map| {
|
||||
if (opts.type) |content_type| {
|
||||
if (map.content == null) continue;
|
||||
if (map.content.?.type != content_type) continue;
|
||||
}
|
||||
if (opts.code) |content_code| {
|
||||
if (map.content == null) continue;
|
||||
if (!std.mem.eql(u8, map.content.?.code, content_code)) continue;
|
||||
}
|
||||
|
||||
try found.append(map.*);
|
||||
}
|
||||
return found;
|
||||
if (self.prefetched) {
|
||||
return try self.store.getMaps(opts);
|
||||
}
|
||||
|
||||
var query = std.ArrayList(u8).init(self.allocator);
|
||||
@ -1003,18 +784,18 @@ pub fn getMaps(self: *Server, opts: MapOptions) FetchError!std.ArrayList(MapTile
|
||||
);
|
||||
|
||||
for (result.items) |map| {
|
||||
try self.addOrUpdateMap(map);
|
||||
try self.store.putMap(map);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn getItem(self: *Server, code: []const u8) FetchError!?Item {
|
||||
if (self.items.get(code)) |item| {
|
||||
if (self.store.getItem(code)) |item| {
|
||||
return item;
|
||||
}
|
||||
|
||||
if (self.prefetched_items) {
|
||||
if (self.prefetched) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1030,7 +811,7 @@ pub fn getItem(self: *Server, code: []const u8) FetchError!?Item {
|
||||
);
|
||||
|
||||
if (result) |item_with_ge| {
|
||||
try self.addOrUpdateItem(item_with_ge.item);
|
||||
try self.store.putItem(item_with_ge.item);
|
||||
|
||||
return item_with_ge.item;
|
||||
} else {
|
||||
@ -1038,8 +819,8 @@ pub fn getItem(self: *Server, code: []const u8) FetchError!?Item {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getItemById(self: *Server, id: ItemId) FetchError!?Item {
|
||||
const code = self.getItemCode(id) orelse return null;
|
||||
pub fn getItemById(self: *Server, id: Store.CodeId) FetchError!?Item {
|
||||
const code = self.store.getCode(id) orelse return null;
|
||||
return self.getItem(code);
|
||||
}
|
||||
|
||||
@ -1053,38 +834,8 @@ pub const ItemOptions = struct {
|
||||
};
|
||||
|
||||
pub fn getItems(self: *Server, opts: ItemOptions) FetchError!std.ArrayList(Item) {
|
||||
if (self.prefetched_items) {
|
||||
var found = std.ArrayList(Item).init(self.allocator);
|
||||
var itemIter = self.items.valueIterator();
|
||||
while (itemIter.next()) |item| {
|
||||
if (opts.craft_skill) |craft_skill| {
|
||||
if (item.craft == null) continue;
|
||||
if (item.craft.?.skill != craft_skill) continue;
|
||||
}
|
||||
if (opts.craft_material) |craft_material| {
|
||||
if (item.craft == null) continue;
|
||||
const recipe = item.craft.?;
|
||||
|
||||
const craft_material_id = try self.getItemId(craft_material);
|
||||
const material_quantity = recipe.items.getQuantity(craft_material_id);
|
||||
if (material_quantity == 0) continue;
|
||||
}
|
||||
if (opts.min_level) |min_level| {
|
||||
if (item.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (item.level > max_level) continue;
|
||||
}
|
||||
if (opts.type) |item_type| {
|
||||
if (item.type != item_type) continue;
|
||||
}
|
||||
if (opts.name) |name| {
|
||||
if (std.mem.indexOf(u8, item.name, name) == null) continue;
|
||||
}
|
||||
|
||||
try found.append(item.*);
|
||||
}
|
||||
return found;
|
||||
if (self.prefetched) {
|
||||
return try self.store.getItems(opts);
|
||||
}
|
||||
|
||||
var str_arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
@ -1122,18 +873,18 @@ pub fn getItems(self: *Server, opts: ItemOptions) FetchError!std.ArrayList(Item)
|
||||
errdefer result.deinit();
|
||||
|
||||
for (result.items) |item| {
|
||||
try self.addOrUpdateItem(item);
|
||||
try self.store.putItem(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn getResource(self: *Server, code: []const u8) FetchError!?Resource {
|
||||
if (self.resources.get(code)) |resource| {
|
||||
if (self.store.getResource(code)) |resource| {
|
||||
return resource;
|
||||
}
|
||||
|
||||
if (self.prefetched_resources) {
|
||||
if (self.prefetched) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1149,7 +900,7 @@ pub fn getResource(self: *Server, code: []const u8) FetchError!?Resource {
|
||||
);
|
||||
|
||||
if (result) |resource| {
|
||||
try self.addOrUpdateResource(resource);
|
||||
try self.store.putResource(resource);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1163,26 +914,8 @@ pub const ResourceOptions = struct {
|
||||
};
|
||||
|
||||
pub fn getResources(self: *Server, opts: ResourceOptions) FetchError!std.ArrayList(Resource) {
|
||||
if (self.prefetched_resources) {
|
||||
var found = std.ArrayList(Resource).init(self.allocator);
|
||||
var resourceIter = self.resources.valueIterator();
|
||||
while (resourceIter.next()) |resource| {
|
||||
if (opts.min_level) |min_level| {
|
||||
if (resource.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (resource.level > max_level) continue;
|
||||
}
|
||||
if (opts.drop) |drop| {
|
||||
const item_id = try self.getItemId(drop);
|
||||
if (!DropRate.doesListContain(&resource.drops, item_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try found.append(resource.*);
|
||||
}
|
||||
return found;
|
||||
if (self.prefetched) {
|
||||
return self.store.getResources(opts);
|
||||
}
|
||||
|
||||
var str_arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
@ -1217,18 +950,18 @@ pub fn getResources(self: *Server, opts: ResourceOptions) FetchError!std.ArrayLi
|
||||
errdefer result.deinit();
|
||||
|
||||
for (result.items) |resource| {
|
||||
try self.addOrUpdateResource(resource);
|
||||
try self.store.putResource(resource);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn getMonster(self: *Server, code: []const u8) FetchError!?Monster {
|
||||
if (self.monsters.get(code)) |monster| {
|
||||
if (self.store.getMonster(code)) |monster| {
|
||||
return monster;
|
||||
}
|
||||
|
||||
if (self.prefetched_monsters) {
|
||||
if (self.prefetched) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1244,7 +977,7 @@ pub fn getMonster(self: *Server, code: []const u8) FetchError!?Monster {
|
||||
);
|
||||
|
||||
if (result) |monster| {
|
||||
try self.addOrUpdateMonster(monster);
|
||||
try self.store.putMonster(monster);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1257,26 +990,8 @@ pub const MonsterOptions = struct {
|
||||
};
|
||||
|
||||
pub fn getMonsters(self: *Server, opts: MonsterOptions) FetchError!std.ArrayList(Monster) {
|
||||
if (self.prefetched_monsters) {
|
||||
var found = std.ArrayList(Monster).init(self.allocator);
|
||||
var monsterIter = self.monsters.valueIterator();
|
||||
while (monsterIter.next()) |monster| {
|
||||
if (opts.min_level) |min_level| {
|
||||
if (monster.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (monster.level > max_level) continue;
|
||||
}
|
||||
if (opts.drop) |drop| {
|
||||
const item_id = try self.getItemId(drop);
|
||||
if (!DropRate.doesListContain(&monster.drops, item_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try found.append(monster.*);
|
||||
}
|
||||
return found;
|
||||
if (self.prefetched) {
|
||||
return try self.store.getMonsters(opts);
|
||||
}
|
||||
|
||||
var str_arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
@ -1307,24 +1022,24 @@ pub fn getMonsters(self: *Server, opts: MonsterOptions) FetchError!std.ArrayList
|
||||
);
|
||||
|
||||
for (result.items) |monster| {
|
||||
try self.addOrUpdateMonster(monster);
|
||||
try self.store.putMonster(monster);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn acceptTask(self: *Server, name: []const u8) errors.TaskAcceptError {
|
||||
pub fn acceptTask(self: *Server, name: []const u8) errors.TaskAcceptError!AcceptTaskResult {
|
||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/task/new", .{name});
|
||||
defer self.allocator.free(path);
|
||||
|
||||
const result = try self.fetchObject(
|
||||
errors.TaskAcceptError,
|
||||
errors.parseTaskAcceptError,
|
||||
EquipResult,
|
||||
EquipResult.parse, .{ self.allocator },
|
||||
AcceptTaskResult,
|
||||
AcceptTaskResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path }
|
||||
);
|
||||
try self.addOrUpdateCharacter(result.character);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
302
api/store.zig
Normal file
302
api/store.zig
Normal file
@ -0,0 +1,302 @@
|
||||
const std = @import("std");
|
||||
const json_utils = @import("json_utils.zig");
|
||||
const Server = @import("./server.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const Store = @This();
|
||||
|
||||
const Character = @import("./schemas/character.zig");
|
||||
const Item = @import("./schemas/item.zig");
|
||||
const Position = @import("./position.zig");
|
||||
const Map = @import("./schemas/map.zig");
|
||||
const Resource = @import("./schemas/resource.zig");
|
||||
const Monster = @import("./schemas/monster.zig");
|
||||
const DropRate = @import("./schemas/drop_rate.zig");
|
||||
|
||||
pub const CodeId = u16;
|
||||
|
||||
allocator: Allocator,
|
||||
codes: std.ArrayList([]u8),
|
||||
characters: std.ArrayList(Character),
|
||||
items: std.StringHashMap(Item),
|
||||
maps: std.AutoHashMap(Position, Map),
|
||||
resources: std.StringHashMap(Resource),
|
||||
monsters: std.StringHashMap(Monster),
|
||||
// TODO: bank
|
||||
|
||||
pub fn init(allocator: Allocator) Store {
|
||||
return Store{
|
||||
.allocator = allocator,
|
||||
.codes = std.ArrayList([]u8).init(allocator),
|
||||
.characters = std.ArrayList(Character).init(allocator),
|
||||
.items = std.StringHashMap(Item).init(allocator),
|
||||
.maps = std.AutoHashMap(Position, Map).init(allocator),
|
||||
.resources = std.StringHashMap(Resource).init(allocator),
|
||||
.monsters = std.StringHashMap(Monster).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Store) void {
|
||||
for (self.codes.items) |code| {
|
||||
self.allocator.free(code);
|
||||
}
|
||||
self.codes.deinit();
|
||||
|
||||
for (self.characters.items) |*char| {
|
||||
char.deinit();
|
||||
}
|
||||
self.characters.deinit();
|
||||
|
||||
var itemsIter = self.items.valueIterator();
|
||||
while (itemsIter.next()) |item| {
|
||||
item.deinit();
|
||||
}
|
||||
self.items.deinit();
|
||||
|
||||
var mapsIter = self.maps.valueIterator();
|
||||
while (mapsIter.next()) |map| {
|
||||
map.deinit(self.allocator);
|
||||
}
|
||||
self.maps.deinit();
|
||||
|
||||
var resourcesIter = self.resources.valueIterator();
|
||||
while (resourcesIter.next()) |resource| {
|
||||
resource.deinit(self.allocator);
|
||||
}
|
||||
self.resources.deinit();
|
||||
|
||||
var monstersIter = self.monsters.valueIterator();
|
||||
while (monstersIter.next()) |monster| {
|
||||
monster.deinit(self.allocator);
|
||||
}
|
||||
self.monsters.deinit();
|
||||
}
|
||||
|
||||
pub fn getCodeId(self: *Store, code: []const u8) !CodeId {
|
||||
assert(code.len != 0);
|
||||
|
||||
for (0.., self.codes.items) |i, item_code| {
|
||||
if (std.mem.eql(u8, code, item_code)) {
|
||||
return @intCast(i);
|
||||
}
|
||||
}
|
||||
|
||||
const code_dupe = try self.allocator.dupe(u8, code);
|
||||
errdefer self.allocator.free(code_dupe);
|
||||
try self.codes.append(code_dupe);
|
||||
|
||||
return @intCast(self.codes.items.len - 1);
|
||||
}
|
||||
|
||||
pub fn getCode(self: *const Store, id: CodeId) ?[]const u8 {
|
||||
if (id >= self.codes.items.len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self.codes.items[id];
|
||||
}
|
||||
|
||||
pub fn getCodeIdJson(self: *Store, object: json.ObjectMap, name: []const u8) !?CodeId {
|
||||
const code = try json_utils.getStringRequired(object, name);
|
||||
if (code.len == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return try self.getCodeId(code);
|
||||
}
|
||||
|
||||
// ----------------------- Character ------------------------------
|
||||
|
||||
fn getCharacterIndex(self: *const Store, name: []const u8) ?usize {
|
||||
for (0.., self.characters.items) |i, character| {
|
||||
if (std.mem.eql(u8, character.name, name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn getCharacter(self: *Store, name: []const u8) ?Character {
|
||||
if (self.getCharacterIndex(name)) |index| {
|
||||
return self.characters.items[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn putCharacter(self: *Store, character: Character) !void {
|
||||
if (self.getCharacterIndex(character.name)) |index| {
|
||||
self.characters.items[index].deinit();
|
||||
self.characters.items[index] = character;
|
||||
} else {
|
||||
try self.characters.append(character);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- Map ------------------------------
|
||||
|
||||
pub fn getMap(self: *Store, x: i64, y: i64) ?Map {
|
||||
const pos = Position.init(x, y);
|
||||
return self.maps.get(pos);
|
||||
}
|
||||
|
||||
pub fn getMaps(self: *Store, opts: Server.MapOptions) !std.ArrayList(Map) {
|
||||
var found = std.ArrayList(Map).init(self.allocator);
|
||||
errdefer found.deinit();
|
||||
|
||||
var mapIter = self.maps.valueIterator();
|
||||
while (mapIter.next()) |map| {
|
||||
if (opts.type) |content_type| {
|
||||
if (map.content == null) continue;
|
||||
if (map.content.?.type != content_type) continue;
|
||||
}
|
||||
if (opts.code) |content_code| {
|
||||
if (map.content == null) continue;
|
||||
if (!std.mem.eql(u8, map.content.?.code, content_code)) continue;
|
||||
}
|
||||
|
||||
try found.append(map.*);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
pub fn putMap(self: *Store, map: Map) !void {
|
||||
var entry = try self.maps.getOrPut(map.position);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = map;
|
||||
}
|
||||
|
||||
// ----------------------- Item ------------------------------
|
||||
|
||||
pub fn getItem(self: *Store, code: []const u8) ?Item {
|
||||
return self.items.get(code);
|
||||
}
|
||||
|
||||
pub fn getItems(self: *Store, opts: Server.ItemOptions) !std.ArrayList(Item) {
|
||||
var found = std.ArrayList(Item).init(self.allocator);
|
||||
errdefer found.deinit();
|
||||
|
||||
var itemIter = self.items.valueIterator();
|
||||
while (itemIter.next()) |item| {
|
||||
if (opts.craft_skill) |craft_skill| {
|
||||
if (item.craft == null) continue;
|
||||
if (item.craft.?.skill != craft_skill) continue;
|
||||
}
|
||||
if (opts.craft_material) |craft_material| {
|
||||
if (item.craft == null) continue;
|
||||
const recipe = item.craft.?;
|
||||
|
||||
const craft_material_id = try self.getItemId(craft_material);
|
||||
const material_quantity = recipe.items.getQuantity(craft_material_id);
|
||||
if (material_quantity == 0) continue;
|
||||
}
|
||||
if (opts.min_level) |min_level| {
|
||||
if (item.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (item.level > max_level) continue;
|
||||
}
|
||||
if (opts.type) |item_type| {
|
||||
if (item.type != item_type) continue;
|
||||
}
|
||||
if (opts.name) |name| {
|
||||
if (std.mem.indexOf(u8, item.name, name) == null) continue;
|
||||
}
|
||||
|
||||
try found.append(item.*);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
pub fn putItem(self: *Store, item: Item) !void {
|
||||
var entry = try self.items.getOrPut(item.code);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit();
|
||||
}
|
||||
entry.value_ptr.* = item;
|
||||
}
|
||||
|
||||
// ----------------------- Monster ------------------------------
|
||||
|
||||
pub fn getMonster(self: *Store, code: []const u8) ?Monster {
|
||||
return self.monsters.get(code);
|
||||
}
|
||||
|
||||
pub fn getMonsters(self: *Store, opts: Server.MonsterOptions) !std.ArrayList(Monster) {
|
||||
var found = std.ArrayList(Monster).init(self.allocator);
|
||||
errdefer found.deinit();
|
||||
|
||||
var monsterIter = self.monsters.valueIterator();
|
||||
while (monsterIter.next()) |monster| {
|
||||
if (opts.min_level) |min_level| {
|
||||
if (monster.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (monster.level > max_level) continue;
|
||||
}
|
||||
if (opts.drop) |drop| {
|
||||
const item_id = try self.getItemId(drop);
|
||||
if (!DropRate.doesListContain(&monster.drops, item_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try found.append(monster.*);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
pub fn putMonster(self: *Store, monster: Monster) !void {
|
||||
var entry = try self.resources.getOrPut(monster.code_id);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = monster;
|
||||
}
|
||||
|
||||
// ----------------------- Resource ------------------------------
|
||||
|
||||
pub fn getResource(self: *Store, code: []const u8) ?Resource {
|
||||
return self.resources.get(code);
|
||||
}
|
||||
|
||||
pub fn getResources(self: *Store, opts: Server.ResourceOptions) !std.ArrayList(Resource) {
|
||||
var found = std.ArrayList(Resource).init(self.allocator);
|
||||
errdefer found.deinit();
|
||||
|
||||
var resourceIter = self.resources.valueIterator();
|
||||
while (resourceIter.next()) |resource| {
|
||||
if (opts.min_level) |min_level| {
|
||||
if (resource.level < min_level) continue;
|
||||
}
|
||||
if (opts.max_level) |max_level| {
|
||||
if (resource.level > max_level) continue;
|
||||
}
|
||||
if (opts.drop) |drop| {
|
||||
const item_id = try self.getItemId(drop);
|
||||
if (!DropRate.doesListContain(&resource.drops, item_id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try found.append(resource.*);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
pub fn putResource(self: *Store, resource: Resource) !void {
|
||||
var entry = try self.resources.getOrPut(resource.code);
|
||||
if (entry.found_existing) {
|
||||
entry.value_ptr.deinit(self.allocator);
|
||||
}
|
||||
entry.value_ptr.* = resource;
|
||||
}
|
@ -9,9 +9,9 @@ pub const Action = union(enum) {
|
||||
fight,
|
||||
gather,
|
||||
deposit_gold: u64,
|
||||
deposit_item: Server.ItemIdQuantity,
|
||||
withdraw_item: Server.ItemIdQuantity,
|
||||
craft_item: Server.ItemIdQuantity,
|
||||
deposit_item: Api.ItemQuantity,
|
||||
withdraw_item: Api.ItemQuantity,
|
||||
craft_item: Api.ItemQuantity,
|
||||
|
||||
pub fn perform(self: Action, api: *Server, name: []const u8) !ActionResult {
|
||||
const log = std.log.default;
|
||||
@ -36,14 +36,14 @@ pub const Action = union(enum) {
|
||||
};
|
||||
},
|
||||
.deposit_item => |item| {
|
||||
const code = api.getItemCode(item.id) orelse return error.ItemNotFound;
|
||||
const code = api.store.getCode(item.id) orelse return error.ItemNotFound;
|
||||
log.debug("[{s}] deposit {s} (x{})", .{name, code, item.quantity});
|
||||
return .{
|
||||
.deposit_item = api.actionBankDepositItem(name, code, item.quantity)
|
||||
};
|
||||
},
|
||||
.withdraw_item => |item| {
|
||||
const code = api.getItemCode(item.id) orelse return error.ItemNotFound;
|
||||
const code = api.store.getCode(item.id) orelse return error.ItemNotFound;
|
||||
log.debug("[{s}] withdraw {s} (x{})", .{name, code, item.quantity});
|
||||
return .{
|
||||
.withdraw_item = api.actionBankWithdrawItem(name, code, item.quantity)
|
||||
@ -56,7 +56,7 @@ pub const Action = union(enum) {
|
||||
};
|
||||
},
|
||||
.craft_item => |item| {
|
||||
const code = api.getItemCode(item.id) orelse return error.ItemNotFound;
|
||||
const code = api.store.getCode(item.id) orelse return error.ItemNotFound;
|
||||
log.debug("[{s}] craft {s} (x{})", .{name, code, item.quantity});
|
||||
return .{
|
||||
.craft_item = api.actionCraft(name, code, item.quantity)
|
||||
|
@ -14,6 +14,7 @@ const Brain = @This();
|
||||
name: []const u8,
|
||||
action_queue: std.ArrayList(QueuedAction),
|
||||
task: ?CharacterTask = null,
|
||||
paused_until: ?i64 = null,
|
||||
|
||||
pub fn init(allocator: Allocator, name: []const u8) !Brain {
|
||||
return Brain{
|
||||
@ -28,17 +29,11 @@ pub fn deinit(self: Brain) void {
|
||||
self.action_queue.deinit();
|
||||
}
|
||||
|
||||
fn currentTime() f64 {
|
||||
const timestamp: f64 = @floatFromInt(std.time.milliTimestamp());
|
||||
return timestamp / std.time.ms_per_s;
|
||||
}
|
||||
|
||||
pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
const log = std.log.default;
|
||||
assert(self.action_queue.items.len > 0);
|
||||
|
||||
const retry_delay = 0.5; // 500ms
|
||||
var character = api.findCharacterPtr(self.name).?;
|
||||
const retry_delay = std.time.ns_per_ms * 500; // 500ms
|
||||
|
||||
const next_action = self.action_queue.items[0];
|
||||
const action_result = try next_action.perform(api, self.name);
|
||||
@ -46,12 +41,14 @@ pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
if (action_result.getErrorResponse()) |error_response| {
|
||||
switch (error_response) {
|
||||
.retry => {
|
||||
character.cooldown_expiration = currentTime() + retry_delay;
|
||||
log.warn("[{s}] retry withdrawing item", .{self.name});
|
||||
self.paused_until = std.time.timestamp() + retry_delay;
|
||||
log.warn("[{s}] retry action", .{self.name});
|
||||
return;
|
||||
},
|
||||
.restart => {
|
||||
log.warn("[{s}] clear action queue", .{self.name});
|
||||
self.action_queue.clearAndFree();
|
||||
return;
|
||||
},
|
||||
.abort => {
|
||||
try action_result.getError();
|
||||
@ -71,6 +68,13 @@ pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
}
|
||||
|
||||
pub fn step(self: *Brain, api: *Api.Server) !void {
|
||||
if (self.paused_until) |paused_until| {
|
||||
if (std.time.timestamp() < paused_until) {
|
||||
return;
|
||||
}
|
||||
self.paused_until = null;
|
||||
}
|
||||
|
||||
if (self.action_queue.items.len > 0) return;
|
||||
|
||||
if (self.task) |task| {
|
||||
@ -86,3 +90,14 @@ pub fn step(self: *Brain, api: *Api.Server) !void {
|
||||
try task.queueActions(api, self.name, &self.action_queue);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cooldown(self: *Brain, api: *Server) i64 {
|
||||
const character = api.store.getCharacter(self.name).?;
|
||||
const cooldown_expiration: i64 = @intFromFloat(character.cooldown_expiration * std.time.ns_per_s);
|
||||
|
||||
if (self.paused_until) |pause_until| {
|
||||
return @max(cooldown_expiration, pause_until);
|
||||
} else {
|
||||
return cooldown_expiration;
|
||||
}
|
||||
}
|
||||
|
16
lib/root.zig
16
lib/root.zig
@ -66,13 +66,12 @@ pub fn step(self: *Artificer) !void {
|
||||
|
||||
for (self.characters.items) |*brain| {
|
||||
if (brain.task == null) {
|
||||
const character = self.server.findCharacter(brain.name).?;
|
||||
const character = self.server.store.getCharacter(brain.name).?;
|
||||
if (character.task == null) {
|
||||
brain.task = .{ .accept_task = .{} };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try brain.step(&self.server);
|
||||
}
|
||||
}
|
||||
@ -90,9 +89,7 @@ fn earliestCooldown(characters: []Brain, api: *Api.Server) ?i64 {
|
||||
for (characters) |*brain| {
|
||||
if (brain.action_queue.items.len == 0) continue;
|
||||
|
||||
const character = api.findCharacter(brain.name).?;
|
||||
const cooldown: i64 = @intFromFloat(character.cooldown_expiration * std.time.ns_per_s);
|
||||
|
||||
const cooldown = brain.cooldown(api);
|
||||
if (earliest_cooldown == null or earliest_cooldown.? > cooldown) {
|
||||
earliest_cooldown = cooldown;
|
||||
}
|
||||
@ -111,16 +108,9 @@ fn runNextActions(characters: []Brain, api: *Api.Server) !void {
|
||||
for (characters) |*brain| {
|
||||
if (brain.action_queue.items.len == 0) continue;
|
||||
|
||||
const character = api.findCharacter(brain.name).?;
|
||||
const cooldown: u64 = @intFromFloat(character.cooldown_expiration * std.time.ns_per_s);
|
||||
|
||||
const cooldown = brain.cooldown(api);
|
||||
if (earliest_cooldown > cooldown) {
|
||||
try brain.performNextAction(api);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn currentTime() f64 {
|
||||
const timestamp: f64 = @floatFromInt(std.time.milliTimestamp());
|
||||
return timestamp / std.time.ms_per_s;
|
||||
}
|
||||
|
32
lib/task.zig
32
lib/task.zig
@ -4,14 +4,14 @@ const Position = Api.Position;
|
||||
|
||||
const Action = @import("./action.zig").Action;
|
||||
const ActionResult = @import("./action.zig").ActionResult;
|
||||
const ItemId = Api.ItemId;
|
||||
const Slot = Api.Slot;
|
||||
const CodeId = Api.CodeId;
|
||||
const ItemQuantity = Api.ItemQuantity;
|
||||
|
||||
const bank_position: Position = .{ .x = 4, .y = 1 }; // TODO: Figure this out dynamically
|
||||
|
||||
pub const UntilCondition = union(enum) {
|
||||
xp: u64,
|
||||
item: Api.ItemIdQuantity,
|
||||
item: Api.ItemQuantity,
|
||||
};
|
||||
|
||||
pub const Task = union(enum) {
|
||||
@ -27,7 +27,7 @@ pub const Task = union(enum) {
|
||||
},
|
||||
craft: struct {
|
||||
at: Position,
|
||||
target: Api.ItemIdQuantity,
|
||||
target: Api.ItemQuantity,
|
||||
progress: u64 = 0,
|
||||
},
|
||||
accept_task: struct {
|
||||
@ -104,8 +104,12 @@ const TaskContext = struct {
|
||||
name: []const u8,
|
||||
action_queue: *std.ArrayList(Action),
|
||||
|
||||
fn getCharacter(self: TaskContext) Api.Character {
|
||||
return self.api.store.getCharacter(self.name).?;
|
||||
}
|
||||
|
||||
fn moveIfNeeded(self: TaskContext, pos: Position) !bool {
|
||||
const character = self.api.findCharacter(self.name).?;
|
||||
const character = self.getCharacter();
|
||||
|
||||
if (character.position.eql(pos)) {
|
||||
return false;
|
||||
@ -117,7 +121,7 @@ const TaskContext = struct {
|
||||
}
|
||||
|
||||
pub fn depositItemsToBank(self: TaskContext) !bool {
|
||||
var character = self.api.findCharacter(self.name).?;
|
||||
var character = self.getCharacter();
|
||||
const action_queue = self.action_queue;
|
||||
|
||||
// Deposit items and gold to bank if full
|
||||
@ -139,7 +143,7 @@ const TaskContext = struct {
|
||||
}
|
||||
|
||||
fn depositIfFull(self: TaskContext) !bool {
|
||||
const character = self.api.findCharacter(self.name).?;
|
||||
const character = self.getCharacter();
|
||||
if (character.getItemCount() < character.inventory_max_items) {
|
||||
return false;
|
||||
}
|
||||
@ -177,8 +181,8 @@ const TaskContext = struct {
|
||||
try self.action_queue.append(.{ .gather = {} });
|
||||
}
|
||||
|
||||
fn withdrawFromBank(self: TaskContext, items: []const Slot) !bool {
|
||||
var character = self.api.findCharacter(self.name).?;
|
||||
fn withdrawFromBank(self: TaskContext, items: []const ItemQuantity) !bool {
|
||||
const character = self.getCharacter();
|
||||
|
||||
var has_all_items = true;
|
||||
for (items) |item_quantity| {
|
||||
@ -207,8 +211,8 @@ const TaskContext = struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn craftItem(self: TaskContext, workstation: Position, id: ItemId, quantity: u64) !bool {
|
||||
var character = self.api.findCharacter(self.name).?;
|
||||
fn craftItem(self: TaskContext, workstation: Position, id: CodeId, quantity: u64) !bool {
|
||||
var character = self.getCharacter();
|
||||
|
||||
const inventory_quantity = character.inventory.getQuantity(id);
|
||||
if (inventory_quantity >= quantity) {
|
||||
@ -227,8 +231,8 @@ const TaskContext = struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn craftRoutine(self: TaskContext, workstation: Position, id: ItemId, quantity: u64) !void {
|
||||
var character = self.api.findCharacter(self.name).?;
|
||||
fn craftRoutine(self: TaskContext, workstation: Position, id: CodeId, quantity: u64) !void {
|
||||
var character = self.getCharacter();
|
||||
const inventory_quantity = character.inventory.getQuantity(id);
|
||||
if (inventory_quantity >= quantity) {
|
||||
if (try self.depositItemsToBank()) {
|
||||
@ -236,7 +240,7 @@ const TaskContext = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const code = self.api.getItemCode(id) orelse return error.InvalidItemId;
|
||||
const code = self.api.store.getCode(id) orelse return error.InvalidItemId;
|
||||
const target_item = try self.api.getItem(code) orelse return error.ItemNotFound;
|
||||
if (target_item.craft == null) {
|
||||
return error.NotCraftable;
|
||||
|
@ -13,43 +13,6 @@ const TaskNode = struct {
|
||||
task: CharacterTask,
|
||||
dependencies: Dependencies = Dependencies.init(0) catch unreachable,
|
||||
missing_items: MissingItems = MissingItems.init(),
|
||||
|
||||
pub fn format(
|
||||
self: TaskNode,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = options;
|
||||
_ = fmt;
|
||||
|
||||
switch (self.task) {
|
||||
.fight => |args| {
|
||||
const item = self.api.getItemCode(args.target.id).?;
|
||||
try writer.print("Task{{ .fight = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, args.target.quantity, args.at});
|
||||
},
|
||||
.gather => |args| {
|
||||
const item = self.api.getItemCode(args.target.id).?;
|
||||
try writer.print("Task{{ .gather = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, args.target.quantity, args.at});
|
||||
},
|
||||
.craft => |args| {
|
||||
const item = self.api.getItemCode(args.target.id).?;
|
||||
try writer.print("Task{{ .craft = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, args.target.quantity, args.at});
|
||||
},
|
||||
}
|
||||
|
||||
// var child_nodes = try self.listByParent(node_id);
|
||||
// defer child_nodes.deinit();
|
||||
//
|
||||
// for (child_nodes.items) |child_node| {
|
||||
// try self.formatNode(child_node, level + 1, writer);
|
||||
// }
|
||||
// for (node.additional_items.slots.constSlice()) |slot| {
|
||||
// const item_code = self.api.getItemCode(slot.id).?;
|
||||
// try writer.writeBytesNTimes(" ", level+1);
|
||||
// try writer.print("+ {{ \"{s}\" x {} }}\n", .{item_code, slot.quantity});
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
const Nodes = std.ArrayList(TaskNode);
|
||||
@ -73,8 +36,8 @@ fn addTask(self: *TaskGraph, node: TaskNode) !TaskNodeId {
|
||||
return @intCast(self.nodes.items.len-1);
|
||||
}
|
||||
|
||||
fn addFightTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantity: u64) !TaskNodeId {
|
||||
const item_code = api.getItemCode(item_id) orelse return error.ItemNotFound;
|
||||
fn addFightTask(self: *TaskGraph, api: *Api.Server, item_id: Api.CodeId, quantity: u64) !TaskNodeId {
|
||||
const item_code = api.store.getCode(item_id) orelse return error.ItemNotFound;
|
||||
const monsters = try api.getMonsters(.{ .drop = item_code });
|
||||
defer monsters.deinit();
|
||||
|
||||
@ -95,14 +58,14 @@ fn addFightTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantit
|
||||
.task = .{
|
||||
.fight = .{
|
||||
.at = resource_map.position,
|
||||
.until = .{ .item = Api.ItemIdQuantity.init(item_id, quantity) }
|
||||
.until = .{ .item = Api.ItemQuantity.init(item_id, quantity) }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn addGatherTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantity: u64) !TaskNodeId {
|
||||
const item_code = api.getItemCode(item_id) orelse return error.ItemNotFound;
|
||||
fn addGatherTask(self: *TaskGraph, api: *Api.Server, item_id: Api.CodeId, quantity: u64) !TaskNodeId {
|
||||
const item_code = api.store.getCode(item_id) orelse return error.ItemNotFound;
|
||||
const resources = try api.getResources(.{ .drop = item_code });
|
||||
defer resources.deinit();
|
||||
|
||||
@ -121,13 +84,13 @@ fn addGatherTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quanti
|
||||
.task = .{
|
||||
.gather = .{
|
||||
.at = resource_map.position,
|
||||
.until = .{ .item = Api.ItemIdQuantity.init(item_id, quantity) }
|
||||
.until = .{ .item = Api.ItemQuantity.init(item_id, quantity) }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn addCraftTaskShallow(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantity: u64) !TaskNodeId {
|
||||
fn addCraftTaskShallow(self: *TaskGraph, api: *Api.Server, item_id: Api.CodeId, quantity: u64) !TaskNodeId {
|
||||
const item = (try api.getItemById(item_id)) orelse return error.ItemNotFound;
|
||||
const recipe = item.craft orelse return error.RecipeNotFound;
|
||||
|
||||
@ -142,13 +105,13 @@ fn addCraftTaskShallow(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId,
|
||||
.task = .{
|
||||
.craft = .{
|
||||
.at = workshop_maps.items[0].position,
|
||||
.target = Api.ItemIdQuantity.init(item_id, quantity)
|
||||
.target = Api.ItemQuantity.init(item_id, quantity)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn addCraftTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantity: u64) !TaskNodeId {
|
||||
fn addCraftTask(self: *TaskGraph, api: *Api.Server, item_id: Api.CodeId, quantity: u64) !TaskNodeId {
|
||||
const node_id = try self.addCraftTaskShallow(api, item_id, quantity);
|
||||
var node = self.get(node_id);
|
||||
|
||||
@ -171,7 +134,7 @@ fn addCraftTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantit
|
||||
}
|
||||
|
||||
// TODO: Remove `anyerror` from function declaration
|
||||
fn addAutoTask(self: *TaskGraph, api: *Api.Server, item_id: Api.ItemId, quantity: u64) anyerror!?TaskNodeId {
|
||||
fn addAutoTask(self: *TaskGraph, api: *Api.Server, item_id: Api.CodeId, quantity: u64) anyerror!?TaskNodeId {
|
||||
const item = (try self.api.getItemById(item_id)) orelse return error.ItemNotFound;
|
||||
|
||||
if (item.craft != null) {
|
||||
@ -209,16 +172,16 @@ fn printTaskLevel(self: *TaskGraph, api: *Api.Server, node_id: TaskNodeId, level
|
||||
switch (node.task) {
|
||||
.fight => |args| {
|
||||
const target_item = args.until.item;
|
||||
const item = api.getItemCode(target_item.id).?;
|
||||
const item = api.store.getCode(target_item.id).?;
|
||||
print("Task{{ .fight = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, target_item.quantity, args.at});
|
||||
},
|
||||
.gather => |args| {
|
||||
const target_item = args.until.item;
|
||||
const item = api.getItemCode(target_item.id).?;
|
||||
const item = api.store.getCode(target_item.id).?;
|
||||
print("Task{{ .gather = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, target_item.quantity, args.at});
|
||||
},
|
||||
.craft => |args| {
|
||||
const item = api.getItemCode(args.target.id).?;
|
||||
const item = api.store.getCode(args.target.id).?;
|
||||
print("Task{{ .craft = {{ \"{s}\" x {} }}, .at = {} }}\n", .{item, args.target.quantity, args.at});
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user