@@ -3,9 +3,9 @@ | |||
EntPlayer::EntPlayer(const Swan::Context &ctx, const Swan::SRF ¶ms): | |||
PhysicsEntity(SIZE, MASS), | |||
anims_{ | |||
Swan::Animation(ctx.world.getImage("core::player-still"), 0.8), | |||
Swan::Animation(ctx.world.getImage("core::player-running"), 1), | |||
Swan::Animation(ctx.world.getImage("core::player-running"), 1, Swan::Animation::Flags::HFLIP) } { | |||
Swan::Animation(ctx.resources.getImage("core::player-still"), 0.8), | |||
Swan::Animation(ctx.resources.getImage("core::player-running"), 1), | |||
Swan::Animation(ctx.resources.getImage("core::player-running"), 1, Swan::Animation::Flags::HFLIP) } { | |||
readSRF(ctx, params); | |||
} |
@@ -4,8 +4,9 @@ add_library(libswan SHARED | |||
src/Chunk.cc | |||
src/Game.cc | |||
src/Item.cc | |||
src/Resource.cc | |||
src/Mod.cc | |||
src/OS.cc | |||
src/Resource.cc | |||
src/SRF.cc | |||
src/Tile.cc | |||
src/Timer.cc |
@@ -16,8 +16,6 @@ class Chunk { | |||
public: | |||
using RelPos = TilePos; | |||
ChunkPos pos_; | |||
Chunk(ChunkPos pos): pos_(pos) { | |||
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | |||
visuals_.reset(new Visuals()); | |||
@@ -38,6 +36,8 @@ public: | |||
bool keepActive(); // Returns true if chunk was inactive | |||
bool isActive() { return deactivate_timer_ > 0; } | |||
ChunkPos pos_; | |||
private: | |||
static constexpr float DEACTIVATE_INTERVAL = 20; | |||
static uint8_t *renderbuf; |
@@ -5,6 +5,7 @@ | |||
#include <string> | |||
#include "common.h" | |||
#include "Mod.h" | |||
#include "World.h" | |||
namespace Swan { | |||
@@ -15,7 +16,8 @@ public: | |||
win_(win), | |||
mouse_pos_(0, 0) {} | |||
void createWorld(const std::string &worldgen); | |||
std::unique_ptr<Mod> loadMod(const std::string &path); | |||
void createWorld(const std::string &worldgen, std::vector<std::unique_ptr<Mod>> &&mods); | |||
void onKeyDown(SDL_Keysym sym) { pressed_keys_[sym.scancode] = true; } | |||
void onKeyUp(SDL_Keysym sym) { pressed_keys_[sym.scancode] = false; } |
@@ -6,6 +6,7 @@ | |||
namespace Swan { | |||
// TODO: Switch to struct | |||
class Item { | |||
public: | |||
struct Builder { | |||
@@ -13,8 +14,8 @@ public: | |||
std::string image; | |||
}; | |||
Item(const ImageResource &image, const std::string &mod, const Builder &builder): | |||
name_(mod+"::"+builder.name), image_(image) {} | |||
Item(const ResourceManager &resources, const Builder &builder): | |||
name_(builder.name), image_(resources.getImage(builder.image)) {} | |||
const std::string name_; | |||
const ImageResource &image_; |
@@ -11,28 +11,38 @@ | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Resource.h" | |||
#include "util.h" | |||
namespace Swan { | |||
class Mod { | |||
public: | |||
Mod(const std::string &path, SDL_Renderer *renderer): path_(path), renderer_(renderer) {} | |||
void init(const std::string &name); | |||
void registerImage(const std::string &name, const std::string &path, int frame_height = -1); | |||
void registerTile(const Tile::Builder &tile); | |||
void registerItem(const Item::Builder &item); | |||
void registerTile(Tile::Builder tile); | |||
void registerItem(Item::Builder item); | |||
void registerWorldGen(const std::string &name, std::unique_ptr<WorldGen::Factory> gen); | |||
void registerEntity(const std::string &name, std::unique_ptr<Entity::Factory> ent); | |||
std::string name_; | |||
std::string path_; | |||
Iter<std::unique_ptr<Tile>> buildTiles(const ResourceManager &resources); | |||
Iter<std::unique_ptr<Item>> buildItems(const ResourceManager &resources); | |||
Iter<WorldGen::Factory *> getWorldGens(); | |||
Iter<Entity::Factory *> getEntities(); | |||
std::string name_ = "@uninitialized"; | |||
std::unordered_map<std::string, std::unique_ptr<ImageResource>> images_; | |||
std::unordered_map<std::string, Tile::Builder> tiles_; | |||
std::unordered_map<std::string, Item::Builder> items_; | |||
std::unordered_map<std::string, std::unique_ptr<WorldGen::Factory>> worldgens_; | |||
std::unordered_map<std::string, std::unique_ptr<Entity::Factory>> entities_; | |||
private: | |||
std::vector<std::unique_ptr<ImageResource>> images_; | |||
std::vector<Tile::Builder> tiles_; | |||
std::vector<Item::Builder> items_; | |||
std::vector<std::unique_ptr<WorldGen::Factory>> worldgens_; | |||
std::vector<std::unique_ptr<Entity::Factory>> entities_; | |||
std::string path_; | |||
SDL_Renderer *renderer_; | |||
bool inited_ = false; | |||
}; |
@@ -0,0 +1,21 @@ | |||
#pragma once | |||
#include <string> | |||
namespace Swan { | |||
namespace OS { | |||
class Dynlib { | |||
public: | |||
Dynlib(const std::string &path); | |||
~Dynlib(); | |||
template<typename T> T get(const std::string &name) { return (T)getVoid(name); } | |||
void *getVoid(const std::string &name); | |||
private: | |||
void *handle_; | |||
}; | |||
} | |||
} |
@@ -4,6 +4,7 @@ | |||
#include <stdint.h> | |||
#include <string> | |||
#include <memory> | |||
#include <unordered_map> | |||
#include "common.h" | |||
@@ -18,9 +19,10 @@ public: | |||
SDL_Renderer *renderer, const std::string &name, | |||
int w, int h, uint8_t r, uint8_t g, uint8_t b); | |||
void tick(float dt); | |||
static std::unique_ptr<ImageResource> createInvalid(Context &ctx); | |||
std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, &SDL_FreeSurface}; | |||
std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, &SDL_DestroyTexture}; | |||
int frame_height_; | |||
@@ -28,11 +30,22 @@ public: | |||
std::string name_; | |||
int frame_ = 0; | |||
static std::unique_ptr<ImageResource> createInvalid(Context &ctx); | |||
private: | |||
float switch_interval_ = 1; | |||
float switch_timer_ = switch_interval_; | |||
}; | |||
class ResourceManager { | |||
public: | |||
void tick(float dt); | |||
ImageResource &getImage(const std::string &name) const; | |||
void addImage(std::string name, std::unique_ptr<ImageResource> img); | |||
std::unique_ptr<ImageResource> invalid_image_; | |||
private: | |||
std::unordered_map<std::string, std::unique_ptr<ImageResource>> images_; | |||
}; | |||
} |
@@ -10,6 +10,7 @@ | |||
namespace Swan { | |||
// TODO: Switch to struct | |||
class Tile { | |||
public: | |||
using ID = uint16_t; | |||
@@ -21,8 +22,8 @@ public: | |||
std::optional<std::string> dropped_item = std::nullopt; | |||
}; | |||
Tile(const ImageResource &image, const std::string &mod, const Builder &builder): | |||
name_(mod+"::"+builder.name), image_(image), | |||
Tile(const ResourceManager &resources, const Builder &builder): | |||
name_(builder.name), image_(resources.getImage(builder.image)), | |||
is_solid_(builder.is_solid), dropped_item_(builder.dropped_item) {} | |||
const std::string name_; |
@@ -12,6 +12,7 @@ | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Resource.h" | |||
#include "Mod.h" | |||
namespace Swan { | |||
@@ -21,33 +22,36 @@ class World { | |||
public: | |||
World(Game *game, unsigned long rand_seed): game_(game), random_(rand_seed) {} | |||
WorldPlane &addPlane(const std::string &gen); | |||
WorldPlane &addPlane() { return addPlane(default_world_gen_); } | |||
void setCurrentPlane(WorldPlane &plane); | |||
void addMod(std::unique_ptr<Mod> mod); | |||
void setWorldGen(const std::string &gen); | |||
void spawnPlayer(); | |||
void registerTile(std::shared_ptr<Tile> t); | |||
void registerItem(std::shared_ptr<Item> i); | |||
void registerWorldGen(std::shared_ptr<WorldGen::Factory> gen); | |||
void registerEntity(std::shared_ptr<Entity::Factory> ent); | |||
void registerImage(std::shared_ptr<ImageResource> i); | |||
void setCurrentPlane(WorldPlane &plane); | |||
WorldPlane &addPlane(const std::string &gen); | |||
WorldPlane &addPlane() { return addPlane(default_world_gen_); } | |||
Tile &getTileByID(Tile::ID id); | |||
Tile::ID getTileID(const std::string &name); | |||
Tile &getTile(const std::string &name); | |||
Item &getItem(const std::string &name); | |||
ImageResource &getImage(const std::string &name); | |||
void draw(Win &win); | |||
void update(float dt); | |||
void tick(float dt); | |||
std::vector<std::shared_ptr<Tile>> tiles_; | |||
std::map<std::string, Tile::ID> tiles_map_; | |||
std::map<std::string, std::shared_ptr<Item>> items_; | |||
std::map<std::string, std::shared_ptr<WorldGen::Factory>> worldgens_; | |||
std::map<std::string, std::shared_ptr<Entity::Factory>> ents_; | |||
std::map<std::string, std::shared_ptr<ImageResource>> images_; | |||
std::vector<std::unique_ptr<Mod>> mods_; | |||
// World owns tiles and items, the mod just has Builder objects | |||
std::vector<std::unique_ptr<Tile>> tiles_; | |||
std::unordered_map<std::string, Tile::ID> tiles_map_; | |||
std::unordered_map<std::string, std::unique_ptr<Item>> items_; | |||
// The mods themselves retain ownership of world gens and entities, | |||
// the world just has non-owning pointers to them | |||
std::unordered_map<std::string, WorldGen::Factory *> worldgens_; | |||
std::unordered_map<std::string, Entity::Factory *> ents_; | |||
ResourceManager resources_; | |||
Entity *player_; | |||
Game *game_; | |||
@@ -19,11 +19,13 @@ class Game; | |||
class World; | |||
class WorldPlane; | |||
class Win; | |||
class ResourceManager; | |||
struct Context { | |||
Game &game; | |||
World &world; | |||
WorldPlane &plane; | |||
ResourceManager &resources; | |||
}; | |||
} |
@@ -0,0 +1,71 @@ | |||
#pragma once | |||
#include <optional> | |||
#include <functional> | |||
namespace Swan { | |||
// Ret can't be a reference, because C++ doesn't support optional<T&>. | |||
template<typename Ret, typename Func = std::function<std::optional<Ret>()>> | |||
class Iter { | |||
public: | |||
class It { | |||
public: | |||
It(std::optional<Ret> next, Func &func): next_(std::move(next)), func_(func) {} | |||
bool operator==(It &other) { | |||
return next_ == std::nullopt && other.next_ == std::nullopt; | |||
} | |||
bool operator!=(It &other) { | |||
return !(*this == other); | |||
} | |||
void operator++() { | |||
next_ = std::move(func_()); | |||
} | |||
Ret operator*() { | |||
return std::move(*next_); | |||
} | |||
private: | |||
std::optional<Ret> next_; | |||
Func &func_; | |||
}; | |||
Iter(Func func): func_(func) {} | |||
operator Iter<Ret, std::function<std::optional<Ret>()>>() { | |||
return Iter<Ret, std::function<std::optional<Ret>()>>(func_); | |||
} | |||
It begin() { | |||
return It(func_(), func_); | |||
} | |||
It end() { | |||
return It(std::nullopt, func_); | |||
} | |||
private: | |||
Func func_; | |||
}; | |||
template<typename InputIterator, typename Func> | |||
auto map(InputIterator first, InputIterator last, Func func) { | |||
using RetT = decltype(func(*first)); | |||
auto l = [=]() mutable -> std::optional<RetT> { | |||
if (first == last) | |||
return std::nullopt; | |||
RetT r = func(*first); | |||
first++; | |||
return r; | |||
}; | |||
return Iter<RetT, decltype(l)>(l); | |||
} | |||
} |
@@ -1,18 +1,36 @@ | |||
#include "Game.h" | |||
#include <dlfcn.h> | |||
#include <math.h> | |||
#include <time.h> | |||
#include <memory> | |||
#include "Tile.h" | |||
#include "OS.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
void Game::createWorld(const std::string &worldgen) { | |||
std::unique_ptr<Mod> Game::loadMod(const std::string &path) { | |||
OS::Dynlib dl(path + "/mod"); | |||
auto init = dl.get<void (*)(Swan::Mod &)>("mod_init"); | |||
if (init == NULL) { | |||
fprintf(stderr, "%s: No 'mod_init' function!\n", path.c_str()); | |||
return NULL; | |||
} | |||
std::unique_ptr<Mod> mod = std::make_unique<Mod>(path, win_.renderer_); | |||
init(*mod); | |||
return mod; | |||
} | |||
void Game::createWorld(const std::string &worldgen, std::vector<std::unique_ptr<Mod>> &&mods) { | |||
world_.reset(new World(this, time(NULL))); | |||
for (auto &mod: mods) { | |||
world_->addMod(std::move(mod)); | |||
} | |||
world_->setWorldGen(worldgen); | |||
world_->setCurrentPlane(world_->addPlane()); | |||
world_->spawnPlayer(); |
@@ -7,9 +7,9 @@ | |||
namespace Swan { | |||
std::unique_ptr<Item> Item::createInvalid(Context &ctx) { | |||
return std::make_unique<Item>(*ctx.game.invalid_image_, "@internal", Builder{ | |||
.name = "invalid", | |||
.image = "invalid", | |||
return std::make_unique<Item>(ctx.resources, Builder{ | |||
.name = "@internal::invalid", | |||
.image = "@internal::invalid", | |||
}); | |||
} | |||
@@ -1,6 +1,9 @@ | |||
#include "Mod.h" | |||
#include <stdio.h> | |||
#include <algorithm> | |||
#include "util.h" | |||
namespace Swan { | |||
@@ -12,31 +15,57 @@ void Mod::init(const std::string &name) { | |||
} | |||
void Mod::registerImage(const std::string &name, const std::string &path, int frame_height) { | |||
images_[name] = std::make_unique<ImageResource>( | |||
renderer_, name_ = "::" + name, path, frame_height); | |||
fprintf(stderr, "Adding image: %s\n", images_[name]->name_.c_str()); | |||
images_.push_back(std::make_unique<ImageResource>( | |||
renderer_, name_ + "::" + name, path_ + "/assets/" + path, frame_height)); | |||
fprintf(stderr, "Adding image: %s\n", (name_ + "::" + name).c_str()); | |||
} | |||
void Mod::registerTile(const Tile::Builder &tile) { | |||
tiles_[tile.name] = tile; | |||
fprintf(stderr, "Adding tile: %s::%s\n", name_.c_str(), tile.name.c_str()); | |||
void Mod::registerTile(Tile::Builder tile) { | |||
tile.name = name_ + "::" + tile.name; | |||
tiles_.push_back(tile); | |||
fprintf(stderr, "Adding tile: %s\n", tile.name.c_str()); | |||
} | |||
void Mod::registerItem(const Item::Builder &item) { | |||
items_[item.name] = item; | |||
fprintf(stderr, "Adding item: %s::%s\n", name_.c_str(), item.name.c_str()); | |||
void Mod::registerItem(Item::Builder item) { | |||
item.name = name_ + "::" + item.name; | |||
items_.push_back(item); | |||
fprintf(stderr, "Adding item: %s\n", item.name.c_str()); | |||
} | |||
void Mod::registerWorldGen(const std::string &name, std::unique_ptr<WorldGen::Factory> gen) { | |||
gen->name_ = name_ + "::" + name; | |||
fprintf(stderr, "Adding world gen: %s\n", gen->name_.c_str()); | |||
worldgens_[name] = std::move(gen); | |||
worldgens_.push_back(std::move(gen)); | |||
} | |||
void Mod::registerEntity(const std::string &name, std::unique_ptr<Entity::Factory> ent) { | |||
ent->name_ = name_ + "::" + name; | |||
fprintf(stderr, "Adding entity: %s\n",ent->name_.c_str()); | |||
entities_[name] = std::move(ent); | |||
entities_.push_back(std::move(ent)); | |||
} | |||
Iter<std::unique_ptr<Tile>> Mod::buildTiles(const ResourceManager &resources) { | |||
return map(begin(tiles_), end(tiles_), [&](const Tile::Builder &builder) { | |||
return std::make_unique<Tile>(resources, builder); | |||
}); | |||
} | |||
Iter<std::unique_ptr<Item>> Mod::buildItems(const ResourceManager &resources) { | |||
return map(begin(items_), end(items_), [&](const Item::Builder &builder) { | |||
return std::make_unique<Item>(resources, builder); | |||
}); | |||
} | |||
Iter<WorldGen::Factory *> Mod::getWorldGens() { | |||
return map(begin(worldgens_), end(worldgens_), [](const std::unique_ptr<WorldGen::Factory> &gen) { | |||
return gen.get(); | |||
}); | |||
} | |||
Iter<Entity::Factory *> Mod::getEntities() { | |||
return map(begin(entities_), end(entities_), [](const std::unique_ptr<Entity::Factory> &ent){ | |||
return ent.get(); | |||
}); | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
#include "OS.h" | |||
#include <stdexcept> | |||
#include <unistd.h> | |||
#include <dlfcn.h> | |||
namespace Swan { | |||
namespace OS { | |||
Dynlib::Dynlib(const std::string &path) { | |||
handle_ = dlopen((path + ".so").c_str(), RTLD_LAZY); | |||
if (handle_ == NULL) { | |||
throw std::runtime_error(dlerror()); | |||
} | |||
} | |||
Dynlib::~Dynlib() { | |||
dlclose(handle_); | |||
} | |||
void *Dynlib::getVoid(const std::string &name) { | |||
return dlsym(handle_, name.c_str()); | |||
} | |||
} | |||
} |
@@ -67,4 +67,17 @@ std::unique_ptr<ImageResource> ImageResource::createInvalid(Context &ctx) { | |||
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE); | |||
} | |||
void ResourceManager::tick(float dt) { | |||
for (auto &[k, v]: images_) { | |||
v->tick(dt); | |||
} | |||
} | |||
ImageResource &ResourceManager::getImage(const std::string &name) const { | |||
auto it = images_.find(name); | |||
if (it == end(images_)) | |||
return *invalid_image_; | |||
return *it->second; | |||
} | |||
} |
@@ -8,9 +8,9 @@ namespace Swan { | |||
Tile::ID Tile::INVALID_ID = 0; | |||
std::unique_ptr<Tile> Tile::createInvalid(Context &ctx) { | |||
return std::make_unique<Tile>(*ctx.game.invalid_image_, "@internal", Builder{ | |||
.name = "invalid", | |||
.image = "invalid", | |||
return std::make_unique<Tile>(ctx.resources, Builder{ | |||
.name = "@internal::invalid", | |||
.image = "@internal::invalid", | |||
}); | |||
} | |||
@@ -9,6 +9,7 @@ static bool chunkLine(int l, WorldPlane &plane, ChunkPos &abspos, const Vec2i &d | |||
for (int i = 0; i < l; ++i) { | |||
plane.getChunk(abspos); | |||
// TODO: Fix this with a non-SFML clock implementation | |||
// Don't blow our frame budget on generating chunks, | |||
// but generate as many as possible within the budget | |||
//if (clock.getElapsedTime().asSeconds() > 1.0 / 100) | |||
@@ -32,48 +33,53 @@ void World::ChunkRenderer::tick(WorldPlane &plane, ChunkPos abspos) { | |||
} | |||
} | |||
void World::setCurrentPlane(WorldPlane &plane) { | |||
current_plane_ = plane.id_; | |||
} | |||
void World::addMod(std::unique_ptr<Mod> mod) { | |||
printf("World: Adding mod %s\n", mod->name_.c_str()); | |||
void World::setWorldGen(const std::string &gen) { | |||
default_world_gen_ = gen; | |||
} | |||
for (auto t: mod->buildTiles(resources_)) { | |||
Tile::ID id = tiles_.size(); | |||
tiles_map_[t->name_] = id; | |||
tiles_.push_back(std::move(t)); | |||
} | |||
void World::spawnPlayer() { | |||
player_ = &planes_[current_plane_].spawnPlayer(); | |||
} | |||
for (auto i: mod->buildItems(resources_)) { | |||
items_[i->name_] = std::move(i); | |||
} | |||
void World::registerTile(std::shared_ptr<Tile> t) { | |||
Tile::ID id = tiles_.size(); | |||
tiles_map_[t->name_] = id; | |||
tiles_.push_back(std::move(t)); | |||
} | |||
for (auto *gen: mod->getWorldGens()) { | |||
worldgens_[gen->name_] = gen; | |||
} | |||
for (auto *ent: mod->getEntities()) { | |||
ents_[ent->name_] = ent; | |||
} | |||
void World::registerItem(std::shared_ptr<Item> i) { | |||
items_[i->name_] = std::move(i); | |||
mods_.push_back(std::move(mod)); | |||
} | |||
void World::registerWorldGen(std::shared_ptr<WorldGen::Factory> gen) { | |||
worldgens_[gen->name_] = std::move(gen); | |||
void World::setWorldGen(const std::string &gen) { | |||
default_world_gen_ = gen; | |||
} | |||
void World::registerEntity(std::shared_ptr<Entity::Factory> ent) { | |||
ents_[ent->name_] = std::move(ent); | |||
void World::spawnPlayer() { | |||
player_ = &planes_[current_plane_].spawnPlayer(); | |||
} | |||
void World::registerImage(std::shared_ptr<ImageResource> i) { | |||
images_[i->name_] = std::move(i); | |||
void World::setCurrentPlane(WorldPlane &plane) { | |||
current_plane_ = plane.id_; | |||
} | |||
ImageResource &World::getImage(const std::string &name) { | |||
auto iter = images_.find(name); | |||
if (iter == images_.end()) { | |||
fprintf(stderr, "Tried to get non-existant asset ''%s'!\n", name.c_str()); | |||
WorldPlane &World::addPlane(const std::string &gen) { | |||
WorldPlane::ID id = planes_.size(); | |||
if (worldgens_.find(gen) == worldgens_.end()) { | |||
fprintf(stderr, "Tried to add plane with non-existant world gen '%s'!\n", | |||
gen.c_str()); | |||
abort(); | |||
} | |||
return *iter->second; | |||
WorldGen *g = worldgens_[gen]->create(*this); | |||
planes_.push_back(WorldPlane(id, this, std::shared_ptr<WorldGen>(g))); | |||
return planes_[id]; | |||
} | |||
Item &World::getItem(const std::string &name) { | |||
@@ -105,19 +111,6 @@ Tile &World::getTile(const std::string &name) { | |||
return getTileByID(id); | |||
} | |||
WorldPlane &World::addPlane(const std::string &gen) { | |||
WorldPlane::ID id = planes_.size(); | |||
if (worldgens_.find(gen) == worldgens_.end()) { | |||
fprintf(stderr, "Tried to add plane with non-existant world gen '%s'!\n", | |||
gen.c_str()); | |||
abort(); | |||
} | |||
WorldGen *g = worldgens_[gen]->create(*this); | |||
planes_.push_back(WorldPlane(id, this, std::shared_ptr<WorldGen>(g))); | |||
return planes_[id]; | |||
} | |||
void World::draw(Win &win) { | |||
auto bounds = *player_->getBounds(); | |||
win.cam_ = bounds.pos - (win.getSize() / 2) + (bounds.size / 2); |
@@ -27,7 +27,7 @@ static Chunk::RelPos relPos(TilePos pos) { | |||
} | |||
Context WorldPlane::getContext() { | |||
return { .game = *world_->game_, .world = *world_, .plane = *this }; | |||
return { .game = *world_->game_, .world = *world_, .plane = *this, .resources = world_->resources_ }; | |||
} | |||
Entity &WorldPlane::spawnEntity(const std::string &name, const SRF ¶ms) { |
@@ -0,0 +1,3 @@ | |||
#include "util.h" | |||
// This file is intentionally left blank. |
@@ -55,6 +55,9 @@ int main() { | |||
Win win(renderer.get()); | |||
Game game(win); | |||
std::vector<std::unique_ptr<Mod>> mods; | |||
mods.push_back(game.loadMod("core.mod")); | |||
game.createWorld("core::default", std::move(mods)); | |||
auto prevTime = std::chrono::steady_clock::now(); | |||