Cuberite
A lightweight, fast and extensible game server for Minecraft
BrewingRecipes.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "BrewingRecipes.h"
5 
6 #include <fstream>
7 
8 #define BREWING_RECIPE_FILE "brewing.txt"
9 
10 
11 
12 
13 
15 {
16  ReloadRecipes();
17 }
18 
19 
20 
21 
22 
24 {
25  ClearRecipes();
26  LOGD("Loading brewing recipes...");
27 
28  std::ifstream f(BREWING_RECIPE_FILE, std::ios::in);
29  if (!f.good())
30  {
31  LOG("Could not open the brewing recipes file \"%s\". No brewing recipes are available.", BREWING_RECIPE_FILE);
32  return;
33  }
34 
35  unsigned int LineNum = 0;
36  AString ParsingLine;
37 
38  while (std::getline(f, ParsingLine))
39  {
40  LineNum++;
41  // Remove comments from the line:
42  size_t FirstCommentSymbol = ParsingLine.find('#');
43  if (FirstCommentSymbol != AString::npos)
44  {
45  ParsingLine.erase(FirstCommentSymbol);
46  }
47 
48  if (IsOnlyWhitespace(ParsingLine))
49  {
50  // Ignore empty and whitespace only lines
51  continue;
52  }
53  AddRecipeFromLine(ParsingLine, LineNum);
54  } // while (getline(ParsingLine))
55 
56  LOG("Loaded %zu brewing recipes", m_Recipes.size());
57 }
58 
59 
60 
61 
62 
63 void cBrewingRecipes::AddRecipeFromLine(AString a_Line, unsigned int a_LineNum)
64 {
65  a_Line.erase(std::remove_if(a_Line.begin(), a_Line.end(), isspace), a_Line.end());
66 
67  auto Recipe = std::make_unique<cRecipe>();
68 
69  const AStringVector & InputAndIngredient = StringSplit(a_Line, "+");
70 
71  if (InputAndIngredient.size() != 2)
72  {
73  LOGWARNING("brewing.txt: line %d: A line with '+' was expected", a_LineNum);
74  LOGINFO("Offending line: \"%s\"", a_Line.c_str());
75  return;
76  }
77 
78  const AStringVector & IngredientAndOutput = StringSplit(InputAndIngredient[1], "=");
79  if (IngredientAndOutput.size() != 2)
80  {
81  LOGWARNING("brewing.txt: line %d: A line with '=' was expected", a_LineNum);
82  LOGINFO("Offending line: \"%s\"", a_Line.c_str());
83  return;
84  }
85 
86  if (!ParseItem(IngredientAndOutput[0], Recipe->Ingredient))
87  {
88  LOGWARNING("brewing.txt: Parsing of the item didn't worked.");
89  LOGINFO("Offending line: \"%s\"", a_Line.c_str());
90  return;
91  }
92 
93  if (!StringToInteger<short>(InputAndIngredient[0], Recipe->Input.m_ItemDamage))
94  {
95  LOGWARNING("brewing.txt: line %d: Cannot parse the damage value for the input item\"%s\".", a_LineNum, InputAndIngredient[0].c_str());
96  LOGINFO("Offending line: \"%s\"", a_Line.c_str());
97  return;
98  }
99 
100  if (!StringToInteger<short>(IngredientAndOutput[1], Recipe->Output.m_ItemDamage))
101  {
102  LOGWARNING("brewing.txt: line %d: Cannot parse the damage value for the output item\"%s\".", a_LineNum, IngredientAndOutput[1].c_str());
103  LOGINFO("Offending line: \"%s\"", a_Line.c_str());
104  return;
105  }
106 
107  m_Recipes.push_back(std::move(Recipe));
108 }
109 
110 
111 
112 
113 
114 bool cBrewingRecipes::ParseItem(const AString & a_String, cItem & a_Item)
115 {
116  return StringToItem(a_String, a_Item);
117 }
118 
119 
120 
121 
122 
124 {
125  m_Recipes.clear();
126 }
127 
128 
129 
130 
131 
132 const cBrewingRecipes::cRecipe * cBrewingRecipes::GetRecipeFrom(const cItem & a_Input, const cItem & a_Ingredient) const
133 {
134  for (const auto & Recipe : m_Recipes)
135  {
136  if ((Recipe->Input.IsEqual(a_Input)) && (Recipe->Ingredient.IsEqual(a_Ingredient)))
137  {
138  return Recipe.get();
139  }
140  }
141 
142  // Check for gunpowder
143  if (a_Ingredient.m_ItemType == E_ITEM_GUNPOWDER)
144  {
145  if (a_Input.m_ItemDamage & 0x2000)
146  {
147  // Create new recipe and add it to list
148  auto Recipe = std::make_unique<cRecipe>();
149 
150  Recipe->Input.m_ItemType = a_Input.m_ItemDamage;
151  Recipe->Output.m_ItemDamage = a_Input.m_ItemDamage + 8192;
152  Recipe->Ingredient.m_ItemType = E_ITEM_GUNPOWDER;
153 
154  auto RecipePtr = Recipe.get();
155  m_Recipes.push_back(std::move(Recipe));
156  return RecipePtr;
157  }
158  return nullptr;
159  }
160 
161  // Check for splash potion
162  if (a_Input.m_ItemDamage & 0x4000)
163  {
164  // Search for the drinkable potion, the ingredients are the same
165  short SplashItemDamage = a_Input.m_ItemDamage - 8192;
166 
167  auto FoundRecipe = std::find_if(m_Recipes.cbegin(), m_Recipes.cend(), [&](const std::unique_ptr<cRecipe>& a_Recipe)
168  {
169  return (
170  (a_Recipe->Input.m_ItemDamage == SplashItemDamage) &&
171  (a_Recipe->Ingredient.IsEqual(a_Ingredient))
172  );
173  });
174 
175  if (FoundRecipe == m_Recipes.cend())
176  {
177  return nullptr;
178  }
179 
180  // Create new recipe and add it to list
181  auto Recipe = std::make_unique<cRecipe>();
182 
183  Recipe->Input.m_ItemDamage = a_Input.m_ItemDamage;
184  Recipe->Output.m_ItemDamage = (*FoundRecipe)->Output.m_ItemDamage + 8192;
185  Recipe->Ingredient.m_ItemType = (*FoundRecipe)->Ingredient.m_ItemType;
186 
187  auto RecipePtr = Recipe.get();
188  m_Recipes.push_back(std::move(Recipe));
189  return RecipePtr;
190  }
191  return nullptr;
192 }
193 
194 
195 
196 
197 
198 bool cBrewingRecipes::IsIngredient(const cItem & a_Ingredient) const
199 {
200  // Check for gunpowder
201  if (a_Ingredient.m_ItemType == E_ITEM_GUNPOWDER)
202  {
203  return true;
204  }
205 
206  for (const auto & Recipe : m_Recipes)
207  {
208  if (Recipe->Ingredient.IsEqual(a_Ingredient))
209  {
210  return true;
211  }
212  }
213  return false;
214 }
215 
216 
217 
218 
219 
220 bool cBrewingRecipes::IsBottle(const cItem & a_Item) const
221 {
222  return (a_Item.m_ItemType == E_ITEM_POTION);
223 }
224 
225 
226 
227 
228 
229 bool cBrewingRecipes::IsFuel(const cItem & a_Item) const
230 {
231  return (a_Item.m_ItemType == E_ITEM_BLAZE_POWDER);
232 }
233 
234 
235 
236 
bool StringToItem(const AString &a_ItemTypeString, cItem &a_Item)
Translates an itemtype string into an item.
Definition: BlockType.cpp:228
@ E_ITEM_POTION
Definition: BlockType.h:418
@ E_ITEM_BLAZE_POWDER
Definition: BlockType.h:423
@ E_ITEM_GUNPOWDER
Definition: BlockType.h:333
#define BREWING_RECIPE_FILE
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
#define LOGD
Definition: LoggerSimple.h:83
void LOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:61
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
Definition: StringUtils.cpp:55
bool IsOnlyWhitespace(const AString &a_String)
Returns true if only whitespace characters are present in the string.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
bool ParseItem(const AString &a_String, cItem &a_Item)
Parses an item string, returns true if successful.
void ClearRecipes(void)
const cRecipe * GetRecipeFrom(const cItem &a_Input, const cItem &a_Ingredient) const
Returns a recipe for the specified input, nullptr if no recipe found.
cRecipes m_Recipes
The collection of parsed recipes.
bool IsIngredient(const cItem &a_Ingredient) const
Returns true if the item is a ingredient, false if not.
void ReloadRecipes(void)
void AddRecipeFromLine(AString a_Line, unsigned int a_LineNum)
Parses the recipe contained in the line, adds it to m_pState's recipes.
bool IsBottle(const cItem &a_Item) const
Returns true if the item is a bottle / potion, false if not.
bool IsFuel(const cItem &a_Item) const
Returns true if the item is the fuel, false if not.
Definition: Item.h:37
short m_ItemType
Definition: Item.h:163
short m_ItemDamage
Definition: Item.h:165