135 lines
3.9 KiB
Zig
135 lines
3.9 KiB
Zig
const std = @import("std");
|
|
const Api = @import("artifacts-api");
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const CharacterBrain = @import("./brain.zig");
|
|
|
|
const Artificer = @This();
|
|
|
|
const expiration_margin: u64 = 100 * std.time.ns_per_ms; // 100ms
|
|
const server_down_retry_interval = 5; // minutes
|
|
|
|
server: Api.Server,
|
|
characters: std.ArrayList(CharacterBrain),
|
|
|
|
paused_until: ?i64 = null,
|
|
|
|
pub fn init(allocator: Allocator, token: []const u8) !Artificer {
|
|
var server = try Api.Server.init(allocator);
|
|
errdefer server.deinit();
|
|
|
|
try server.setToken(token);
|
|
|
|
var characters = std.ArrayList(CharacterBrain).init(allocator);
|
|
defer characters.deinit();
|
|
// TODO: Add character deinit
|
|
|
|
// const chars = try api.listMyCharacters();
|
|
// defer chars.deinit();
|
|
|
|
// for (chars.items) |char| {
|
|
// try scheduler.addCharacter(char.name);
|
|
// }
|
|
|
|
return Artificer{
|
|
.server = server,
|
|
.characters = characters
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: Artificer) void {
|
|
for (self.characters.items) |brain| {
|
|
brain.deinit();
|
|
}
|
|
self.characters.deinit();
|
|
}
|
|
|
|
pub fn step(self: *Artificer) !void {
|
|
if (self.paused_until) |paused_until| {
|
|
if (std.time.timestamp() < paused_until) {
|
|
return;
|
|
}
|
|
self.paused_until = null;
|
|
}
|
|
|
|
runNextActions(self.characters.items, &self.server) catch |err| switch (err) {
|
|
Api.Error.ServerUnavailable => {
|
|
self.paused_until = std.time.timestamp() + std.time.ns_per_min * server_down_retry_interval;
|
|
std.log.warn("Server is down, retrying in {}min", .{ server_down_retry_interval });
|
|
return;
|
|
},
|
|
else => return err
|
|
};
|
|
|
|
for (self.characters.items) |*brain| {
|
|
if (brain.action_queue.items.len > 0) continue;
|
|
|
|
if (brain.isTaskFinished()) {
|
|
if (try brain.depositItemsToBank(&self.server)) {
|
|
continue;
|
|
}
|
|
brain.task = null;
|
|
}
|
|
|
|
if (brain.task == null) {
|
|
// var next_tasks = try task_tree.listNextTasks();
|
|
// defer next_tasks.deinit();
|
|
//
|
|
// if (next_tasks.items.len > 0) {
|
|
// const next_task_index = random.intRangeLessThan(usize, 0, next_tasks.items.len);
|
|
// brain.task = next_tasks.items[next_task_index];
|
|
// }
|
|
}
|
|
|
|
try brain.performTask(&self.server);
|
|
}
|
|
}
|
|
|
|
pub fn nextStepAt(self: *Artificer) i64 {
|
|
if (self.paused_until) |paused_until| {
|
|
return paused_until;
|
|
}
|
|
|
|
return earliestCooldown(self.characters.items, &self.server) orelse 0;
|
|
}
|
|
|
|
fn earliestCooldown(characters: []CharacterBrain, api: *Api.Server) ?i64 {
|
|
var earliest_cooldown: ?i64 = null;
|
|
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);
|
|
|
|
if (earliest_cooldown == null or earliest_cooldown.? > cooldown) {
|
|
earliest_cooldown = cooldown;
|
|
}
|
|
}
|
|
|
|
return earliest_cooldown;
|
|
}
|
|
|
|
fn runNextActions(characters: []CharacterBrain, api: *Api.Server) !void {
|
|
const maybe_earliest_cooldown = earliestCooldown(characters, api);
|
|
if (maybe_earliest_cooldown == null) return;
|
|
|
|
const earliest_cooldown = maybe_earliest_cooldown.?;
|
|
if (earliest_cooldown < std.time.timestamp()) return;
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|