use std::fmt;
pub use winit;
#[cfg(feature = "audio")]
use crate::audio;
use crate::conf;
use crate::error::GameResult;
use crate::filesystem::Filesystem;
use crate::graphics;
use crate::graphics::GraphicsContext;
use crate::input;
use crate::timer;
pub struct Context {
pub fs: Filesystem,
pub gfx: GraphicsContext,
pub time: timer::TimeContext,
#[cfg(feature = "audio")]
pub audio: audio::AudioContext,
pub keyboard: input::keyboard::KeyboardContext,
pub mouse: input::mouse::MouseContext,
#[cfg(feature = "gamepad")]
pub gamepad: input::gamepad::GamepadContext,
pub(crate) conf: conf::Conf,
pub continuing: bool,
pub quit_requested: bool,
}
impl Context {
pub fn request_quit(&mut self) {
self.quit_requested = true;
}
}
pub trait Has<T> {
fn retrieve(&self) -> &T;
}
impl<T> Has<T> for T {
#[inline]
fn retrieve(&self) -> &T {
self
}
}
impl Has<Filesystem> for Context {
#[inline]
fn retrieve(&self) -> &Filesystem {
&self.fs
}
}
impl Has<GraphicsContext> for Context {
#[inline]
fn retrieve(&self) -> &GraphicsContext {
&self.gfx
}
}
#[cfg(feature = "audio")]
impl Has<audio::AudioContext> for Context {
#[inline]
fn retrieve(&self) -> &audio::AudioContext {
&self.audio
}
}
pub trait HasMut<T> {
fn retrieve_mut(&mut self) -> &mut T;
}
impl<T> HasMut<T> for T {
#[inline]
fn retrieve_mut(&mut self) -> &mut T {
self
}
}
impl HasMut<GraphicsContext> for Context {
#[inline]
fn retrieve_mut(&mut self) -> &mut GraphicsContext {
&mut self.gfx
}
}
impl fmt::Debug for Context {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Context: {:p}>", self)
}
}
impl Context {
fn from_conf(
conf: conf::Conf,
fs: Filesystem,
) -> GameResult<(Context, winit::event_loop::EventLoop<()>)> {
#[cfg(feature = "audio")]
let audio_context = audio::AudioContext::new(&fs)?;
let events_loop = winit::event_loop::EventLoop::new();
let timer_context = timer::TimeContext::new();
let graphics_context = graphics::context::GraphicsContext::new(&events_loop, &conf, &fs)?;
let ctx = Context {
conf,
fs,
gfx: graphics_context,
continuing: true,
quit_requested: false,
time: timer_context,
#[cfg(feature = "audio")]
audio: audio_context,
keyboard: input::keyboard::KeyboardContext::new(),
mouse: input::mouse::MouseContext::new(),
#[cfg(feature = "gamepad")]
gamepad: input::gamepad::GamepadContext::new()?,
};
Ok((ctx, events_loop))
}
}
use std::borrow::Cow;
use std::path;
#[derive(Debug, Clone, PartialEq)]
pub struct ContextBuilder {
pub(crate) game_id: String,
pub(crate) author: String,
pub(crate) conf: conf::Conf,
pub(crate) resources_dir_name: String,
pub(crate) resources_zip_name: String,
pub(crate) paths: Vec<path::PathBuf>,
pub(crate) memory_zip_files: Vec<Cow<'static, [u8]>>,
pub(crate) load_conf_file: bool,
}
impl ContextBuilder {
pub fn new(game_id: &str, author: &str) -> Self {
Self {
game_id: game_id.to_string(),
author: author.to_string(),
conf: conf::Conf::default(),
resources_dir_name: "resources".to_string(),
resources_zip_name: "resources.zip".to_string(),
paths: vec![],
memory_zip_files: vec![],
load_conf_file: true,
}
}
#[must_use]
pub fn window_setup(mut self, setup: conf::WindowSetup) -> Self {
self.conf.window_setup = setup;
self
}
#[must_use]
pub fn window_mode(mut self, mode: conf::WindowMode) -> Self {
self.conf.window_mode = mode;
self
}
#[must_use]
pub fn backend(mut self, backend: conf::Backend) -> Self {
self.conf.backend = backend;
self
}
#[must_use]
pub fn default_conf(mut self, conf: conf::Conf) -> Self {
self.conf = conf;
self
}
#[must_use]
pub fn resources_dir_name(mut self, new_name: impl ToString) -> Self {
self.resources_dir_name = new_name.to_string();
self
}
#[must_use]
pub fn resources_zip_name(mut self, new_name: impl ToString) -> Self {
self.resources_zip_name = new_name.to_string();
self
}
#[must_use]
pub fn add_resource_path<T>(mut self, path: T) -> Self
where
T: Into<path::PathBuf>,
{
self.paths.push(path.into());
self
}
#[must_use]
pub fn add_zipfile_bytes<B>(mut self, bytes: B) -> Self
where
B: Into<Cow<'static, [u8]>>,
{
let cow = bytes.into();
self.memory_zip_files.push(cow);
self
}
#[must_use]
pub fn with_conf_file(mut self, load_conf_file: bool) -> Self {
self.load_conf_file = load_conf_file;
self
}
pub fn build(self) -> GameResult<(Context, winit::event_loop::EventLoop<()>)> {
let fs = Filesystem::new(
self.game_id.as_ref(),
self.author.as_ref(),
&self.resources_dir_name,
&self.resources_zip_name,
)?;
for path in &self.paths {
fs.mount(path, true);
}
for zipfile_bytes in self.memory_zip_files {
fs.add_zip_file(std::io::Cursor::new(zipfile_bytes))?;
}
let config = if self.load_conf_file {
fs.read_config().unwrap_or(self.conf)
} else {
self.conf
};
Context::from_conf(config, fs)
}
}
#[deprecated(
since = "0.8.0",
note = "Use [`ctx.request_quit`](struct.Context.html#method.request_quit) instead."
)]
pub fn quit(ctx: &mut Context) {
ctx.continuing = false;
}
#[cfg(test)]
mod tests {
use crate::{
context::{Has, HasMut},
graphics::GraphicsContext,
ContextBuilder,
};
#[test]
fn has_traits() {
let (mut ctx, _event_loop) = ContextBuilder::new("test", "ggez").build().unwrap();
fn takes_gfx(_gfx: &impl Has<GraphicsContext>) {}
takes_gfx(&ctx);
takes_gfx(&ctx.gfx);
fn takes_mut_gfx(_gfx: &mut impl HasMut<GraphicsContext>) {}
takes_mut_gfx(&mut ctx);
takes_mut_gfx(&mut ctx.gfx);
}
}