* reworked some resource loading and mod init stuff * texetures are now configured at runtime via .toml files * moved from SRF to messagepack * changed folder structures * added the fmt library (for later)opengl-renderer-broken
@@ -16,3 +16,6 @@ | |||
[submodule "third_party/imgui-plot"] | |||
path = third_party/imgui-plot | |||
url = https://github.com/soulthreads/imgui-plot.git | |||
[submodule "third_party/fmt"] | |||
path = third_party/fmt | |||
url = https://github.com/fmtlib/fmt.git |
@@ -39,7 +39,7 @@ endif() | |||
add_subdirectory(third_party) | |||
set(libraries imgui SDL2 SDL2_image dl z) | |||
set(libraries imgui fmt cpptoml msgpack SDL2 SDL2_image dl z) | |||
# We want to be able to use C++20 designated initializers, | |||
# but Clang doesn't support them yet. |
@@ -7,14 +7,16 @@ set_target_properties(core.mod PROPERTIES OUTPUT_NAME mod PREFIX "") | |||
target_link_libraries(core.mod libswan ${libraries}) | |||
set(assets | |||
assets/entities/player-still.png | |||
assets/entities/player-running.png | |||
assets/tiles/grass.png | |||
assets/tiles/air.png | |||
assets/tiles/stone.png | |||
assets/tiles/dirt.png | |||
assets/tiles/leaves.png | |||
assets/tiles/tree-trunk.png | |||
assets/entity/player-still.png | |||
assets/entity/player-still.toml | |||
assets/entity/player-running.png | |||
assets/entity/player-running.toml | |||
assets/tile/grass.png | |||
assets/tile/air.png | |||
assets/tile/stone.png | |||
assets/tile/dirt.png | |||
assets/tile/leaves.png | |||
assets/tile/tree-trunk.png | |||
assets/misc/background-cave.png) | |||
foreach(a ${assets}) | |||
configure_file("${a}" "${a}" COPYONLY) |
@@ -0,0 +1 @@ | |||
height = 64 |
@@ -0,0 +1 @@ | |||
height = 64 |
@@ -2,6 +2,8 @@ | |||
#include <algorithm> | |||
#include "entities/PlayerEntity.h" | |||
static int grassLevel(const siv::PerlinNoise &perlin, int x) { | |||
return (int)(perlin.noise(x / 50.0, 0) * 13); | |||
} | |||
@@ -72,9 +74,9 @@ void DefaultWorldGen::genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) { | |||
} | |||
} | |||
Swan::BodyTrait::HasBody *DefaultWorldGen::spawnPlayer(Swan::WorldPlane &plane) { | |||
Swan::BodyTrait::HasBody *DefaultWorldGen::spawnPlayer(const Swan::Context &ctx) { | |||
int x = 0; | |||
return dynamic_cast<Swan::BodyTrait::HasBody *>( | |||
plane.spawnEntity("core::player", Swan::SRFFloatArray{ | |||
(float)x, (float)grassLevel(perlin_, x) - 4 })); | |||
ctx.plane.spawnEntity(std::make_unique<PlayerEntity>( | |||
ctx, Swan::Vec2{ (float)x, (float)grassLevel(perlin_, x) - 4 }))); | |||
} |
@@ -6,11 +6,6 @@ | |||
class DefaultWorldGen: public Swan::WorldGen { | |||
public: | |||
class Factory: public Swan::WorldGen::Factory { | |||
public: | |||
WorldGen *create(Swan::World &world) override { return new DefaultWorldGen(world); } | |||
}; | |||
DefaultWorldGen(Swan::World &world): | |||
tGrass_(world.getTileID("core::grass")), | |||
tDirt_(world.getTileID("core::dirt")), | |||
@@ -18,12 +13,12 @@ public: | |||
tAir_(world.getTileID("core::air")), | |||
tTreeTrunk_(world.getTileID("core::tree-trunk")), | |||
tLeaves_(world.getTileID("core::leaves")), | |||
bgCave_(world.resources_.getImage("core::background-cave")) {} | |||
bgCave_(world.resources_.getImage("core/misc/background-cave")) {} | |||
void drawBackground(const Swan::Context &ctx, Swan::Win &win, Swan::Vec2 pos) override; | |||
SDL_Color backgroundColor(Swan::Vec2 pos) override; | |||
void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; | |||
Swan::BodyTrait::HasBody *spawnPlayer(Swan::WorldPlane &plane) override; | |||
Swan::BodyTrait::HasBody *spawnPlayer(const Swan::Context &ctx) override; | |||
private: | |||
Swan::Tile::ID genTile(Swan::TilePos pos); |
@@ -2,11 +2,11 @@ | |||
#include <random> | |||
ItemStackEntity::ItemStackEntity(const Swan::Context &ctx, const Swan::SRF ¶ms): | |||
ItemStackEntity::ItemStackEntity(const Swan::Context &ctx, const PackObject &obj): | |||
PhysicsEntity(SIZE, MASS) { | |||
PhysicsEntity::body_.bounciness_ = 0.6; | |||
readSRF(ctx, params); | |||
deserialize(ctx, obj); | |||
static std::uniform_real_distribution vx(-2.3f, 2.3f); | |||
static std::uniform_real_distribution vy(-2.3f, -1.2f); | |||
@@ -31,18 +31,14 @@ void ItemStackEntity::tick(const Swan::Context &ctx, float dt) { | |||
ctx.plane.despawnEntity(*this); | |||
} | |||
void ItemStackEntity::readSRF(const Swan::Context &ctx, const Swan::SRF &srf) { | |||
auto &arr = dynamic_cast<const Swan::SRFArray &>(srf); | |||
auto *pos = dynamic_cast<Swan::SRFFloatArray *>(arr.val[0].get()); | |||
auto *name = dynamic_cast<Swan::SRFString *>(arr.val[1].get()); | |||
body_.pos_.set(pos->val[0], pos->val[1]); | |||
item_ = &ctx.world.getItem(name->val); | |||
void ItemStackEntity::deserialize(const Swan::Context &ctx, const PackObject &obj) { | |||
body_.pos_ = obj.at("pos").as<Swan::Vec2>(); | |||
item_ = &ctx.world.getItem(obj.at("item").as<std::string>()); | |||
} | |||
Swan::SRF *ItemStackEntity::writeSRF(const Swan::Context &ctx) { | |||
return new Swan::SRFArray{ | |||
new Swan::SRFFloatArray{ body_.pos_.x, body_.pos_.y }, | |||
new Swan::SRFString{ item_->name_ }, | |||
Swan::Entity::PackObject ItemStackEntity::serialize(const Swan::Context &ctx, msgpack::zone &zone) { | |||
return { | |||
{ "pos", msgpack::object(body_.pos_, zone) }, | |||
{ "tile", msgpack::object(item_->name_, zone) }, | |||
}; | |||
} |
@@ -4,18 +4,12 @@ | |||
class ItemStackEntity: public Swan::PhysicsEntity { | |||
public: | |||
class Factory: public Swan::Entity::Factory { | |||
Swan::Entity *create(const Swan::Context &ctx, const Swan::SRF ¶ms) override { | |||
return new ItemStackEntity(ctx, params); | |||
} | |||
}; | |||
ItemStackEntity(const Swan::Context &ctx, const Swan::SRF ¶ms); | |||
ItemStackEntity(const Swan::Context &ctx, const PackObject &obj); | |||
void draw(const Swan::Context &ctx, Swan::Win &win) override; | |||
void tick(const Swan::Context &ctx, float dt) override; | |||
void readSRF(const Swan::Context &ctx, const Swan::SRF &srf) override; | |||
Swan::SRF *writeSRF(const Swan::Context &ctx) override; | |||
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; | |||
PackObject serialize(const Swan::Context &ctx, msgpack::zone &zone) override; | |||
private: | |||
static constexpr float MASS = 80; |
@@ -4,14 +4,24 @@ | |||
#include "ItemStackEntity.h" | |||
PlayerEntity::PlayerEntity(const Swan::Context &ctx, const Swan::SRF ¶ms): | |||
PlayerEntity::PlayerEntity(const Swan::Context &ctx, const PackObject &obj): | |||
PhysicsEntity(SIZE, MASS), inventory_(INVENTORY_SIZE), | |||
anims_{ | |||
Swan::Animation(ctx.resources.getImage("core::player-still"), 0.8), | |||
Swan::Animation(ctx.resources.getImage("core::player-running"), 1, SDL_FLIP_HORIZONTAL), | |||
Swan::Animation(ctx.resources.getImage("core::player-running"), 1) } { | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-still"), 0.8), | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-running"), 1, SDL_FLIP_HORIZONTAL), | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-running"), 1) } { | |||
readSRF(ctx, params); | |||
deserialize(ctx, obj); | |||
} | |||
PlayerEntity::PlayerEntity(const Swan::Context &ctx, Swan::Vec2 pos): | |||
PhysicsEntity(SIZE, MASS), inventory_(INVENTORY_SIZE), | |||
anims_{ | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-still"), 0.8), | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-running"), 1, SDL_FLIP_HORIZONTAL), | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-running"), 1) } { | |||
body_.pos_ = pos; | |||
} | |||
void PlayerEntity::draw(const Swan::Context &ctx, Swan::Win &win) { | |||
@@ -76,11 +86,15 @@ void PlayerEntity::tick(const Swan::Context &ctx, float dt) { | |||
} | |||
} | |||
void PlayerEntity::readSRF(const Swan::Context &ctx, const Swan::SRF &srf) { | |||
auto pos = dynamic_cast<const Swan::SRFFloatArray &>(srf); | |||
body_.pos_.set(pos.val[0], pos.val[1]); | |||
void PlayerEntity::deserialize(const Swan::Context &ctx, const PackObject &obj) { | |||
//body_.deserialize(obj["body"]); | |||
} | |||
Swan::SRF *PlayerEntity::writeSRF(const Swan::Context &ctx) { | |||
return new Swan::SRFFloatArray{ body_.pos_.x, body_.pos_.y }; | |||
Swan::Entity::PackObject PlayerEntity::serialize(const Swan::Context &ctx, msgpack::zone &zone) { | |||
return {}; | |||
/* | |||
return Swan::MsgPackObject{ | |||
{ "body", body_.serialize(w) }, | |||
}; | |||
*/ | |||
} |
@@ -5,22 +5,16 @@ | |||
class PlayerEntity: public Swan::PhysicsEntity, public Swan::InventoryTrait::HasInventory { | |||
public: | |||
class Factory: public Swan::Entity::Factory { | |||
public: | |||
Swan::Entity *create(const Swan::Context &ctx, const Swan::SRF ¶ms) override { | |||
return new PlayerEntity(ctx, params); | |||
} | |||
}; | |||
PlayerEntity(const Swan::Context &ctx, const Swan::SRF ¶ms); | |||
PlayerEntity(const Swan::Context &ctx, const PackObject &obj); | |||
PlayerEntity(const Swan::Context &ctx, Swan::Vec2 pos); | |||
Swan::InventoryTrait::Inventory &getInventory() override { return inventory_; } | |||
void draw(const Swan::Context &ctx, Swan::Win &win) override; | |||
void update(const Swan::Context &ctx, float dt) override; | |||
void tick(const Swan::Context &ctx, float dt) override; | |||
void readSRF(const Swan::Context &ctx, const Swan::SRF &srf) override; | |||
Swan::SRF *writeSRF(const Swan::Context &ctx) override; | |||
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; | |||
PackObject serialize(const Swan::Context &ctx, msgpack::zone &zone) override; | |||
private: | |||
static constexpr int INVENTORY_SIZE = 18; |
@@ -7,66 +7,65 @@ | |||
extern "C" void mod_init(Swan::Mod &mod) { | |||
mod.init("core"); | |||
mod.registerImage({ "air", "tiles/air.png" }); | |||
mod.registerImage({ "stone", "tiles/stone.png" }); | |||
mod.registerImage({ "dirt", "tiles/dirt.png" }); | |||
mod.registerImage({ "grass", "tiles/grass.png" }); | |||
mod.registerImage({ "tree-trunk", "tiles/tree-trunk.png" }); | |||
mod.registerImage({ "leaves", "tiles/leaves.png" }); | |||
mod.registerImage({ "player-running", "entities/player-running.png", 64 }); | |||
mod.registerImage({ "player-still", "entities/player-still.png", 64 }); | |||
mod.registerImage({ "background-cave", "misc/background-cave.png" }); | |||
mod.registerImage({ "background-cave-2", "misc/background-cave-2.png" }); | |||
mod.registerImage("tile/air"); | |||
mod.registerImage("tile/stone"); | |||
mod.registerImage("tile/dirt"); | |||
mod.registerImage("tile/grass"); | |||
mod.registerImage("tile/tree-trunk"); | |||
mod.registerImage("tile/leaves"); | |||
mod.registerImage("entity/player-running"); | |||
mod.registerImage("entity/player-still"); | |||
mod.registerImage("misc/background-cave"); | |||
mod.registerTile({ | |||
.name = "air", | |||
.image = "core::air", | |||
.image = "core/tile/air", | |||
.is_solid = false, | |||
}); | |||
mod.registerTile({ | |||
.name = "stone", | |||
.image = "core::stone", | |||
.image = "core/tile/stone", | |||
.dropped_item = "core::stone", | |||
}); | |||
mod.registerTile({ | |||
.name = "dirt", | |||
.image = "core::dirt", | |||
.image = "core/tile/dirt", | |||
.dropped_item = "core::dirt", | |||
}); | |||
mod.registerTile({ | |||
.name = "grass", | |||
.image = "core::grass", | |||
.image = "core/tile/grass", | |||
.dropped_item = "core::dirt", | |||
}); | |||
mod.registerTile({ | |||
.name = "tree-trunk", | |||
.image = "core::tree-trunk", | |||
.image = "core/tile/tree-trunk", | |||
.dropped_item = "core::tree-trunk", | |||
}); | |||
mod.registerTile({ | |||
.name = "leaves", | |||
.image = "core::leaves", | |||
.image = "core/tile/leaves", | |||
}); | |||
mod.registerItem({ | |||
.name = "stone", | |||
.image = "core::stone", | |||
.image = "core/tile/stone", | |||
}); | |||
mod.registerItem({ | |||
.name = "dirt", | |||
.image = "core::dirt", | |||
.image = "core/tile/dirt", | |||
}); | |||
mod.registerItem({ | |||
.name = "grass", | |||
.image = "core::grass", | |||
.image = "core/tile/grass", | |||
}); | |||
mod.registerItem({ | |||
.name = "tree-trunk", | |||
.image = "core::tree-trunk", | |||
.image = "core/tile/tree-trunk", | |||
}); | |||
mod.registerWorldGen("default", std::make_unique<DefaultWorldGen::Factory>()); | |||
mod.registerWorldGen<DefaultWorldGen>("default"); | |||
mod.registerEntity("player", std::make_unique<PlayerEntity::Factory>()); | |||
mod.registerEntity("item-stack", std::make_unique<ItemStackEntity::Factory>()); | |||
mod.registerEntity<PlayerEntity>("player"); | |||
mod.registerEntity<ItemStackEntity>("item-stack"); | |||
} |
@@ -12,7 +12,6 @@ add_library(libswan SHARED | |||
src/OS.cc | |||
src/PerfCounter.cc | |||
src/Resource.cc | |||
src/SRF.cc | |||
src/Tile.cc | |||
src/World.cc | |||
src/WorldPlane.cc) |
@@ -2,11 +2,11 @@ | |||
#include <memory> | |||
#include <optional> | |||
#include <msgpack.hpp> | |||
#include "common.h" | |||
#include "log.h" | |||
#include "traits/BodyTrait.h" | |||
#include "SRF.h" | |||
namespace Swan { | |||
@@ -16,11 +16,11 @@ class Game; | |||
class Entity { | |||
public: | |||
class Factory { | |||
public: | |||
virtual ~Factory() = default; | |||
virtual Entity *create(const Context &ctx, const SRF ¶ms) = 0; | |||
std::string name_; | |||
using PackObject = std::unordered_map<std::string_view, msgpack::object>; | |||
struct Factory { | |||
const std::string name; | |||
std::unique_ptr<Entity> (*create)(const Context &ctx, const PackObject &obj); | |||
}; | |||
virtual ~Entity() = default; | |||
@@ -30,8 +30,8 @@ public: | |||
virtual void tick(const Context &ctx, float dt) {} | |||
virtual void despawn() {} | |||
virtual void readSRF(const Swan::Context &ctx, const SRF &srf) {} | |||
virtual SRF *writeSRF(const Swan::Context &ctx) { return new SRFNone(); } | |||
virtual void deserialize(const Swan::Context &ctx, const PackObject &obj) {} | |||
virtual PackObject serialize(const Swan::Context &ctx, msgpack::zone &zone) { return {}; } | |||
}; | |||
class PhysicsEntity: public Entity, public BodyTrait::HasBody { |
@@ -27,26 +27,47 @@ public: | |||
void init(const std::string &name); | |||
void registerImage(ImageResource::Builder image); | |||
void registerImage(const std::string &id); | |||
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); | |||
template<typename WG> | |||
void registerWorldGen(const std::string &name) { | |||
worldgens_.push_back(WorldGen::Factory{ | |||
.name = name_ + "::" + name, | |||
.create = [](World &world) { | |||
return static_cast<std::unique_ptr<WorldGen>>( | |||
std::make_unique<WG>(world)); | |||
} | |||
}); | |||
} | |||
template<typename Ent> | |||
void registerEntity(const std::string &name) { | |||
entities_.push_back(Entity::Factory{ | |||
.name = name_ + "::" + name, | |||
.create = [](const Context &ctx, const Entity::PackObject &obj) { | |||
return static_cast<std::unique_ptr<Entity>>( | |||
std::make_unique<Ent>(ctx, obj)); | |||
} | |||
}); | |||
} | |||
Iter<std::unique_ptr<ImageResource>> buildImages(SDL_Renderer *renderer); | |||
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(); | |||
Iter<WorldGen::Factory> getWorldGens(); | |||
Iter<Entity::Factory> getEntities(); | |||
std::string name_ = "@uninitialized"; | |||
private: | |||
std::vector<ImageResource::Builder> images_; | |||
std::vector<std::string> 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::vector<WorldGen::Factory> worldgens_; | |||
std::vector<Entity::Factory> entities_; | |||
std::string path_; | |||
OS::Dynlib dynlib_; |
@@ -12,14 +12,8 @@ namespace Swan { | |||
class ImageResource { | |||
public: | |||
struct Builder { | |||
std::string name; | |||
std::string path; | |||
int frame_height = -1; | |||
std::string modpath = ""; | |||
}; | |||
ImageResource(SDL_Renderer *renderer, const Builder &builder); | |||
ImageResource( | |||
SDL_Renderer *renderer, const std::string &modpath, const std::string &id); | |||
ImageResource( | |||
SDL_Renderer *renderer, const std::string &name, | |||
int w, int h, uint8_t r, uint8_t g, uint8_t b); |
@@ -1,181 +0,0 @@ | |||
#pragma once | |||
#include <ostream> | |||
#include <istream> | |||
#include <vector> | |||
#include <unordered_map> | |||
#include <memory> | |||
#include <string> | |||
#include <initializer_list> | |||
#include <utility> | |||
#include <stdint.h> | |||
namespace Swan { | |||
struct SRF { | |||
virtual ~SRF() = default; | |||
virtual void serialize(std::ostream &os) const = 0; | |||
virtual void parse(std::istream &is) = 0; | |||
virtual std::ostream &pretty(std::ostream &os) const = 0; | |||
static SRF *read(std::istream &is); | |||
friend std::ostream &operator<<(std::ostream &os, const SRF &srf); | |||
}; | |||
struct SRFObject: SRF { | |||
SRFObject() {} | |||
SRFObject(std::initializer_list<std::pair<std::string, SRF *>> lst); | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::unordered_map<std::string, std::unique_ptr<SRF>> val; | |||
}; | |||
struct SRFArray: SRF { | |||
SRFArray() {} | |||
SRFArray(std::initializer_list<SRF *> lst); | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<std::unique_ptr<SRF>> val; | |||
}; | |||
struct SRFString: SRF { | |||
SRFString(): val("") {} | |||
SRFString(const std::string &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::string val; | |||
}; | |||
struct SRFByte: SRF { | |||
SRFByte(): val(0) {} | |||
SRFByte(uint8_t v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
uint8_t val; | |||
}; | |||
struct SRFWord: SRF { | |||
SRFWord(): val(0) {} | |||
SRFWord(uint16_t v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
uint16_t val; | |||
}; | |||
struct SRFInt: SRF { | |||
SRFInt(): val(0) {} | |||
SRFInt(int32_t v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
int32_t val; | |||
}; | |||
struct SRFFloat: SRF { | |||
SRFFloat(): val(0) {} | |||
SRFFloat(float v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
float val; | |||
}; | |||
struct SRFDouble: SRF { | |||
SRFDouble(): val(0) {} | |||
SRFDouble(double v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
double val; | |||
}; | |||
struct SRFNone: SRF { | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
}; | |||
struct SRFByteArray: SRF { | |||
SRFByteArray() = default; | |||
SRFByteArray(std::initializer_list<uint8_t> lst): val(lst) {} | |||
SRFByteArray(std::vector<uint8_t> &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<uint8_t> val; | |||
}; | |||
struct SRFWordArray: SRF { | |||
SRFWordArray() = default; | |||
SRFWordArray(std::initializer_list<uint16_t> v): val(v) {} | |||
SRFWordArray(std::vector<uint16_t> &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<uint16_t> val; | |||
}; | |||
struct SRFIntArray: SRF { | |||
SRFIntArray() = default; | |||
SRFIntArray(std::initializer_list<int> v): val(v) {} | |||
SRFIntArray(std::vector<int32_t> &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<int32_t> val; | |||
}; | |||
struct SRFFloatArray: SRF { | |||
SRFFloatArray() = default; | |||
SRFFloatArray(std::initializer_list<float> v): val(v) {} | |||
SRFFloatArray(std::vector<float> &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<float> val; | |||
}; | |||
struct SRFDoubleArray: SRF { | |||
SRFDoubleArray() = default; | |||
SRFDoubleArray(std::initializer_list<double> v): val(v) {} | |||
SRFDoubleArray(std::vector<double> &v): val(v) {} | |||
void serialize(std::ostream &os) const override; | |||
void parse(std::istream &os) override; | |||
std::ostream &pretty(std::ostream &os) const override; | |||
std::vector<double> val; | |||
}; | |||
} |
@@ -3,6 +3,7 @@ | |||
#include <utility> | |||
#include <ostream> | |||
#include <cmath> | |||
#include <msgpack.hpp> | |||
namespace Swan { | |||
@@ -11,6 +12,8 @@ struct Vector2 { | |||
T x; | |||
T y; | |||
MSGPACK_DEFINE(x, y) | |||
constexpr Vector2(T x = 0, T y = 0): x(x), y(y) {} | |||
constexpr Vector2<T> &set(T x, T y) { |
@@ -50,8 +50,8 @@ public: | |||
// 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_; | |||
std::unordered_map<std::string, WorldGen::Factory> worldgens_; | |||
std::unordered_map<std::string, Entity::Factory> ents_; | |||
BodyTrait::HasBody *player_; | |||
Game *game_; |
@@ -15,20 +15,11 @@ class World; | |||
class WorldPlane; | |||
class ImageResource; | |||
class WorldGenStructure { | |||
public: | |||
virtual ~WorldGenStructure() = 0; | |||
virtual bool isBase(TilePos pos); | |||
}; | |||
class WorldGen { | |||
public: | |||
class Factory { | |||
public: | |||
virtual ~Factory() = default; | |||
virtual WorldGen *create(World &world) = 0; | |||
std::string name_; | |||
struct Factory { | |||
const std::string name; | |||
std::unique_ptr<WorldGen> (*create)(World &world); | |||
}; | |||
virtual ~WorldGen() = default; | |||
@@ -37,7 +28,7 @@ public: | |||
virtual SDL_Color backgroundColor(Vec2 pos) = 0; | |||
virtual void genChunk(WorldPlane &plane, Chunk &chunk) = 0; | |||
virtual BodyTrait::HasBody *spawnPlayer(WorldPlane &plane) = 0; | |||
virtual BodyTrait::HasBody *spawnPlayer(const Context &ctx) = 0; | |||
}; | |||
} |
@@ -24,10 +24,11 @@ class WorldPlane: NonCopyable { | |||
public: | |||
using ID = uint16_t; | |||
WorldPlane(ID id, World *world, std::shared_ptr<WorldGen> gen): | |||
WorldPlane(ID id, World *world, std::unique_ptr<WorldGen> gen): | |||
id_(id), world_(world), gen_(std::move(gen)) {} | |||
Entity *spawnEntity(const std::string &name, const SRF ¶ms); | |||
Entity *spawnEntity(const std::string &name, const Entity::PackObject ¶ms); | |||
Entity *spawnEntity(std::unique_ptr<Entity> ent); | |||
void despawnEntity(Entity &ent); | |||
Context getContext(); | |||
@@ -62,7 +63,7 @@ public: | |||
ID id_; | |||
World *world_; | |||
std::shared_ptr<WorldGen> gen_; | |||
std::unique_ptr<WorldGen> gen_; | |||
private: | |||
std::map<std::pair<int, int>, Chunk> chunks_; |
@@ -13,7 +13,6 @@ | |||
#include <swan/PerfCounter.h> | |||
#include <swan/OS.h> | |||
#include <swan/Resource.h> | |||
#include <swan/SRF.h> | |||
#include <swan/Tile.h> | |||
#include <swan/Vector2.h> | |||
#include <swan/Win.h> |
@@ -68,7 +68,11 @@ public: | |||
} | |||
void operator++() { | |||
next_ = std::move(func_()); | |||
auto val(func_()); | |||
if (val) | |||
next_.emplace(std::move(*val)); | |||
else | |||
next_.reset(); | |||
} | |||
Ret operator*() { |
@@ -23,11 +23,9 @@ void Mod::init(const std::string &name) { | |||
info << "Mod initing: " << name_; | |||
} | |||
void Mod::registerImage(ImageResource::Builder image) { | |||
image.name = name_ + "::" + image.name; | |||
image.modpath = path_; | |||
images_.push_back(image); | |||
info << " Adding image: " << image.name << " (" << image.path << ')'; | |||
void Mod::registerImage(const std::string &id) { | |||
images_.push_back(name_ + "/" + id); | |||
info << " Adding image: " << images_.back(); | |||
} | |||
void Mod::registerTile(Tile::Builder tile) { | |||
@@ -42,21 +40,9 @@ void Mod::registerItem(Item::Builder item) { | |||
info << " Adding item: " << item.name; | |||
} | |||
void Mod::registerWorldGen(const std::string &name, std::unique_ptr<WorldGen::Factory> gen) { | |||
gen->name_ = name_ + "::" + name; | |||
info << " Adding world gen: " << gen->name_; | |||
worldgens_.push_back(std::move(gen)); | |||
} | |||
void Mod::registerEntity(const std::string &name, std::unique_ptr<Entity::Factory> ent) { | |||
ent->name_ = name_ + "::" + name; | |||
info << " Adding entity: " << ent->name_; | |||
entities_.push_back(std::move(ent)); | |||
} | |||
Iter<std::unique_ptr<ImageResource>> Mod::buildImages(SDL_Renderer *renderer) { | |||
return map(begin(images_), end(images_), [=](const ImageResource::Builder &builder) { | |||
return std::make_unique<ImageResource>(renderer, builder); | |||
return map(begin(images_), end(images_), [renderer, this](const std::string &id) { | |||
return std::make_unique<ImageResource>(renderer, path_, id); | |||
}); | |||
} | |||
@@ -72,15 +58,15 @@ Iter<std::unique_ptr<Item>> Mod::buildItems(const ResourceManager &resources) { | |||
}); | |||
} | |||
Iter<WorldGen::Factory *> Mod::getWorldGens() { | |||
return map(begin(worldgens_), end(worldgens_), [](const std::unique_ptr<WorldGen::Factory> &gen) { | |||
return gen.get(); | |||
Iter<WorldGen::Factory> Mod::getWorldGens() { | |||
return map(begin(worldgens_), end(worldgens_), [](WorldGen::Factory &fact) { | |||
return fact; | |||
}); | |||
} | |||
Iter<Entity::Factory *> Mod::getEntities() { | |||
return map(begin(entities_), end(entities_), [](const std::unique_ptr<Entity::Factory> &ent){ | |||
return ent.get(); | |||
Iter<Entity::Factory> Mod::getEntities() { | |||
return map(begin(entities_), end(entities_), [](Entity::Factory &fact){ | |||
return fact; | |||
}); | |||
} | |||
@@ -2,6 +2,10 @@ | |||
#include <stdio.h> | |||
#include <SDL2/SDL_image.h> | |||
#include <regex> | |||
#include <cpptoml.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include "log.h" | |||
#include "common.h" | |||
@@ -10,7 +14,10 @@ | |||
namespace Swan { | |||
ImageResource::ImageResource(SDL_Renderer *renderer, const Builder &builder) { | |||
ImageResource::ImageResource( | |||
SDL_Renderer *renderer, const std::string &modpath, const std::string &id) { | |||
static std::regex first_part_re("^.*?/"); | |||
SDL_RendererInfo rinfo; | |||
if (SDL_GetRendererInfo(renderer, &rinfo) < 0) { | |||
panic << "GetRendererInfo failed: " << SDL_GetError(); | |||
@@ -25,12 +32,15 @@ ImageResource::ImageResource(SDL_Renderer *renderer, const Builder &builder) { | |||
abort(); | |||
} | |||
surface_.reset(IMG_Load((builder.modpath + "/assets/" + builder.path).c_str())); | |||
std::string assetpath = modpath + "/assets/" + | |||
std::regex_replace(id, first_part_re, ""); | |||
surface_.reset(IMG_Load((assetpath + ".png").c_str())); | |||
// If we have a surface, and it's the wrong pixel format, convert it | |||
if (surface_ && surface_->format->format != format) { | |||
info | |||
<< " " << builder.name << ": Converting from " | |||
<< " " << id << ": Converting from " | |||
<< SDL_GetPixelFormatName(surface_->format->format) << " to " | |||
<< SDL_GetPixelFormatName(format); | |||
surface_.reset(SDL_ConvertSurfaceFormat(surface_.get(), format, 0)); | |||
@@ -39,7 +49,7 @@ ImageResource::ImageResource(SDL_Renderer *renderer, const Builder &builder) { | |||
// If we don't have a surface yet (either loading or conversion failed), | |||
// create a placeholder | |||
if (!surface_) { | |||
warn << "Loading image " << builder.name << " failed: " << SDL_GetError(); | |||
warn << "Loading image " << id << " failed: " << SDL_GetError(); | |||
surface_.reset(SDL_CreateRGBSurface( | |||
0, TILE_SIZE, TILE_SIZE, bpp, rmask, gmask, bmask, amask)); | |||
@@ -47,9 +57,23 @@ ImageResource::ImageResource(SDL_Renderer *renderer, const Builder &builder) { | |||
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE)); | |||
} | |||
frame_height_ = builder.frame_height; | |||
if (frame_height_ < 0) | |||
frame_height_ = surface_->h; | |||
frame_height_ = 32; | |||
// Load TOML if it exists | |||
errno = ENOENT; // I don't know if ifstream is guaranteed to set errno | |||
std::ifstream tomlfile(assetpath + ".toml"); | |||
if (tomlfile) { | |||
cpptoml::parser parser(tomlfile); | |||
try { | |||
auto toml = parser.parse(); | |||
frame_height_ = toml->get_as<int>("height").value_or(frame_height_); | |||
} catch (cpptoml::parse_exception &exc) { | |||
warn << "Failed to parse toml file " << assetpath << ".toml: " | |||
<< exc.what(); | |||
} | |||
} else if (errno != ENOENT) { | |||
warn << "Couldn't open " << assetpath << ".toml: " << strerror(errno); | |||
} | |||
texture_.reset(SDL_CreateTextureFromSurface(renderer, surface_.get())); | |||
if (!texture_) { | |||
@@ -58,7 +82,7 @@ ImageResource::ImageResource(SDL_Renderer *renderer, const Builder &builder) { | |||
} | |||
num_frames_ = surface_->h / frame_height_; | |||
name_ = builder.name; | |||
name_ = id; | |||
} | |||
ImageResource::ImageResource( |
@@ -1,467 +0,0 @@ | |||
#include "SRF.h" | |||
namespace Swan { | |||
enum class Type { | |||
OBJECT = 0, | |||
ARRAY = 1, | |||
STRING = 2, | |||
BYTE = 3, | |||
WORD = 4, | |||
INT = 5, | |||
FLOAT = 6, | |||
DOUBLE = 7, | |||
NONE = 8, | |||
BYTE_ARRAY = 9, | |||
WORD_ARRAY = 10, | |||
INT_ARRAY = 11, | |||
FLOAT_ARRAY = 12, | |||
DOUBLE_ARRAY = 13, | |||
}; | |||
static void writeByte(std::ostream &os, uint8_t val) { | |||
os.put(val); | |||
} | |||
static uint8_t readByte(std::istream &is) { | |||
return is.get(); | |||
} | |||
static void writeWord(std::ostream &os, uint16_t val) { | |||
os.put((val & 0xff00u) >> 8); | |||
os.put(val & 0x00ffu); | |||
} | |||
static uint16_t readWord(std::istream &is) { | |||
return (uint16_t)( | |||
((uint16_t)is.get()) << 8 | | |||
((uint16_t)is.get())); | |||
} | |||
static void writeInt(std::ostream &os, int32_t val) { | |||
uint32_t uval = val; | |||
os.put((uval & 0xff000000u) << 24); | |||
os.put((uval & 0x00ff0000u) << 16); | |||
os.put((uval & 0x0000ff00u) << 8); | |||
os.put((uval & 0x000000ffu)); | |||
} | |||
int32_t readInt(std::istream &is) { | |||
return (int32_t)( | |||
((uint32_t)is.get() << 24) | | |||
((uint32_t)is.get() << 16) | | |||
((uint32_t)is.get() << 8) | | |||
((uint32_t)is.get())); | |||
} | |||
static void writeFloat(std::ostream &os, float val) { | |||
uint32_t uval = (uint32_t)val; | |||
os.put((uval & 0xff000000u) << 24); | |||
os.put((uval & 0x00ff0000u) << 16); | |||
os.put((uval & 0x0000ff00u) << 8); | |||
os.put((uval & 0x000000ffu)); | |||
} | |||
static float readFloat(std::istream &is) { | |||
return (float)( | |||
((uint32_t)is.get() << 24) | | |||
((uint32_t)is.get() << 16) | | |||
((uint32_t)is.get() << 8) | | |||
((uint32_t)is.get())); | |||
} | |||
static void writeDouble(std::ostream &os, double val) { | |||
uint64_t uval = (uint64_t)val; | |||
os.put((uval & 0xff00000000000000lu) << 56); | |||
os.put((uval & 0x00ff000000000000lu) << 48); | |||
os.put((uval & 0x0000ff0000000000lu) << 40); | |||
os.put((uval & 0x000000ff00000000lu) << 32); | |||
os.put((uval & 0x00000000ff000000lu) << 24); | |||
os.put((uval & 0x0000000000ff0000lu) << 16); | |||
os.put((uval & 0x000000000000ff00lu) << 8); | |||
os.put((uval & 0x00000000000000fflu)); | |||
} | |||
static double readDouble(std::istream &is) { | |||
return (double)( | |||
((uint64_t)is.get() << 56) | | |||
((uint64_t)is.get() << 48) | | |||
((uint64_t)is.get() << 40) | | |||
((uint64_t)is.get() << 32) | | |||
((uint64_t)is.get() << 24) | | |||
((uint64_t)is.get() << 16) | | |||
((uint64_t)is.get() << 8) | | |||
((uint64_t)is.get())); | |||
} | |||
static void writeString(std::ostream &os, const std::string &str) { | |||
writeInt(os, str.size()); | |||
os.write(str.c_str(), str.size()); | |||
} | |||
static std::string readString(std::istream &is) { | |||
std::string str; | |||
int32_t len = readInt(is); | |||
str.reserve(len); | |||
is.read(str.data(), len); | |||
return str; | |||
} | |||
static char hexchr(uint8_t nibble) { | |||
if (nibble < 10) | |||
return (char)('0' + nibble); | |||
else | |||
return (char)('a' + (nibble - 10)); | |||
} | |||
SRF *SRF::read(std::istream &is) { | |||
Type type = (Type)readByte(is); | |||
SRF *srf = nullptr; | |||
switch (type) { | |||
case Type::OBJECT: | |||
srf = new SRFObject(); break; | |||
case Type::ARRAY: | |||
srf = new SRFArray(); break; | |||
case Type::STRING: | |||
srf = new SRFString(); break; | |||
case Type::BYTE: | |||
srf = new SRFByte(); break; | |||
case Type::WORD: | |||
srf = new SRFWord(); break; | |||
case Type::INT: | |||
srf = new SRFInt(); break; | |||
case Type::FLOAT: | |||
srf = new SRFFloat(); break; | |||
case Type::DOUBLE: | |||
srf = new SRFDouble(); break; | |||
case Type::NONE: | |||
srf = new SRFNone(); break; | |||
case Type::BYTE_ARRAY: | |||
srf = new SRFByteArray(); break; | |||
case Type::WORD_ARRAY: | |||
srf = new SRFWordArray(); break; | |||
case Type::INT_ARRAY: | |||
srf = new SRFIntArray(); break; | |||
case Type::FLOAT_ARRAY: | |||
srf = new SRFFloatArray(); break; | |||
case Type::DOUBLE_ARRAY: | |||
srf = new SRFDoubleArray(); break; | |||
} | |||
srf->parse(is); | |||
return srf; | |||
} | |||
std::ostream &operator<<(std::ostream &os, const SRF &srf) { | |||
srf.pretty(os); | |||
return os; | |||
} | |||
SRFObject::SRFObject(std::initializer_list<std::pair<std::string, SRF *>> lst) { | |||
for (auto &[k, v]: lst) | |||
val[k] = std::unique_ptr<SRF>(v); | |||
} | |||
void SRFObject::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::OBJECT); | |||
writeInt(os, val.size()); | |||
for (auto &[k, v]: val) { | |||
writeString(os, k); | |||
v->serialize(os); | |||
} | |||
} | |||
void SRFObject::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
for (int32_t i = 0; i < count; ++i) { | |||
std::string key = readString(is); | |||
val[key] = std::unique_ptr<SRF>(SRF::read(is)); | |||
} | |||
} | |||
std::ostream &SRFObject::pretty(std::ostream &os) const { | |||
os << "{ "; | |||
bool first = true; | |||
for (auto &[k, v]: val) { | |||
if (!first) | |||
os << ", "; | |||
os << '\'' << k << "': "; | |||
v->pretty(os); | |||
first = false; | |||
} | |||
return os << " }"; | |||
} | |||
SRFArray::SRFArray(std::initializer_list<SRF *> lst) { | |||
for (auto &v: lst) | |||
val.push_back(std::unique_ptr<SRF>(v)); | |||
} | |||
void SRFArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::ARRAY); | |||
writeInt(os, val.size()); | |||
for (auto &v: val) { | |||
v->serialize(os); | |||
} | |||
} | |||
void SRFArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
for (int32_t i = 0; i < count; ++i) { | |||
val[i] = std::unique_ptr<SRF>(SRF::read(is)); | |||
} | |||
} | |||
std::ostream &SRFArray::pretty(std::ostream &os) const { | |||
os << "[ "; | |||
bool first = true; | |||
for (auto &v: val) { | |||
if (!first) | |||
os << ", "; | |||
v->pretty(os); | |||
first = false; | |||
} | |||
return os << " ]"; | |||
} | |||
void SRFString::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::STRING); | |||
writeString(os, val); | |||
} | |||
void SRFString::parse(std::istream &is) { | |||
val = readString(is); | |||
} | |||
std::ostream &SRFString::pretty(std::ostream &os) const { | |||
return os << '"' << val << '"'; | |||
} | |||
void SRFByte::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::BYTE); | |||
writeByte(os, val); | |||
} | |||
void SRFByte::parse(std::istream &is) { | |||
val = readByte(is); | |||
} | |||
std::ostream &SRFByte::pretty(std::ostream &os) const { | |||
return os << "0x" | |||
<< hexchr((val & 0xf0) >> 4) | |||
<< hexchr((val & 0x0f) >> 0); | |||
} | |||
void SRFWord::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::WORD); | |||
writeWord(os, val); | |||
} | |||
void SRFWord::parse(std::istream &is) { | |||
val = readWord(is); | |||
} | |||
std::ostream &SRFWord::pretty(std::ostream &os) const { | |||
return os << "0x" | |||
<< hexchr((val & 0xf000) >> 12) | |||
<< hexchr((val & 0x0f00) >> 8) | |||
<< hexchr((val & 0x00f0) >> 4) | |||
<< hexchr((val & 0x000f) >> 0); | |||
} | |||
void SRFInt::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::INT); | |||
writeInt(os, val); | |||
} | |||
void SRFInt::parse(std::istream &is) { | |||
val = readInt(is); | |||
} | |||
std::ostream &SRFInt::pretty(std::ostream &os) const { | |||
return os << val; | |||
} | |||
void SRFFloat::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::FLOAT); | |||
writeFloat(os, val); | |||
} | |||
void SRFFloat::parse(std::istream &is) { | |||
val = readFloat(is); | |||
} | |||
std::ostream &SRFFloat::pretty(std::ostream &os) const { | |||
return os << val; | |||
} | |||
void SRFDouble::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::DOUBLE); | |||
writeDouble(os, val); | |||
} | |||
void SRFDouble::parse(std::istream &is) { | |||
val = readDouble(is); | |||
} | |||
std::ostream &SRFDouble::pretty(std::ostream &os) const { | |||
return os << val; | |||
} | |||
void SRFNone::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::NONE); | |||
} | |||
void SRFNone::parse(std::istream &is) {} | |||
std::ostream &SRFNone::pretty(std::ostream &os) const { | |||
return os << "(null)"; | |||
} | |||
void SRFByteArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::BYTE_ARRAY); | |||
writeInt(os, val.size()); | |||
os.write((const char *)val.data(), val.size()); | |||
} | |||
void SRFByteArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
is.read((char *)val.data(), count); | |||
} | |||
std::ostream &SRFByteArray::pretty(std::ostream &os) const { | |||
os << "byte[ " << std::hex; | |||
for (auto v: val) { | |||
os | |||
<< hexchr((v & 0xf0) >> 4) | |||
<< hexchr((v & 0x0f) >> 0) << ' '; | |||
} | |||
return os << ']'; | |||
} | |||
void SRFWordArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::WORD_ARRAY); | |||
writeInt(os, val.size()); | |||
for (auto &v: val) { | |||
writeWord(os, v); | |||
} | |||
} | |||
void SRFWordArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
for (int32_t i = 0; i < count; ++i) { | |||
val[i] = readWord(is); | |||
} | |||
} | |||
std::ostream &SRFWordArray::pretty(std::ostream &os) const { | |||
os << "word[ "; | |||
for (auto v: val) { | |||
os | |||
<< hexchr((v & 0xf000) >> 12) | |||
<< hexchr((v & 0x0f00) >> 8) | |||
<< hexchr((v & 0x00f0) >> 4) | |||
<< hexchr((v & 0x000f) >> 0) | |||
<< ' '; | |||
} | |||
return os << ']'; | |||
} | |||
void SRFIntArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::INT_ARRAY); | |||
writeInt(os, val.size()); | |||
for (auto &v: val) { | |||
writeInt(os, v); | |||
} | |||
} | |||
void SRFIntArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
for (int32_t i = 0; i < count; ++i) { | |||
val[i] = readInt(is); | |||
} | |||
} | |||
std::ostream &SRFIntArray::pretty(std::ostream &os) const { | |||
os << "int[ "; | |||
for (auto v: val) { | |||
os << v << ' '; | |||
} | |||
return os << ']'; | |||
} | |||
void SRFFloatArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::FLOAT_ARRAY); | |||
writeInt(os, val.size()); | |||
for (auto &v: val) { | |||
writeFloat(os, v); | |||
} | |||
} | |||
void SRFFloatArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
for (int32_t i = 0; i < count; ++i) { | |||
val[i] = readFloat(is); | |||
} | |||
} | |||
std::ostream &SRFFloatArray::pretty(std::ostream &os) const { | |||
os << "float[ "; | |||
for (auto v: val) { | |||
os << v << ' '; | |||
} | |||
return os << ']'; | |||
} | |||
void SRFDoubleArray::serialize(std::ostream &os) const { | |||
writeByte(os, (uint8_t)Type::DOUBLE_ARRAY); | |||
writeInt(os, val.size()); | |||
for (auto &v: val) { | |||
writeDouble(os, v); | |||
} | |||
} | |||
void SRFDoubleArray::parse(std::istream &is) { | |||
int32_t count = readInt(is); | |||
val.resize(count); | |||
for (int32_t i = 0; i < count; ++i) { | |||
val[i] = readDouble(is); | |||
} | |||
} | |||
std::ostream &SRFDoubleArray::pretty(std::ostream &os) const { | |||
os << "double[ "; | |||
for (auto v: val) { | |||
os << v << ' '; | |||
} | |||
return os << ']'; | |||
} | |||
} |
@@ -59,12 +59,18 @@ void World::addMod(std::unique_ptr<Mod> mod) { | |||
items_[i->name_] = std::move(i); | |||
} | |||
for (auto *gen: mod->getWorldGens()) { | |||
worldgens_[gen->name_] = gen; | |||
for (auto gen: mod->getWorldGens()) { | |||
worldgens_.emplace( | |||
std::piecewise_construct, | |||
std::forward_as_tuple(gen.name), | |||
std::forward_as_tuple(gen)); | |||
} | |||
for (auto *ent: mod->getEntities()) { | |||
ents_[ent->name_] = ent; | |||
for (auto ent: mod->getEntities()) { | |||
ents_.emplace( | |||
std::piecewise_construct, | |||
std::forward_as_tuple(ent.name), | |||
std::forward_as_tuple(ent)); | |||
} | |||
mods_.push_back(std::move(mod)); | |||
@@ -90,9 +96,9 @@ WorldPlane &World::addPlane(const std::string &gen) { | |||
abort(); | |||
} | |||
WorldGen::Factory *factory = it->second; | |||
WorldGen *g = factory->create(*this); | |||
planes_.emplace_back(id, this, std::shared_ptr<WorldGen>(g)); | |||
WorldGen::Factory &factory = it->second; | |||
std::unique_ptr<WorldGen> g = factory.create(*this); | |||
planes_.emplace_back(id, this, std::move(g)); | |||
return planes_[id]; | |||
} | |||
@@ -36,23 +36,27 @@ Context WorldPlane::getContext() { | |||
}; | |||
} | |||
Entity *WorldPlane::spawnEntity(const std::string &name, const SRF ¶ms) { | |||
Entity *WorldPlane::spawnEntity(const std::string &name, const Entity::PackObject &obj) { | |||
if (world_->ents_.find(name) == world_->ents_.end()) { | |||
panic << "Tried to spawn a non-existant entity " << name << "!"; | |||
abort(); | |||
} | |||
Entity *ent = world_->ents_[name]->create(getContext(), params); | |||
if (auto has_body = dynamic_cast<BodyTrait::HasBody *>(ent); has_body) { | |||
return spawnEntity(world_->ents_[name].create(getContext(), obj)); | |||
} | |||
Entity *WorldPlane::spawnEntity(std::unique_ptr<Entity> ent) { | |||
Entity *ptr = ent.get(); | |||
if (auto has_body = dynamic_cast<BodyTrait::HasBody *>(ent.get()); has_body) { | |||
BodyTrait::Body &body = has_body->getBody(); | |||
BodyTrait::Bounds bounds = body.getBounds(); | |||
body.move({ 0.5f - bounds.size.x / 2, 0 }); | |||
} | |||
spawn_list_.push_back(std::unique_ptr<Entity>(ent)); | |||
info << "Spawned " << name << ". SRF: " << params; | |||
return ent; | |||
spawn_list_.push_back(std::move(ent)); | |||
info << "Spawned entity."; | |||
return ptr; | |||
} | |||
void WorldPlane::despawnEntity(Entity &ent) { | |||
@@ -138,7 +142,7 @@ Iter<Entity *> WorldPlane::getEntsInArea(Vec2 center, float radius) { | |||
} | |||
BodyTrait::HasBody *WorldPlane::spawnPlayer() { | |||
return gen_->spawnPlayer(*this); | |||
return gen_->spawnPlayer(getContext()); | |||
} | |||
void WorldPlane::breakBlock(TilePos pos) { | |||
@@ -154,10 +158,11 @@ void WorldPlane::breakBlock(TilePos pos) { | |||
// Then spawn an item stack entity. | |||
Tile &t = world_->getTileByID(id); | |||
if (t.dropped_item_ != std::nullopt) { | |||
spawnEntity("core::item-stack", SRFArray{ | |||
new SRFFloatArray{ (float)pos.x, (float)pos.y }, | |||
new SRFString{ *t.dropped_item_ }, | |||
if (t.dropped_item_) { | |||
msgpack::zone zone; | |||
spawnEntity("core::item-stack", Entity::PackObject{ | |||
{ "pos", msgpack::object(pos, zone) }, | |||
{ "item", msgpack::object(*t.dropped_item_, zone) }, | |||
}); | |||
} | |||
} |
@@ -5,18 +5,25 @@ add_library(imgui SHARED | |||
${PROJECT_SOURCE_DIR}/third_party/imgui/imgui.cpp | |||
${PROJECT_SOURCE_DIR}/third_party/imgui_sdl/imgui_sdl.cpp | |||
${PROJECT_SOURCE_DIR}/third_party/imgui-plot/src/imgui_plot.cpp) | |||
set_target_properties(imgui PROPERTIES CXX_CLANG_TIDY "") | |||
target_include_directories(imgui PUBLIC | |||
${PROJECT_SOURCE_DIR}/third_party/imgui | |||
${PROJECT_SOURCE_DIR}/third_party/imgui-plot/include | |||
${SDL2_INCLUDE_DIRS}) | |||
set_target_properties(imgui PROPERTIES CXX_CLANG_TIDY "") | |||
install(TARGETS imgui DESTINATION swan/third_party) | |||
add_library(fmt SHARED | |||
${PROJECT_SOURCE_DIR}/third_party/fmt/src/format.cc | |||
${PROJECT_SOURCE_DIR}/third_party/fmt/src/os.cc) | |||
target_include_directories(fmt PUBLIC | |||
${PROJECT_SOURCE_DIR}/third_party/fmt/include) | |||
install(TARGETS fmt DESTINATION swan/third_party) | |||
add_library(cpptoml INTERFACE) | |||
target_include_directories(cpptoml PUBLIC | |||
target_include_directories(cpptoml INTERFACE | |||
${PROJECT_SOURCE_DIR}/third_party/cpptoml/include) | |||
add_library(msgpack INTERFACE) | |||
target_include_directories(msgpack PUBLIC | |||
${PROJECT_SOURCE_DIR}/third_party/msgpack/include) | |||
target_include_directories(msgpack INTERFACE | |||
${PROJECT_SOURCE_DIR}/third_party/msgpack-c/include) | |||
install(TARGETS imgui DESTINATION swan/third_party) |
@@ -0,0 +1 @@ | |||
Subproject commit 9bdd1596cef1b57b9556f8bef32dc4a32322ef3e |