use {
objects::{HasId, RoomObject, SizedRoomObject},
traits::TryInto,
ConversionError,
};
pub mod cpu {
use std::collections;
use constants::ReturnCode;
#[derive(Default, Serialize, Deserialize)]
pub struct HeapStatistics {
pub total_heap_size: u32,
pub total_heap_size_executable: u32,
pub total_physical_size: u32,
pub used_heap_size: u32,
pub heap_size_limit: u32,
pub malloced_memory: u32,
pub peak_malloced_memory: u32,
pub does_zap_garbage: u32,
pub externally_allocated_size: u32,
}
js_serializable!(HeapStatistics);
js_deserializable!(HeapStatistics);
pub fn limit() -> f64 {
js_unwrap!(Game.cpu.limit)
}
pub fn tick_limit() -> f64 {
js_unwrap!(Game.cpu.tickLimit)
}
pub fn bucket() -> f64 {
js_unwrap!(Game.cpu.bucket)
}
pub fn shard_limits() -> collections::HashMap<String, f64> {
js_unwrap!(Game.cpu.shardLimits)
}
pub fn get_heap_statistics() -> HeapStatistics {
use stdweb::unstable::TryInto;
use stdweb::Value;
let heap_stats: Value =
js_unwrap!(Game.cpu.getHeapStatistics && Game.cpu.getHeapStatistics());
match heap_stats {
Value::Null | Value::Undefined | Value::Bool(false) => HeapStatistics::default(),
other => other.try_into().expect(
"expected Game.cpu.getHeapStatistics() to return an object with a known format",
),
}
}
pub fn get_used() -> f64 {
js_unwrap!(Game.cpu.getUsed())
}
pub fn set_shard_limits(limits: collections::HashMap<String, f64>) -> ReturnCode {
js_unwrap!(Game.cpu.setShardLimits(@{limits}))
}
}
pub mod gcl {
pub fn level() -> u32 {
js_unwrap!(Game.gcl.level)
}
pub fn progress() -> f64 {
js_unwrap!(Game.gcl.progress)
}
pub fn progress_total() -> f64 {
js_unwrap!(Game.gcl.progressTotal)
}
}
pub mod map {
use std::{collections, mem};
use stdweb::Value;
use {
constants::{find::Exit, Direction, ReturnCode},
objects::RoomTerrain,
traits::{TryFrom, TryInto},
};
pub fn describe_exits(room_name: &str) -> collections::HashMap<Direction, String> {
use num_traits::FromPrimitive;
let orig: collections::HashMap<String, String> =
js_unwrap!(Game.map.describeExits(@{room_name}));
orig.into_iter()
.map(|(key, value)| {
let key: u32 = key.parse().expect(
"expected all directions returned from Game.map.describeExits to be integers",
);
(
Direction::from_u32(key).expect("expected all directions returned from Game.map.describeExits to be directions"),
value,
)
})
.collect()
}
pub fn get_room_linear_distance(room1: &str, room2: &str, continuous: bool) -> u32 {
js_unwrap!(Game.map.getRoomLinearDistance(@{room1}, @{room2}, @{continuous}))
}
pub fn get_room_terrain(room_name: &str) -> RoomTerrain {
js_unwrap!(Game.map.getRoomTerrain(@{room_name}))
}
pub fn get_world_size() -> u32 {
js_unwrap!(Game.map.getWorldSize())
}
pub fn is_room_available(room_name: &str) -> bool {
js_unwrap!(Game.map.isRoomAvailable(@{room_name}))
}
pub fn find_exit(from_room: &str, to_room: &str) -> Result<Exit, ReturnCode> {
let code: i32 = js_unwrap! {Game.map.findExit(@{from_room}, @{to_room})};
Exit::try_from(code)
.map_err(|v| v.try_into().expect("find_exit: Error code not recognized."))
}
pub fn find_exit_with_callback(
from_room: &str,
to_room: &str,
route_callback: impl Fn(String, String) -> f64,
) -> Result<Exit, ReturnCode> {
fn callback(room_name: String, from_room_name: String) -> f64 {
FR_CALLBACK.with(|callback| callback(room_name, from_room_name))
}
let callback_type_erased: Box<Fn(String, String) -> f64> = Box::new(route_callback);
let callback_lifetime_erased: Box<Fn(String, String) -> f64 + 'static> =
unsafe { mem::transmute(callback_type_erased) };
FR_CALLBACK.set(&callback_lifetime_erased, || {
let code: i32 = js_unwrap! {Game.map.findExit(@{from_room}, @{to_room}, @{callback})};
Exit::try_from(code)
.map_err(|v| v.try_into().expect("find_exit: Error code not recognized."))
})
}
pub fn find_route(from_room: &str, to_room: &str) -> Result<Vec<RoomRouteStep>, ReturnCode> {
let v = js!(return Game.map.findRoute(@{from_room}, @{to_room}););
parse_find_route_returned_value(v)
}
scoped_thread_local!(static FR_CALLBACK: Box<(Fn(String, String) -> f64)>);
pub fn find_route_with_callback(
from_room: &str,
to_room: &str,
route_callback: impl Fn(String, String) -> f64,
) -> Result<Vec<RoomRouteStep>, ReturnCode> {
fn callback(room_name: String, from_room_name: String) -> f64 {
FR_CALLBACK.with(|callback| callback(room_name, from_room_name))
}
let callback_type_erased: Box<Fn(String, String) -> f64> = Box::new(route_callback);
let callback_lifetime_erased: Box<Fn(String, String) -> f64 + 'static> =
unsafe { mem::transmute(callback_type_erased) };
FR_CALLBACK.set(&callback_lifetime_erased, || {
let v = js!(return Game.map.findRoute(@{from_room}, @{to_room}, @{callback}););
parse_find_route_returned_value(v)
})
}
fn parse_find_route_returned_value(v: Value) -> Result<Vec<RoomRouteStep>, ReturnCode> {
match v {
Value::Number(x) => {
let i: i32 = x.try_into().unwrap();
Err(i
.try_into()
.unwrap_or_else(|val| panic!("Unexpected return code: {}", val)))
}
Value::Reference(_) => Ok(v.try_into().expect("Error on parsing exit directions.")),
_ => panic!(
"Game.map.findRoute expected Number or Reference, found {:?}.",
v
),
}
}
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RoomRouteStep {
exit: Exit,
room: String,
}
js_deserializable!(RoomRouteStep);
}
pub mod market {
use std::collections::HashMap;
use stdweb::unstable::TryInto;
use constants::{ResourceType, ReturnCode};
use Room;
#[repr(u32)]
#[derive(Clone, Debug)]
pub enum OrderType {
Sell = 0,
Buy = 1,
}
#[derive(Deserialize, Debug)]
pub struct Player {
username: String,
}
js_deserializable!(Player);
#[derive(Deserialize, Debug)]
pub struct TransactionOrder {
id: String,
#[serde(rename = "type")]
order_type: String,
price: f64,
}
js_deserializable!(TransactionOrder);
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
transaction_id: String,
time: u32,
sender: Player,
recipient: Player,
resource_type: String,
amount: u32,
from: String,
to: String,
description: String,
order: Option<TransactionOrder>,
}
js_deserializable!(Transaction);
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Order {
id: String,
created: u32,
#[serde(rename = "type")]
order_type: String,
resource_type: String,
room_name: String,
amount: u32,
remaining_amount: u32,
price: f64,
}
js_deserializable!(Order);
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MyOrder {
id: String,
created: u32,
active: bool,
#[serde(rename = "type")]
order_type: String,
resource_type: String,
room_name: String,
amount: u32,
remaining_amount: u32,
total_amount: u32,
price: f64,
}
js_deserializable!(MyOrder);
pub fn credits() -> u32 {
js_unwrap!(Game.market.credits)
}
pub fn incoming_transactions() -> Vec<Transaction> {
let arr_transaction_value = js! {
return Game.market.incomingTransactions;
};
arr_transaction_value.try_into().unwrap()
}
pub fn outgoing_transactions() -> Vec<Transaction> {
let arr_transaction_value = js! {
return Game.market.outgoingTransactions;
};
arr_transaction_value.try_into().unwrap()
}
pub fn orders() -> HashMap<String, MyOrder> {
let order_book_value = js! {
return Game.market.orders;
};
order_book_value.try_into().unwrap()
}
pub fn calc_transaction_cost(amount: u32, room1: &Room, room2: &Room) -> u32 {
js_unwrap!(Game.market.calcTransactionCost(@{amount}, @{room1.name()}, @{room2.name()}))
}
pub fn cancel_order(order_id: &str) -> ReturnCode {
js_unwrap!(Game.market.cancelOrder(@{order_id}))
}
pub fn change_order_price(order_id: &str, new_price: u32) -> ReturnCode {
js_unwrap!(Game.market.changeOrderPrice(@{order_id}, @{new_price}))
}
pub fn create_order(
order_type: OrderType,
resource_type: ResourceType,
price: f64,
total_amount: u32,
room: &Room,
) -> ReturnCode {
js_unwrap! {
Game.market.createOrder(__order_type_num_to_str(@{order_type as u32}),
__resource_type_num_to_str(@{resource_type as u32}),
@{price},
@{total_amount},
@{room.name()})
}
}
pub fn deal(order_id: &str, amount: u32, target_room: &Room) -> ReturnCode {
js_unwrap! {Game.market.deal(@{order_id}, @{amount}, @{target_room.name()})}
}
pub fn extend_order(order_id: &str, add_amount: u32) -> ReturnCode {
js_unwrap! {Game.market.extendOrder(@{order_id}, @{add_amount})}
}
pub fn get_all_orders() -> Vec<Order> {
let all_order = js! {
return Game.market.getAllOrders();
};
all_order.try_into().unwrap()
}
pub fn get_order(id: &str) -> Option<Order> {
let order = js! {
return Game.marget.getOrder(@{id});
};
order.try_into().ok()
}
}
pub mod shard {
pub fn name() -> String {
js_unwrap!(Game.shard.name)
}
pub fn shard_type() -> String {
js_unwrap!(Game.shard.type)
}
pub fn ptr() -> bool {
js_unwrap!(Game.shard.ptr)
}
}
game_map_access! {
(construction_sites, objects::ConstructionSite, Game.constructionSites),
(creeps, objects::Creep, Game.creeps),
(flags, objects::Flag, Game.flags),
(rooms, objects::Room, Game.rooms),
(spawns, objects::StructureSpawn, Game.spawns),
(structures, objects::Structure, Game.structures)
}
pub fn time() -> u32 {
js_unwrap!(Game.time)
}
pub fn get_object_typed<T>(id: &str) -> Result<Option<T>, ConversionError>
where
T: HasId + SizedRoomObject,
{
js!(return Game.getObjectById(@{id});).try_into()
}
pub fn get_object_erased(id: &str) -> Option<RoomObject> {
js_unwrap_ref!(Game.getObjectById(@{id}))
}
pub fn notify(message: &str, group_interval: Option<u32>) {
js! {Game.notify(@{message}, @{group_interval.unwrap_or(0)})};
}