TrinityCore
Loading...
Searching...
No Matches
GameTables.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "GameTables.h"
19#include "ItemTemplate.h"
20#include "Timer.h"
21#include "Log.h"
22#include "StringConvert.h"
23#include "Util.h"
24#include <boost/filesystem/path.hpp>
25#include <fstream>
26#include <sstream>
27
42
43template<class T>
44inline uint32 LoadGameTable(std::vector<std::string>& errors, GameTable<T>& storage, boost::filesystem::path const& path)
45{
46 std::ifstream stream(path.string());
47 if (!stream)
48 {
49 errors.push_back(Trinity::StringFormat("GameTable file {} cannot be opened.", path.string()));
50 return 0;
51 }
52
53 std::string headers;
54 if (!std::getline(stream, headers))
55 {
56 errors.push_back(Trinity::StringFormat("GameTable file {} is empty.", path.string()));
57 return 0;
58 }
59
60 std::vector<std::string_view> columnDefs = Trinity::Tokenize(headers, '\t', false);
61
62 ASSERT(columnDefs.size() - 1 == sizeof(T) / sizeof(float),
63 "GameTable '%s' has different count of columns " SZFMTD " than expected by size of C++ structure (" SZFMTD ").",
64 path.string().c_str(), columnDefs.size() - 1, sizeof(T) / sizeof(float));
65
66 std::vector<T> data;
67 data.emplace_back(); // row id 0, unused
68
69 std::string line;
70 while (std::getline(stream, line))
71 {
72 RemoveCRLF(line); // file extracted from client will always have CRLF line endings, on linux opening file in text mode will not work, manually erase \r
73 std::vector<std::string_view> values = Trinity::Tokenize(line, '\t', true);
74 if (values.empty())
75 break;
76
77 // make end point just after last nonempty token
78 auto end = values.begin() + values.size() - 1;
79 while (end->empty() && end != values.begin())
80 --end;
81
82 if (values.begin() == end)
83 break;
84
85 ++end;
86
87 ASSERT(std::size_t(std::distance(values.begin(), end)) == columnDefs.size(), SZFMTD " == " SZFMTD, std::size_t(std::distance(values.begin(), end)), columnDefs.size());
88
89 // client ignores id column - CombatRatings has copypasted rows for levels > 110
90 //ASSERT(Trinity::StringTo<int32>(values[0], 10) == data.size(),
91 // "Unexpected row identifier %d at row " SZFMTD " (expected " SZFMTD ")",
92 // Trinity::StringTo<int32>(values[0], 10).value_or(0), data.size(), data.size());
93
94 data.emplace_back();
95 float* row = reinterpret_cast<float*>(&data.back());
96 for (auto itr = values.begin() + 1; itr != end; ++itr)
97 *row++ = Trinity::StringTo<float>(*itr, 10).value_or(0.0f);
98 }
99
100 storage.SetData(std::move(data));
101 return 1;
102}
103
104void LoadGameTables(std::string const& dataPath)
105{
106 uint32 oldMSTime = getMSTime();
107
108 boost::filesystem::path gtPath(dataPath);
109 gtPath /= "gt";
110
111 std::vector<std::string> bad_gt_files;
112 uint32 gameTableCount = 0, expectedGameTableCount = 0;
113
114 auto LOAD_GT = [&]<typename T>(GameTable<T>& gameTable, char const* file)
115 {
116 gameTableCount += LoadGameTable(bad_gt_files, gameTable, gtPath / file);
117 ++expectedGameTableCount;
118 };
119
120 LOAD_GT(sArtifactKnowledgeMultiplierGameTable, "ArtifactKnowledgeMultiplier.txt");
121 LOAD_GT(sArtifactLevelXPGameTable, "ArtifactLevelXP.txt");
122 LOAD_GT(sBarberShopCostBaseGameTable, "BarberShopCostBase.txt");
123 LOAD_GT(sBaseMPGameTable, "BaseMp.txt");
124 LOAD_GT(sBattlePetXPGameTable, "BattlePetXP.txt");
125 LOAD_GT(sCombatRatingsGameTable, "CombatRatings.txt");
126 LOAD_GT(sCombatRatingsMultByILvlGameTable, "CombatRatingsMultByILvl.txt");
127 LOAD_GT(sItemLevelByLevelTable, "ItemLevelByLevel.txt");
128 LOAD_GT(sItemSocketCostPerLevelGameTable, "ItemSocketCostPerLevel.txt");
129 LOAD_GT(sHpPerStaGameTable, "HpPerSta.txt");
130 LOAD_GT(sNpcManaCostScalerGameTable, "NPCManaCostScaler.txt");
131 LOAD_GT(sSpellScalingGameTable, "SpellScaling.txt");
132 LOAD_GT(sStaminaMultByILvlGameTable, "StaminaMultByILvl.txt");
133 LOAD_GT(sXpGameTable, "xp.txt");
134
135#undef LOAD_GT
136
137 // error checks
138 if (gameTableCount != expectedGameTableCount)
139 {
140 std::ostringstream str;
141 for (std::string const& err : bad_gt_files)
142 str << err << std::endl;
143
144 WPFatal(false, "Some required *.txt GameTable files (" SZFMTD ") not found or not compatible:\n%s", bad_gt_files.size(), str.str().c_str());
145 }
146
147 TC_LOG_INFO("server.loading", ">> Initialized {} GameTables in {} ms", gameTableCount, GetMSTimeDiffToNow(oldMSTime));
148}
149
150template<class T>
151float GetIlvlStatMultiplier(T const* row, InventoryType invType)
152{
153 switch (invType)
154 {
155 case INVTYPE_NECK:
156 case INVTYPE_FINGER:
157 return row->JewelryMultiplier;
158 break;
159 case INVTYPE_TRINKET:
160 return row->TrinketMultiplier;
161 break;
162 case INVTYPE_WEAPON:
163 case INVTYPE_SHIELD:
164 case INVTYPE_RANGED:
165 case INVTYPE_2HWEAPON:
168 case INVTYPE_HOLDABLE:
170 return row->WeaponMultiplier;
171 break;
172 default:
173 return row->ArmorMultiplier;
174 break;
175 }
176}
177
179template float GetIlvlStatMultiplier(GtStaminaMultByILvl const* row, InventoryType invType);
uint32_t uint32
Definition Define.h:154
#define SZFMTD
Definition Define.h:144
#define WPFatal(cond,...)
Definition Errors.h:69
#define ASSERT
Definition Errors.h:80
GameTable< GtSpellScalingEntry > sSpellScalingGameTable
GameTable< GtBattlePetXPEntry > sBattlePetXPGameTable
GameTable< GtItemSocketCostPerLevelEntry > sItemSocketCostPerLevelGameTable
GameTable< GtStaminaMultByILvl > sStaminaMultByILvlGameTable
float GetIlvlStatMultiplier(T const *row, InventoryType invType)
GameTable< GtCombatRatingsEntry > sCombatRatingsGameTable
GameTable< GtItemLevelByLevelEntry > sItemLevelByLevelTable
void LoadGameTables(std::string const &dataPath)
GameTable< GtArtifactKnowledgeMultiplierEntry > sArtifactKnowledgeMultiplierGameTable
GameTable< GtXpEntry > sXpGameTable
GameTable< GtHpPerStaEntry > sHpPerStaGameTable
GameTable< GtNpcManaCostScalerEntry > sNpcManaCostScalerGameTable
GameTable< GtBaseMPEntry > sBaseMPGameTable
GameTable< GtBarberShopCostBaseEntry > sBarberShopCostBaseGameTable
GameTable< GtCombatRatingsMultByILvl > sCombatRatingsMultByILvlGameTable
uint32 LoadGameTable(std::vector< std::string > &errors, GameTable< T > &storage, boost::filesystem::path const &path)
GameTable< GtArtifactLevelXPEntry > sArtifactLevelXPGameTable
InventoryType
@ INVTYPE_FINGER
@ INVTYPE_HOLDABLE
@ INVTYPE_TRINKET
@ INVTYPE_RANGED
@ INVTYPE_RANGEDRIGHT
@ INVTYPE_WEAPON
@ INVTYPE_WEAPONMAINHAND
@ INVTYPE_WEAPONOFFHAND
@ INVTYPE_2HWEAPON
@ INVTYPE_NECK
@ INVTYPE_SHIELD
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
TC_COMMON_API Optional< std::size_t > RemoveCRLF(std::string &str)
Definition Util.cpp:797
void SetData(std::vector< T > data)
Definition GameTables.h:191
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:57
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.