#pragma once #include #include #include #include #include #include "Tile.h" #include "Item.h" #include "WorldGen.h" #include "Entity.h" #include "Collection.h" #include "OS.h" #include "util.h" namespace Swan { class ModWrapper; class Mod { public: Mod(std::string name): name_(std::move(name)) {} virtual ~Mod() = default; void registerTile(Tile::Builder tile) { tiles_.push_back(tile); } void registerItem(Item::Builder item) { items_.push_back(item); } void registerSprite(std::string sprite) { sprites_.push_back(sprite); } template void registerWorldGen(std::string name) { worldGens_.push_back(WorldGen::Factory{ .name = name, .create = [](World &world) -> std::unique_ptr { return std::make_unique(world); } }); } template void registerEntity(const std::string &name) { static_assert( std::is_move_constructible_v, "Entities must be movable"); entities_.push_back(EntityCollection::Factory{ .name = name, .create = [](std::string name) -> std::unique_ptr { return std::make_unique>(std::move(name)); } }); } private: const std::string name_; std::vector tiles_; std::vector items_; std::vector sprites_; std::vector worldGens_; std::vector entities_; friend ModWrapper; }; class ModWrapper { public: ModWrapper(std::unique_ptr mod, std::string path, OS::Dynlib lib): mod_(std::move(mod)), path_(std::move(path)), dynlib_(std::move(lib)) {} ModWrapper(ModWrapper &&other) noexcept = default; ~ModWrapper() { // Mod::~Mod will destroy stuff allocated by the dynlib, // so we must run its destructor before deleting the dynlib mod_.reset(); } const std::string &name() { return mod_->name_; } const std::vector &tiles() { return mod_->tiles_; } const std::vector &items() { return mod_->items_; } const std::vector &sprites() { return mod_->sprites_; } const std::vector &worldGens() { return mod_->worldGens_; } const std::vector &entities() { return mod_->entities_; } std::unique_ptr mod_; std::string path_; OS::Dynlib dynlib_; }; }