1
0
cuberite-2a/src/FurnaceRecipe.cpp

345 lines
7.1 KiB
C++
Raw Normal View History

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "FurnaceRecipe.h"
#include "Item.h"
#include <fstream>
2020-05-07 15:14:00 -04:00
#define FURNACE_RECIPE_FILE "furnace.txt"
2014-08-31 13:00:36 -04:00
typedef std::list<cFurnaceRecipe::cRecipe> RecipeList;
typedef std::list<cFurnaceRecipe::cFuel> FuelList;
struct cFurnaceRecipe::sFurnaceRecipeState
{
RecipeList Recipes;
FuelList Fuel;
};
cFurnaceRecipe::cFurnaceRecipe()
2014-08-31 13:00:36 -04:00
: m_pState(new sFurnaceRecipeState)
{
ReloadRecipes();
}
cFurnaceRecipe::~cFurnaceRecipe()
{
ClearRecipes();
delete m_pState;
2014-10-20 16:55:07 -04:00
m_pState = nullptr;
}
void cFurnaceRecipe::ReloadRecipes(void)
{
ClearRecipes();
LOGD("Loading furnace recipes...");
2014-06-21 19:06:58 -04:00
std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in);
if (!f.good())
{
LOG("Could not open the furnace recipes file \"%s\". No furnace recipes are available.", FURNACE_RECIPE_FILE);
return;
}
2016-02-05 16:45:45 -05:00
unsigned int LineNum = 0;
AString ParsingLine;
2014-06-21 19:06:58 -04:00
while (std::getline(f, ParsingLine))
{
LineNum++;
2014-08-31 13:00:36 -04:00
// Remove comments from the line:
size_t FirstCommentSymbol = ParsingLine.find('#');
if ((FirstCommentSymbol != AString::npos) && (FirstCommentSymbol != 0))
{
2015-05-24 07:56:56 -04:00
ParsingLine.erase(ParsingLine.begin() + static_cast<const long>(FirstCommentSymbol), ParsingLine.end());
2014-08-31 13:00:36 -04:00
}
if (IsOnlyWhitespace(ParsingLine))
{
// Ignore empty and whitespace only lines
continue;
}
switch (ParsingLine[0])
{
case '#':
{
// Comment
break;
}
case '!':
{
AddFuelFromLine(ParsingLine, LineNum);
break;
}
default:
{
AddRecipeFromLine(ParsingLine, LineNum);
break;
}
} // switch (ParsingLine[0])
} // while (getline(ParsingLine))
LOG("Loaded %zu furnace recipes and %zu fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
}
2014-08-31 14:53:41 -04:00
void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, unsigned int a_LineNum)
{
2014-08-31 13:00:36 -04:00
AString Line(a_Line);
Line.erase(Line.begin()); // Remove the beginning "!"
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
std::unique_ptr<cItem> Item = std::make_unique<cItem>();
2014-08-31 13:00:36 -04:00
int BurnTime;
const AStringVector & Sides = StringSplit(Line, "=");
if (Sides.size() != 2)
{
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %zu", a_LineNum, Sides.size() - 1);
2014-08-31 13:00:36 -04:00
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
2014-08-31 13:00:36 -04:00
if (!ParseItem(Sides[0], *Item))
{
LOGWARNING("furnace.txt: line %d: Cannot parse item \"%s\".", a_LineNum, Sides[0].c_str());
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
2014-08-31 13:00:36 -04:00
if (!StringToInteger<int>(Sides[1], BurnTime))
{
2014-08-31 13:00:36 -04:00
LOGWARNING("furnace.txt: line %d: Cannot parse burn time.", a_LineNum);
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
2014-08-31 13:00:36 -04:00
// Add to fuel list:
cFuel Fuel;
2014-08-31 16:04:52 -04:00
Fuel.In = Item.release();
2014-08-31 13:00:36 -04:00
Fuel.BurnTime = BurnTime;
m_pState->Fuel.push_back(Fuel);
}
2014-08-31 14:53:41 -04:00
void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum)
{
2014-08-31 13:00:36 -04:00
AString Line(a_Line);
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
2014-08-31 13:00:36 -04:00
int CookTime = 200;
float Reward = 0;
std::unique_ptr<cItem> InputItem = std::make_unique<cItem>();
std::unique_ptr<cItem> OutputItem = std::make_unique<cItem>();
2014-08-31 13:00:36 -04:00
const AStringVector & Sides = StringSplit(Line, "=");
if (Sides.size() != 2)
{
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %zu", a_LineNum, Sides.size() - 1);
2014-08-31 13:00:36 -04:00
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
2014-08-31 13:00:36 -04:00
const AStringVector & InputSplit = StringSplit(Sides[0], "@");
if (!ParseItem(InputSplit[0], *InputItem))
{
2014-08-31 13:00:36 -04:00
LOGWARNING("furnace.txt: line %d: Cannot parse input item \"%s\".", a_LineNum, InputSplit[0].c_str());
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
2014-08-31 13:00:36 -04:00
if (InputSplit.size() > 1)
{
2014-08-31 13:00:36 -04:00
if (!StringToInteger<int>(InputSplit[1], CookTime))
{
2014-08-31 13:00:36 -04:00
LOGWARNING("furnace.txt: line %d: Cannot parse cook time \"%s\".", a_LineNum, InputSplit[1].c_str());
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
}
const AStringVector & OutputSplit = StringSplit(Sides[1], "$");
if (!ParseItem(OutputSplit[0], *OutputItem))
{
LOGWARNING("furnace.txt: line %d: Cannot parse output item \"%s\".", a_LineNum, OutputSplit[0].c_str());
2014-08-31 13:00:36 -04:00
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
if (OutputSplit.size() > 1)
{
if (!StringToFloat(OutputSplit[1], Reward))
{
LOGWARNING("furnace.txt: line %d: Cannot parse reward \"%s\".", a_LineNum, OutputSplit[1].c_str());
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
return;
}
}
2014-08-31 13:00:36 -04:00
cRecipe Recipe;
2014-08-31 16:04:52 -04:00
Recipe.In = InputItem.release();
Recipe.Out = OutputItem.release();
2014-08-31 13:00:36 -04:00
Recipe.CookTime = CookTime;
Recipe.Reward = Reward;
2014-08-31 13:00:36 -04:00
m_pState->Recipes.push_back(Recipe);
}
2014-08-31 13:00:36 -04:00
bool cFurnaceRecipe::ParseItem(const AString & a_String, cItem & a_Item)
{
2014-08-31 13:00:36 -04:00
AString ItemString = a_String;
2016-02-05 16:45:45 -05:00
2014-08-31 13:00:36 -04:00
const AStringVector & SplitAmount = StringSplit(ItemString, ",");
ItemString = SplitAmount[0];
2014-08-31 13:00:36 -04:00
const AStringVector & SplitMeta = StringSplit(ItemString, ":");
ItemString = SplitMeta[0];
2014-08-31 13:00:36 -04:00
if (!StringToItem(ItemString, a_Item))
{
return false;
}
2014-08-31 13:00:36 -04:00
if (SplitAmount.size() > 1)
{
if (!StringToInteger<char>(SplitAmount[1], a_Item.m_ItemCount))
{
2014-08-31 13:00:36 -04:00
return false;
}
}
2014-08-31 13:00:36 -04:00
if (SplitMeta.size() > 1)
{
if (!StringToInteger<short>(SplitMeta[1], a_Item.m_ItemDamage))
2014-08-31 13:00:36 -04:00
{
return false;
}
}
return true;
}
void cFurnaceRecipe::ClearRecipes(void)
{
for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
{
2014-08-31 13:00:36 -04:00
cRecipe Recipe = *itr;
delete Recipe.In;
2014-10-20 16:55:07 -04:00
Recipe.In = nullptr;
2014-08-31 13:00:36 -04:00
delete Recipe.Out;
2014-10-20 16:55:07 -04:00
Recipe.Out = nullptr;
}
m_pState->Recipes.clear();
for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
{
2014-08-31 13:00:36 -04:00
cFuel Fuel = *itr;
delete Fuel.In;
2014-10-20 16:55:07 -04:00
Fuel.In = nullptr;
}
m_pState->Fuel.clear();
}
2014-08-31 13:00:36 -04:00
const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_Ingredient) const
{
const cRecipe * BestRecipe = nullptr;
for (RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
{
2014-08-31 13:00:36 -04:00
const cRecipe & Recipe = *itr;
if ((Recipe.In->m_ItemType == a_Ingredient.m_ItemType) && (Recipe.In->m_ItemCount <= a_Ingredient.m_ItemCount))
{
2014-08-31 13:00:36 -04:00
if (BestRecipe && (BestRecipe->In->m_ItemCount > Recipe.In->m_ItemCount))
{
continue;
}
else if ((Recipe.In->m_ItemDamage == -1) || (Recipe.In->m_ItemDamage == a_Ingredient.m_ItemDamage))
{
2014-08-31 13:00:36 -04:00
BestRecipe = &Recipe;
}
}
}
return BestRecipe;
}
bool cFurnaceRecipe::IsFuel(const cItem & a_Item) const
{
2014-12-17 13:14:01 -05:00
for (auto & Fuel : m_pState->Fuel)
{
if ((Fuel.In->m_ItemType == a_Item.m_ItemType) && (Fuel.In->m_ItemCount <= a_Item.m_ItemCount))
{
return true;
}
}
return false;
}
int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const
{
int BestFuel = 0;
for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
{
2014-08-31 13:00:36 -04:00
const cFuel & Fuel = *itr;
if ((Fuel.In->m_ItemType == a_Fuel.m_ItemType) && (Fuel.In->m_ItemCount <= a_Fuel.m_ItemCount))
{
2014-08-31 13:00:36 -04:00
if (BestFuel > 0 && (BestFuel > Fuel.BurnTime))
{
continue;
}
else
{
2014-08-31 13:00:36 -04:00
BestFuel = Fuel.BurnTime;
}
}
}
return BestFuel;
}