farmlands/src/storage/Parsers.cpp

715 lines
22 KiB
C++

/*
* Parsers.cpp
*
* Created on: Dec 2, 2016
* Author: tibi
*/
#include <graphics/backend/SdlRenderer.h>
#include <storage/Parsers.h>
#include <resources/Resources.h>
using namespace farmlands::resources;
namespace farmlands {
namespace storage {
/****** Components ******/
void parseMapCells(resources::ResourceId cellsResource, components::Map* map, components::MapLayer& layer)
{
Assert(RInfo[cellsResource].type == ResourceType::MapLayer, "Resource must be a level layer.");
char buffer[1024 * 10];
// Open file
std::string pathIn = ResourceManager::instance().getPath(cellsResource);
std::ifstream in(pathIn);
if (!in)
THROW(utils::ResourceLoadException, "Could not load level layer " + pathIn);
// Read CSV file line by line
for (size_t row = 0; row < map->height; row++)
{
in.getline(buffer, sizeof(buffer));
if (in.eof())
THROW(utils::ResourceLoadException, "Unexpected end of file " + pathIn);
// Separated by comma (or maybe semicolon)
char* nextNum = strtok(buffer, ",;");
for (size_t col = 0; col < map->width && nextNum != NULL; col++)
{
components::Cell cell = (components::Cell) strtol(nextNum, NULL, 10);
layer[row][col] = cell;
nextNum = strtok(NULL, ",;");
}
}
in.close();
}
template <>
components::Map* parse<components::Map> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Map")
root = root.front().second;
// This object can be declared in another file
std::string src = root.get<std::string>("<xmlattr>.src", "");
if (!src.empty())
{
ResourceId id = ResourceManager::instance().getId(src);
return parse<components::Map>(id);
}
// Read map attributes
components::Map* map = new components::Map();
map->width = root.get<size_t>("<xmlattr>.width");
map->height = root.get<size_t>("<xmlattr>.height");
map->cellWidth = root.get<size_t>("<xmlattr>.cellWidth");
map->cellHeight = root.get<size_t>("<xmlattr>.cellHeight");
// Read layers
for (auto layerNode : root)
{
if (layerNode.first == "Layer")
{
// Read layer name
std::string name = layerNode.second.get<std::string>("<xmlattr>.name");
components::MapLayer& layer = map->addLayer(name);
// Read tile set
auto tileSetNode = layerNode.second.get_child("TileSet");
model::TileSet* tileSet = parse<model::TileSet>(tileSetNode);
layer.tileSet = *tileSet;
delete tileSet;
// Read cells
std::string cellsPath = layerNode.second.get<std::string>("<xmlattr>.cells", "");
if (!cellsPath.empty())
{
resources::ResourceId cellsId = resources::ResourceManager::instance().getId(cellsPath);
parseMapCells(cellsId, map, layer);
}
}
}
return map;
}
template <>
components::basic::Camera* parse<components::basic::Camera> (boost::property_tree::ptree& root)
{
if (root.size() > 0 && root.front().first == "Camera")
root = root.front().second;
components::basic::Camera* camera = new components::basic::Camera();
camera->scale = root.get<float>("<xmlattr>.scale", 1.0f);
camera->mainCamera = root.get<bool>("<xmlattr>.mainCamera", false);
return camera;
}
template <>
components::basic::Frame* parse<components::basic::Frame> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Frame")
root = root.front().second;
components::basic::Frame* frame = new components::basic::Frame();
// Set properties
std::string tileSetPath = root.get<std::string>("<xmlattr>.tileSet");
frame->tileSetId = resources::ResourceManager::instance().getId(tileSetPath);
frame->tileSetCell = root.get<int>("<xmlattr>.cell");
frame->duration = root.get<float>("<xmlattr>.duration");
return frame;
}
template <>
components::basic::Grid* parse<components::basic::Grid> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Grid")
root = root.front().second;
components::basic::Grid* grid = new components::basic::Grid();
// Set properties
utils::Rect<int> bounds;
bounds.x = root.get<int>("<xmlattr>.x", 0);
bounds.y = root.get<int>("<xmlattr>.y", 0);
bounds.w = root.get<int>("<xmlattr>.w");
bounds.h = root.get<int>("<xmlattr>.h");
grid->setBounds(bounds);
return grid;
}
template <>
components::basic::Inventory* parse<components::basic::Inventory> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Inventory")
root = root.front().second;
components::basic::Inventory* inventory = new components::basic::Inventory();
size_t capacity = root.get<size_t>("<xmlattr>.capacity");
inventory->setCapacity(capacity);
return inventory;
}
template <>
components::basic::InventoryItem* parse<components::basic::InventoryItem> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "InventoryItem")
root = root.front().second;
components::basic::InventoryItem* item = new components::basic::InventoryItem();
item->slot = root.get<size_t>("<xmlattr>.slot");
return item;
}
template <>
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Sprite")
root = root.front().second;
// This object can be declared in another file
std::string src = root.get<std::string>("<xmlattr>.src", "");
if (!src.empty())
{
ResourceId id = ResourceManager::instance().getId(src);
return parse<components::basic::Sprite>(id);
}
// Parse components::basic::Sprite
components::basic::Sprite* sprite = new components::basic::Sprite();
sprite->w = root.get<float>("<xmlattr>.w");
sprite->h = root.get<float>("<xmlattr>.h");
sprite->anchorX = root.get<float>("<xmlattr>.anchorX");
sprite->anchorY = root.get<float>("<xmlattr>.anchorY");
sprite->animationSpeed = root.get<float>("<xmlattr>.animationSpeed", 1.0f);
for (auto child : root)
{
if (child.first == "State")
{
components::basic::SpriteState* state = parse<components::basic::SpriteState>(child.second);
sprite->addState(*state);
delete state;
}
}
return sprite;
}
template <>
components::basic::SpriteState* parse<components::basic::SpriteState> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "SpriteState")
root = root.front().second;
components::basic::SpriteState* spriteState = new components::basic::SpriteState();
spriteState->name = root.get<std::string>("<xmlattr>.name");
for (auto child : root)
{
if (child.first == "Frame")
{
components::basic::Frame* frame = parse<components::basic::Frame>(child.second);
spriteState->frames.push_back(*frame);
delete frame;
}
}
return spriteState;
}
template <>
components::DebugController* parse<components::DebugController> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "DebugController")
root = root.front().second;
components::DebugController* controller = new components::DebugController();
return controller;
}
template <>
components::environment::GameTime* parse<components::environment::GameTime> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "GameTime")
root = root.front().second;
components::environment::GameTime* gameTime = new components::environment::GameTime();
return gameTime;
}
components::environment::WeatherType parseWeatherType(std::string weatherType)
{
boost::to_lower(weatherType);
components::environment::WeatherType type = components::environment::WeatherType::Sunny;
if (weatherType == "cloudy")
type = components::environment::WeatherType::Cloudy;
if (weatherType == "rainy")
type = components::environment::WeatherType::Rainy;
return type;
}
template <>
components::environment::Weather* parse<components::environment::Weather> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Weather")
root = root.front().second;
components::environment::Weather* weather = new components::environment::Weather();
std::string today = root.get<std::string>("<xmlattr>.today", "Sunny");
weather->today = parseWeatherType(today);
std::string tomorrow = root.get<std::string>("<xmlattr>.tomorrow", "Sunny");
weather->tomorrow = parseWeatherType(tomorrow);
return weather;
}
template <>
components::items::Axe* parse<components::items::Axe> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Axe")
root = root.front().second;
// Parse
return new components::items::Axe();
}
template <>
components::items::Giftable* parse<components::items::Giftable> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Giftable")
root = root.front().second;
// Parse
return new components::items::Giftable();
}
template <>
components::items::Hoe* parse<components::items::Hoe> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Hoe")
root = root.front().second;
// Parse
return new components::items::Hoe();
}
template <>
components::items::Item* parse<components::items::Item> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Item")
root = root.front().second;
// Parse
components::items::Item* item = new components::items::Item();
item->name = root.get<std::string>("<xmlattr>.name");
item->description = root.get<std::string>("<xmlattr>.description");
item->level = root.get<uint8_t>("<xmlattr>.level", 1);
return item;
}
template <>
components::items::Pickable* parse<components::items::Pickable> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Pickaxe")
root = root.front().second;
// Parse
return new components::items::Pickable();
}
template <>
components::items::Pickaxe* parse<components::items::Pickaxe> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Pickaxe")
root = root.front().second;
// Parse
return new components::items::Pickaxe();
}
template <>
components::items::Scythe* parse<components::items::Scythe> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Pickaxe")
root = root.front().second;
// Parse
return new components::items::Scythe();
}
template <>
components::items::WateringCan* parse<components::items::WateringCan> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "WateringCan")
root = root.front().second;
// Parse
components::items::WateringCan* can = new components::items::WateringCan();
can->capacity = root.get<float>("<xmlattr>.capacity");
can->amountLeft = root.get<float>("<xmlattr>.amountLeft");
return can;
}
template <>
components::items::Weapon* parse<components::items::Weapon> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Weapon")
root = root.front().second;
// Parse
components::items::Weapon* weapon = new components::items::Weapon();
weapon->damage = root.get<float>("<xmlattr>.damage");
weapon->critProbability = root.get<float>("<xmlattr>.critProbability");
weapon->critDamage = root.get<float>("<xmlattr>.critDamage");
weapon->attackDuration = root.get<float>("<xmlattr>.attackDuration");
weapon->energyCost = root.get<float>("<xmlattr>.energyCost");
return weapon;
}
template <>
components::plants::Plant* parse<components::plants::Plant> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Plant")
root = root.front().second;
// Parse
components::plants::Plant* plant = new components::plants::Plant();
plant->needsWater = root.get<bool>("<xmlattr>.needsWater");
plant->daysWithoutWater = root.get<uint32_t>("<xmlattr>.daysWithoutWater", 0);
plant->maxDaysWithoutWater = root.get<uint32_t>("<xmlattr>.maxDaysWithoutWater", 2);
plant->state = root.get<size_t>("<xmlattr>.state", 0);
plant->stateDays = root.get<uint32_t>("<xmlattr>.stateDays", 0);
for (auto child : root)
if (child.first == "State")
{
int32_t length = child.second.get<int32_t>("<xmlattr>.len", -1);
plant->stateLengths.push_back(length);
}
return plant;
}
template <>
components::plants::Seed* parse<components::plants::Seed> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Seed")
root = root.front().second;
// Parse
components::plants::Seed* seed = new components::plants::Seed();
seed->plantName = root.get<std::string>("<xmlattr>.plantName");
return seed;
}
model::Direction parseDirection(std::string directionStr)
{
model::Direction direction = model::Direction::None;
boost::to_lower(directionStr);
if (directionStr == "east")
direction = model::Direction::East;
if (directionStr == "north")
direction = model::Direction::North;
if (directionStr == "west")
direction = model::Direction::West;
if (directionStr == "south")
direction = model::Direction::South;
return direction;
}
template <>
components::player::Player* parse<components::player::Player> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Player")
root = root.front().second;
components::player::Player* player = new components::player::Player();
// Inventory
player->selectedItemIndex = root.get<int>("<xmlattr>.selectedItemIndex", -1);
player->itemActionTimeLeft = root.get<float>("<xmlattr>.itemActionTimeLeft", 0.0f);
// Movement
std::string direction = root.get<std::string>("<xmlattr>.facingDirection", "South");
player->facingDirection = parseDirection(direction);
player->walking = root.get<bool>("<xmlattr>.walking", false);
player->running = root.get<bool>("<xmlattr>.running", false);
// Looking
player->lookX = root.get<float>("<xmlattr>.lookX", 0.0f);
player->lookY = root.get<float>("<xmlattr>.lookY", 0.0f);
// Health, energy
player->hp = root.get<float>("<xmlattr>.hp", 100.0f);
player->maxHp = root.get<float>("<xmlattr>.maxHp", 100.0f);
player->energy = root.get<float>("<xmlattr>.energy", 100.0f);
player->maxEnergy = root.get<float>("<xmlattr>.maxEnergy", 100.0f);
// Cash
player->money = root.get<uint32_t>("<xmlattr>.money", 0u);
return player;
}
/****** Graphics ******/
template <>
graphics::MapRenderer* parse<graphics::MapRenderer> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "MapRenderer")
root = root.front().second;
graphics::MapRenderer* renderer = new graphics::MapRenderer();
return renderer;
}
template <>
graphics::SpriteRenderer* parse<graphics::SpriteRenderer> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "SpriteRenderer")
root = root.front().second;
graphics::SpriteRenderer* renderer = new graphics::SpriteRenderer();
return renderer;
}
/****** Model ******/
void parseTransform (model::Transform& transform, boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Transform")
root = root.front().second;
transform.x = root.get<float>("<xmlattr>.x", 0.0f);
transform.y = root.get<float>("<xmlattr>.y", 0.0f);
transform.scaleX = root.get<float>("<xmlattr>.scaleX", 1.0f);
transform.scaleY = root.get<float>("<xmlattr>.scaleY", 1.0f);
}
template <>
model::GameObject* parse<model::GameObject> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "GameObject")
root = root.front().second;
model::GameObject* gameObj = new model::GameObject();
gameObj->name = root.get<std::string>("<xmlattr>.name");
gameObj->visible = root.get<bool>("<xmlattr>.visible", true);
gameObj->setEnabled(root.get<bool>("<xmlattr>.enabled", true));
for (auto child : root)
{
// Game object
if (child.first == "GameObject")
gameObj->addChild(parse<model::GameObject>(child.second));
else if (child.first == "Transform")
parseTransform(gameObj->transform, child.second);
// Components::basic
else if (child.first == "Camera")
gameObj->addComponent(parse<components::basic::Camera>(child.second));
else if (child.first == "Grid")
gameObj->addComponent(parse<components::basic::Grid>(child.second));
else if (child.first == "Inventory")
gameObj->addComponent(parse<components::basic::Inventory>(child.second));
else if (child.first == "InventoryItem")
gameObj->addComponent(parse<components::basic::InventoryItem>(child.second));
else if (child.first == "Sprite")
gameObj->addComponent(parse<components::basic::Sprite>(child.second));
// Components::items
else if (child.first == "Axe")
gameObj->addComponent(parse<components::items::Axe>(child.second));
else if (child.first == "Giftable")
gameObj->addComponent(parse<components::items::Giftable>(child.second));
else if (child.first == "Hoe")
gameObj->addComponent(parse<components::items::Hoe>(child.second));
else if (child.first == "Item")
gameObj->addComponent(parse<components::items::Item>(child.second));
else if (child.first == "Pickable")
gameObj->addComponent(parse<components::items::Pickable>(child.second));
else if (child.first == "Pickaxe")
gameObj->addComponent(parse<components::items::Pickaxe>(child.second));
else if (child.first == "Scythe")
gameObj->addComponent(parse<components::items::Scythe>(child.second));
else if (child.first == "WateringCan")
gameObj->addComponent(parse<components::items::WateringCan>(child.second));
else if (child.first == "Weapon")
gameObj->addComponent(parse<components::items::Weapon>(child.second));
// Components::plants
else if (child.first == "Plant")
gameObj->addComponent(parse<components::plants::Plant>(child.second));
else if (child.first == "Seed")
gameObj->addComponent(parse<components::plants::Seed>(child.second));
// Components::player
else if (child.first == "Player")
gameObj->addComponent(parse<components::player::Player>(child.second));
// Components
else if (child.first == "DebugController")
gameObj->addComponent(parse<components::DebugController>(child.second));
// Environment
else if (child.first == "GameTime")
gameObj->addComponent(parse<components::environment::GameTime>(child.second));
else if (child.first == "Weather")
gameObj->addComponent(parse<components::environment::Weather>(child.second));
else if (child.first == "Map")
gameObj->addComponent(parse<components::Map>(child.second));
// Graphics
else if (child.first == "MapRenderer")
gameObj->addComponent(parse<graphics::MapRenderer>(child.second));
else if (child.first == "SpriteRenderer")
gameObj->addComponent(parse<graphics::SpriteRenderer>(child.second));
// !!! Add additional types here !!!
}
return gameObj;
}
template <>
model::Configuration* parse<model::Configuration> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Configuration")
root = root.front().second;
model::Configuration* config = new model::Configuration();
config->animationFps = root.get<float>("animationFps");
return config;
}
template <>
model::Scene* parse<model::Scene> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "Scene")
root = root.front().second;
model::Scene* scene = new model::Scene();
scene->cellWidth = root.get<uint32_t>("<xmlattr>.cellWidth");
scene->cellHeight = root.get<uint32_t>("<xmlattr>.cellHeight");
for (auto child : root)
{
if (child.first == "GameObject")
{
model::GameObject* obj = parse<model::GameObject>(child.second);
scene->root.addChild(obj);
}
}
return scene;
}
template<>
model::TileSet* parse<model::TileSet> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.size() > 0 && root.front().first == "TileSet")
root = root.front().second;
// This object can be declared in another file
std::string src = root.get<std::string>("<xmlattr>.src", "");
if (!src.empty())
{
ResourceId id = ResourceManager::instance().getId(src);
return parse<model::TileSet>(id);
}
// Read attributes
model::TileSet* tileSet = new model::TileSet();
std::string texPath = root.get<std::string>("<xmlattr>.texture");
tileSet->texture = resources::ResourceManager::instance().getId(texPath);
tileSet->tileWidth = root.get<size_t>("<xmlattr>.tileWidth");
tileSet->tileHeight = root.get<size_t>("<xmlattr>.tileHeight");
// Get image size
int w, h;
SDL_Texture* sdlTex = ResourceManager::instance().texture(tileSet->texture);
graphics::backend::SdlRenderer::instance().getTextureSize(sdlTex, &w, &h);
tileSet->width = w;
tileSet->height = h;
return tileSet;
}
}
}