use core::mem::take;
use std::{error::Error, fs::DirEntry, fmt::Debug};
use bevy_app::{App, Plugin, PreStartup};
use bevy_ecs::world::World;
use bevy_reflect::{impl_from_reflect_opaque, impl_reflect_opaque, Reflect};
use bevy_utils::default;
use parking_lot::{lock_api::RawMutex as IRawMutex, RawMutex};
use toml::{Table, Value};
use crate::{
mod_loader::ModLoader,
mod_object::{
GlobalModConfig, Mod, ModDependency, ModInfo, ModState, ModVersion, ModVersionRequirement,
},
};
const _: () = {
#[allow(unused_mut)]
impl bevy_reflect::GetTypeRegistration for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration = bevy_reflect::TypeRegistration::of::<Self>();
registration.insert:: <bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType:: <Self> ::from_type());
registration.insert::<bevy_reflect::ReflectFromReflect>(
bevy_reflect::FromType::<Self>::from_type(),
);
registration
}
}
const _: () = {
mod private_scope {
type AssertIsPrimitive = super::ModLoaderPluginLock;
}
};
impl bevy_reflect::TypePath for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
fn type_path() -> &'static str {
"ModLoaderPluginLock"
}
fn short_type_path() -> &'static str {
"ModLoaderPluginLock"
}
fn type_ident() -> Option<&'static str> {
::core::option::Option::Some("ModLoaderPluginLock")
}
fn crate_name() -> Option<&'static str> {
::core::option::Option::None
}
fn module_path() -> Option<&'static str> {
::core::option::Option::None
}
}
impl bevy_reflect::Typed for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
#[inline]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(|| {
let info = bevy_reflect::OpaqueInfo::new::<Self>();
bevy_reflect::TypeInfo::Opaque(info)
})
}
}
impl bevy_reflect::Reflect for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
#[inline]
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
self
}
#[inline]
fn into_reflect(
self: ::std::boxed::Box<Self>,
) -> ::std::boxed::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(
&mut self,
value: ::std::boxed::Box<dyn bevy_reflect::Reflect>,
) -> ::core::result::Result<(), ::std::boxed::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl bevy_reflect::PartialReflect for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
#[inline]
fn get_represented_type_info(
&self,
) -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as bevy_reflect::Typed>::type_info())
}
#[inline]
fn clone_value(&self) -> ::std::boxed::Box<dyn bevy_reflect::PartialReflect> {
::std::boxed::Box::new(::core::clone::Clone::clone(self))
}
#[inline]
fn try_apply(
&mut self,
value: &dyn bevy_reflect::PartialReflect,
) -> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let ::core::option::Option::Some(value) =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value)
{
*self = ::core::clone::Clone::clone(value);
return ::core::result::Result::Ok(());
}
::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedTypes {
from_type: ::core::convert::Into::into(
bevy_reflect::DynamicTypePath::reflect_type_path(value),
),
to_type: ::core::convert::Into::into(<Self as bevy_reflect::TypePath>::type_path()),
})
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Opaque
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Opaque(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Opaque(self)
}
#[inline]
fn reflect_owned(self: ::std::boxed::Box<Self>) -> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Opaque(self)
}
#[inline]
fn try_into_reflect(
self: ::std::boxed::Box<Self>,
) -> ::core::result::Result<
::std::boxed::Box<dyn bevy_reflect::Reflect>,
::std::boxed::Box<dyn bevy_reflect::PartialReflect>,
> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self) -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self) -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(
self: ::std::boxed::Box<Self>,
) -> ::std::boxed::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self) -> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn bevy_reflect::PartialReflect {
self
}
}
impl bevy_reflect::FromReflect for ModLoaderPluginLock
where
ModLoaderPluginLock: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
{
fn from_reflect(
reflect: &dyn bevy_reflect::PartialReflect,
) -> ::core::option::Option<Self> {
::core::option::Option::Some(::core::clone::Clone::clone(
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<ModLoaderPluginLock>(
reflect,
)?,
))
}
}
};
#[doc(hidden )]
#[repr(transparent)]
struct ModLoaderPluginLock(RawMutex);
impl Debug for ModLoaderPluginLock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ModLoaderPluginLock")
}
}
impl Default for ModLoaderPluginLock {
fn default() -> Self {
Self(RawMutex::INIT)
}
}
impl Clone for ModLoaderPluginLock {
fn clone(&self) -> Self {
Self(RawMutex::INIT)
}
}
#[derive(Debug, Reflect, Default)]
pub struct ModLoaderPlugin {
pub mod_paths: Vec<String>,
pub mod_config: GlobalModConfig,
pub mods: Vec<Mod>,
#[allow(private_interfaces)]
pub lock: ModLoaderPluginLock,
}
#[allow(unreachable_code)]
#[allow(unused_variables)]
fn load_path(entry: DirEntry, app: &mut App) -> Result<(), Box<dyn Error>> {
let _null_str = Value::String(String::new());
let _null_arr = Value::Array(vec![]);
if entry.file_type()?.is_dir() {
let string = std::fs::read_to_string(entry.path().join("mod.toml"))?;
let mod_file = string.parse::<Table>()?;
let mod_info = ModInfo {
name: mod_file
.get("name")
.expect("missing name")
.as_str()
.expect("name is not a string")
.to_string(),
version: ModVersion::from_str(
mod_file
.get("version")
.expect("missing version")
.as_str()
.expect("version is not a string"),
),
description: mod_file
.get("description")
.unwrap_or_else(|| &_null_str)
.as_str()
.expect("description is not a string")
.to_string(),
author: mod_file
.get("author")
.unwrap_or_else(|| &_null_str)
.as_str()
.expect("author is not a string")
.to_string(),
mod_type: mod_file
.get("mod_type")
.unwrap_or_else(|| &_null_str)
.as_str()
.expect("mod_type is not a string")
.try_into()?,
dependencies: mod_file
.get("dependencies")
.unwrap_or_else(|| &_null_arr)
.as_array()
.expect("dependencies is not an array")
.iter()
.map(|v| {
let table = v.as_table().expect("dependency is not a table");
let dep_type = table
.get("type")
.unwrap_or_else(|| &_null_str)
.as_str()
.expect("type is not a string");
let name = table
.get("name")
.expect("missing name")
.as_str()
.expect("name is not a string")
.to_string();
let version;
if dep_type == "conflict" {
version = "0.0.0";
} else {
version = table
.get("version")
.unwrap_or_else(|| &_null_str)
.as_str()
.expect("version is not a string");
}
match dep_type {
"required" => ModDependency::Required {
name: name,
version: ModVersionRequirement::from_str(version),
},
"optional" => ModDependency::Optional {
name: name,
version: ModVersionRequirement::from_str(version),
},
"conflict" => ModDependency::Conflict(name),
_ => panic!("unknown dependency type"),
}
})
.collect(),
};
unimplemented!();
}
unimplemented!();
Ok(())
}
impl Plugin for ModLoaderPlugin {
fn is_unique(&self) -> bool {
false
}
fn build(&self, app: &mut App) {
unsafe {
self.lock.0.lock();
let mods = take((&raw const self.mods).cast_mut().as_mut().unwrap_unchecked());
app.world_mut().insert_resource(ModLoader {
config: self.mod_config.clone(),
mods,
..default()
});
self.lock.0.unlock();
}
app.add_systems(PreStartup, |world: &mut World| {
let unsafe_world = &raw mut *world;
let mut mod_loader;
unsafe {
mod_loader = unsafe_world
.as_mut()
.unwrap_unchecked()
.resource_mut::<ModLoader>();
}
mod_loader
.execute_stage(ModState::Prototype, world)
.and_then(|_| mod_loader.execute_stage(ModState::Data, world))
.and_then(|_| mod_loader.execute_stage(ModState::Modify, world))
.and_then(|_| mod_loader.execute_stage(ModState::Loaded, world))
.map(|_| {
bevy_utils::info(format!(
"Bevy Mod Loader loaded {} mods",
mod_loader.mods.len()
));
})
.unwrap_or_else(|e| {
bevy_utils::error(Err(format!("Mod loader failed to execute: {}", e)));
});
});
}
fn finish(&self, app: &mut App) {
for mod_path in &self.mod_paths {
bevy_utils::error(std::fs::read_dir(mod_path).map(|entries| {
entries
.filter_map(|entry| match entry {
Ok(entry) => Some(entry),
Err(e) => {
bevy_utils::error(Err(e));
None
}
})
.for_each(|entry| {
bevy_utils::error(load_path(entry, app));
});
}));
}
unsafe {
let unsafe_world = &raw mut *app.world_mut();
let mut mod_loader = unsafe_world
.as_mut()
.unwrap_unchecked()
.resource_mut::<ModLoader>();
mod_loader.build(app);
}
}
fn cleanup(&self, app: &mut App) {
unsafe {
let unsafe_world = &raw mut *app.world_mut();
let mut mod_loader = unsafe_world
.as_mut()
.unwrap_unchecked()
.resource_mut::<ModLoader>();
mod_loader.build_cleanup(app);
}
}
fn name(&self) -> &str {
"Bevy Mod Loader"
}
}