Fix bee targeting fail across wrap world edge
Previously, the bee always aimed for the light area, no matter where you actually put the target. It also got confused whenever it flew across the wrap world edge.
How the bee works now:
1) The placed bee target is *not* recalculated when it was placed in the "gray" part of the wrap world edge. This allows for more fine-tuning.
1a) Place target in light area: bee aims for target light area
1b) Place target in gray area: bee aims for target, but flies to gray area first
2) Bee target is recalculated whenever bee passes the wrap world edge.
use std::ffi::{ CString, CStr, OsStr };
use std::io::Result;
use std::sync::{ Mutex };
use libc::{ c_int, c_char };
/// Keep track of the number of global contexts.
static mut NUM_CONTEXTS: usize = 0;
/// Utility
mod util;
/// File operations
pub mod file;
#[link(name = "physfs")]
extern {
// nonzero on success, zero on error.
fn PHYSFS_init(arg0: *const c_char) -> c_int;
// nonzero if initialized, zero if not.
fn PHYSFS_isInit() -> c_int;
// nonzero if success, zero if error.
fn PHYSFS_deinit() -> c_int;
// string if success, NULL if error.
fn PHYSFS_getLastError() -> *const c_char;
// nonzero if success, zero if error
fn PHYSFS_mount(new_dir: *const c_char, mount_point: *const c_char, append_to_path: c_int) -> c_int;
// nonzero if success, zero if error.
fn PHYSFS_setWriteDir(write_dir: *const c_char) -> c_int;
// nonzero on success, zero on error.
fn PHYSFS_mkdir(dir_name: *const c_char) -> c_int;
// Checks if a given path exists; returns nonzero if true
fn PHYSFS_exists(path: *const c_char) -> c_int;
// Checks if a given path is a directory; returns nonzero if true
fn PHYSFS_isDirectory(path: *const c_char) -> c_int;
}
/// The access point for PhysFS function calls.
pub struct PhysFSContext;
unsafe impl Send for PhysFSContext {}
impl PhysFSContext {
/// Creates a new PhysFS context.
pub fn new() -> Result<Self> {
let con = PhysFSContext;
match PhysFSContext::init() {
Err(e) => Err(e),
_ => {
// Everything's gone right so far
// now, increment the instance counter
println!("Inc");
unsafe {
NUM_CONTEXTS += 1;
}
// and return the newly created context
Ok(con)
}
}
}
/// initializes the PhysFS library.
fn init() -> Result<()> {
// Initializing multiple times throws an error. So let's not!
if PhysFSContext::is_init() { return Ok(()); }
let mut args = ::std::env::args();
let default_arg0 = "".to_string();
let arg0 = args.next().unwrap_or(default_arg0);
let c_arg0 = try!(CString::new(arg0));
let ret = unsafe { PHYSFS_init(c_arg0.as_ptr()) };
match ret {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
/// Checks if PhysFS is initialized
pub fn is_init() -> bool {
unsafe { PHYSFS_isInit() != 0 }
}
/// De-initializes PhysFS. It is recommended to close
/// all file handles manually before calling this.
fn de_init() {
// de_init'ing more than once can cause a double-free -- do not want.
if !PhysFSContext::is_init() { return }
unsafe {
PHYSFS_deinit();
}
}
/// Adds an archive or directory to the search path.
/// mount_point is the location in the tree to mount it to.
pub fn mount<P>(&self, new_dir: P, mount_point: String, append_to_path: bool) -> Result<()>
where P: AsRef<OsStr>
{
let c_new_dir = CString::new(new_dir.as_ref().to_string_lossy().as_bytes()).unwrap();
let c_mount_point = try!(CString::new(mount_point));
match unsafe {
PHYSFS_mount(
c_new_dir.as_c_str().as_ptr(),
c_mount_point.as_ptr(),
append_to_path as c_int
)
} {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
/// Gets the last error message in a human-readable format
/// This message may be localized, so do not expect it to
/// match a specific string of characters.
pub fn get_last_error() -> String {
let ptr: *const c_char = unsafe {
PHYSFS_getLastError()
};
if ptr.is_null() {
return "".to_string()
}
let buf = unsafe { CStr::from_ptr(ptr).to_bytes().to_vec() };
String::from_utf8(buf).unwrap()
}
/// Sets a new write directory.
/// This method will fail if the current write dir
/// still has open files in it.
pub fn set_write_dir<P>(&self, write_dir: P) -> Result<()>
where P: AsRef<OsStr>
{
let write_dir = CStr::from_bytes_with_nul(write_dir.as_ref().to_str().unwrap().as_bytes()).unwrap();
let ret = unsafe {
PHYSFS_setWriteDir(write_dir.as_ptr())
};
match ret {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
/// Creates a new dir relative to the write_dir.
pub fn mkdir(&self, dir_name: &str) -> Result<()> {
let c_dir_name = try!(CString::new(dir_name));
let ret = unsafe {
PHYSFS_mkdir(c_dir_name.as_ptr())
};
match ret {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
/// Checks if given path exists
pub fn exists(&self, path: &str) -> Result<()> {
let c_path = try!(CString::new(path));
let ret = unsafe { PHYSFS_exists(c_path.as_ptr()) };
match ret {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
/// Checks if given path is a directory
pub fn is_directory(&self, path: &str) -> Result<()> {
let c_path = try!(CString::new(path));
let ret = unsafe { PHYSFS_isDirectory(c_path.as_ptr()) };
match ret {
0 => Err(util::physfs_error_as_io_error()),
_ => Ok(())
}
}
}
impl Drop for PhysFSContext {
fn drop(&mut self) {
// decrement NUM_CONTEXTS
unsafe {
NUM_CONTEXTS -= 1;
}
// and de_init if there aren't any contexts left.
if unsafe { NUM_CONTEXTS == 0 } {
PhysFSContext::de_init();
}
}
}