PageRenderTime 1924ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Libs/ConsoleCommands/ConVar.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 325 lines | 211 code | 55 blank | 59 comment | 33 complexity | 60a94f0e192b7d87576e73612157b143 MD5 | raw file
  1. /*
  2. =================================================================================
  3. This file is part of Cafu, the open-source game engine and graphics engine
  4. for multiplayer, cross-platform, real-time 3D action.
  5. Copyright (C) 2002-2013 Carsten Fuchs Software.
  6. Cafu is free software: you can redistribute it and/or modify it under the terms
  7. of the GNU General Public License as published by the Free Software Foundation,
  8. either version 3 of the License, or (at your option) any later version.
  9. Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  10. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Cafu. If not, see <http://www.gnu.org/licenses/>.
  14. For support and more information about Cafu, visit us at <http://www.cafu.de>.
  15. =================================================================================
  16. */
  17. #include "ConVar.hpp"
  18. #include "ConsoleInterpreter.hpp"
  19. #include <cassert>
  20. #include <fstream>
  21. // This functions returns a static list where all ConVarT objects that are instantiated before the call to ConVarT::RegisterStaticList()
  22. // register themselves (this is done by their ctors), waiting to be registered with the ConsoleInterpreter.
  23. // Usually only globally declared ConVarTs get into this list.
  24. //
  25. // Note that we can *NOT* simply have a static ArrayT<ConVarT*> StaticList; here (without the function around it), because the StaticList
  26. // is then just another global variable (as the ConVarT objects), and it seems that when a ctor of a global ConVarT object is run, it can
  27. // happen that the ctor of the StaticList has NOT YET BEEN RUN, so this is a (nontrivial) instance of the "static initialization order problem",
  28. // fixed by the wrapper function. Note that the deinitialization order is not a problem here.
  29. static ArrayT<ConVarT*>& GetStaticList()
  30. {
  31. static ArrayT<ConVarT*> StaticList;
  32. return StaticList;
  33. }
  34. void ConVarT::RegisterStaticList()
  35. {
  36. assert(ConsoleInterpreter!=NULL);
  37. // Well, under Linux it seems that it is possible that this method is called multiple times per loaded (game) DLL...
  38. // This is probably because Windows DLLs get their reference count increased and their global data *duplicated* when being loaded multiply,
  39. // whereas under Linux, loading a DLL is more like statically linking a ".a" library - there is only *one* instance of the global data.
  40. // assert(!(GetStaticList().Size()>0 && GetStaticList()[0]==NULL));
  41. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL) return;
  42. for (unsigned long ConVarNr=0; ConVarNr<GetStaticList().Size(); ConVarNr++)
  43. ConsoleInterpreter->Register(GetStaticList()[ConVarNr]);
  44. // The sole purpose of the list is fulfilled, mark it appropriately.
  45. GetStaticList().Clear();
  46. GetStaticList().PushBack(NULL);
  47. }
  48. // This is just a helper method for the constructor below.
  49. static ArrayT<std::string> ConvertStringList(const char** Strings)
  50. {
  51. ArrayT<std::string> List;
  52. if (Strings==NULL) return List;
  53. for (unsigned long Nr=0; Strings[Nr]!=NULL; Nr++)
  54. List.PushBack(Strings[Nr]);
  55. return List;
  56. }
  57. ConVarT::ConVarT(const std::string& Name_, const std::string& Value_, const int Flags_, const std::string& Description_, const char** AllowedValues_)
  58. : Name(Name_),
  59. Description(Description_),
  60. Flags(Flags_ | FLAG_BY_CODE),
  61. Type(String),
  62. ValueString(Value_),
  63. ValueInt(0),
  64. ValueDouble(0.0),
  65. MinValue(0.0),
  66. MaxValue(0.0),
  67. AllowedValues(ConvertStringList(AllowedValues_)),
  68. IsModified(false)
  69. {
  70. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL)
  71. {
  72. // The StaticList is already in the state that indicates that the ConsoleInterpreter is available now
  73. // and its members have already been registered with it. So register this ConFuncT directly, too.
  74. assert(ConsoleInterpreter!=NULL);
  75. ConsoleInterpreter->Register(this);
  76. }
  77. else
  78. {
  79. // RegisterStaticList() has not yet been called, so add this ConFuncT to the waiting list for later registration.
  80. GetStaticList().PushBack(this);
  81. }
  82. }
  83. // This ctor is identical to the one above, except for the type of the Value_ parameter.
  84. ConVarT::ConVarT(const std::string& Name_, const char* Value_, const int Flags_, const std::string& Description_, const char** AllowedValues_)
  85. : Name(Name_),
  86. Description(Description_),
  87. Flags(Flags_ | FLAG_BY_CODE),
  88. Type(String),
  89. ValueString(Value_),
  90. ValueInt(0),
  91. ValueDouble(0.0),
  92. MinValue(0.0),
  93. MaxValue(0.0),
  94. AllowedValues(ConvertStringList(AllowedValues_)),
  95. IsModified(false)
  96. {
  97. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL)
  98. {
  99. // The StaticList is already in the state that indicates that the ConsoleInterpreter is available now
  100. // and its members have already been registered with it. So register this ConFuncT directly, too.
  101. assert(ConsoleInterpreter!=NULL);
  102. ConsoleInterpreter->Register(this);
  103. }
  104. else
  105. {
  106. // RegisterStaticList() has not yet been called, so add this ConFuncT to the waiting list for later registration.
  107. GetStaticList().PushBack(this);
  108. }
  109. }
  110. ConVarT::ConVarT(const std::string& Name_, const int Value_, const int Flags_, const std::string& Description_, const int MinValue_, const int MaxValue_)
  111. : Name(Name_),
  112. Description(Description_),
  113. Flags(Flags_ | FLAG_BY_CODE),
  114. Type(Integer),
  115. ValueString(""),
  116. ValueInt(Value_),
  117. ValueDouble(0.0),
  118. MinValue(MinValue_),
  119. MaxValue(MaxValue_),
  120. AllowedValues(),
  121. IsModified(false)
  122. {
  123. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL)
  124. {
  125. // The StaticList is already in the state that indicates that the ConsoleInterpreter is available now
  126. // and its members have already been registered with it. So register this ConFuncT directly, too.
  127. assert(ConsoleInterpreter!=NULL);
  128. ConsoleInterpreter->Register(this);
  129. }
  130. else
  131. {
  132. // RegisterStaticList() has not yet been called, so add this ConFuncT to the waiting list for later registration.
  133. GetStaticList().PushBack(this);
  134. }
  135. }
  136. ConVarT::ConVarT(const std::string& Name_, const bool Value_, const int Flags_, const std::string& Description_)
  137. : Name(Name_),
  138. Description(Description_),
  139. Flags(Flags_ | FLAG_BY_CODE),
  140. Type(Bool),
  141. ValueString(""),
  142. ValueInt(Value_),
  143. ValueDouble(0.0),
  144. MinValue(0.0),
  145. MaxValue(0.0),
  146. AllowedValues(),
  147. IsModified(false)
  148. {
  149. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL)
  150. {
  151. // The StaticList is already in the state that indicates that the ConsoleInterpreter is available now
  152. // and its members have already been registered with it. So register this ConFuncT directly, too.
  153. assert(ConsoleInterpreter!=NULL);
  154. ConsoleInterpreter->Register(this);
  155. }
  156. else
  157. {
  158. // RegisterStaticList() has not yet been called, so add this ConFuncT to the waiting list for later registration.
  159. GetStaticList().PushBack(this);
  160. }
  161. }
  162. ConVarT::ConVarT(const std::string& Name_, const double Value_, const int Flags_, const std::string& Description_, const double MinValue_, const double MaxValue_)
  163. : Name(Name_),
  164. Description(Description_),
  165. Flags(Flags_ | FLAG_BY_CODE),
  166. Type(Double),
  167. ValueString(""),
  168. ValueInt(0),
  169. ValueDouble(Value_),
  170. MinValue(MinValue_),
  171. MaxValue(MaxValue_),
  172. AllowedValues(),
  173. IsModified(false)
  174. {
  175. if (GetStaticList().Size()>0 && GetStaticList()[0]==NULL)
  176. {
  177. // The StaticList is already in the state that indicates that the ConsoleInterpreter is available now
  178. // and its members have already been registered with it. So register this ConFuncT directly, too.
  179. assert(ConsoleInterpreter!=NULL);
  180. ConsoleInterpreter->Register(this);
  181. }
  182. else
  183. {
  184. // RegisterStaticList() has not yet been called, so add this ConFuncT to the waiting list for later registration.
  185. GetStaticList().PushBack(this);
  186. }
  187. }
  188. ConVarT::~ConVarT()
  189. {
  190. if (Flags & FLAG_PERSISTENT)
  191. {
  192. std::ofstream CfgFile("config_p.lua", std::ios::app);
  193. if (!CfgFile.bad())
  194. {
  195. CfgFile << Name << " = ";
  196. switch (Type)
  197. {
  198. case String: CfgFile << "\"" << ValueString << "\""; break;
  199. case Integer: CfgFile << ValueInt; break;
  200. case Bool: CfgFile << ((ValueInt!=0) ? "true" : "false"); break;
  201. case Double: CfgFile << ValueDouble; break;
  202. }
  203. CfgFile << "\n";
  204. }
  205. }
  206. // Notify the ConsoleInterpreter that we're going down, and e.g. the completion callback is thus not longer available.
  207. // Note that it is possible that ConsoleInterpreter==NULL here, because when it as well as this ConVarT was a static variable,
  208. // it usually is unclear who is destructed before whom.
  209. if (ConsoleInterpreter!=NULL) ConsoleInterpreter->Unregister(this);
  210. }
  211. void ConVarT::SetValue(const std::string& Value_)
  212. {
  213. assert(Type==String);
  214. if (AllowedValues.Size()>0)
  215. {
  216. unsigned long Nr;
  217. for (Nr=0; Nr<AllowedValues.Size(); Nr++)
  218. if (Value_==AllowedValues[Nr]) break;
  219. if (Nr>=AllowedValues.Size()) return;
  220. }
  221. // If the value remains the same, return (don't set the IsModified flag).
  222. if (ValueString==Value_) return;
  223. ValueString=Value_;
  224. IsModified=true;
  225. }
  226. void ConVarT::SetValue(const char* Value_)
  227. {
  228. const std::string Str=Value_ ? Value_ : "NULL";
  229. SetValue(Str);
  230. }
  231. void ConVarT::SetValue(const int Value_)
  232. {
  233. assert(Type==Integer);
  234. if (MinValue<=MaxValue)
  235. {
  236. // If we have a valid min-max range, and the value is outside it, return.
  237. if (double(Value_)<MinValue) return;
  238. if (double(Value_)>MaxValue) return;
  239. }
  240. // If the value remains the same, return (don't set the IsModified flag).
  241. if (ValueInt==Value_) return;
  242. ValueInt=Value_;
  243. IsModified=true;
  244. }
  245. void ConVarT::SetValue(const bool Value_)
  246. {
  247. assert(Type==Bool);
  248. // If the value remains the same, return (don't set the IsModified flag).
  249. if ((ValueInt!=0)==Value_) return;
  250. ValueInt=Value_;
  251. IsModified=true;
  252. }
  253. void ConVarT::SetValue(const double Value_)
  254. {
  255. assert(Type==Double);
  256. if (MinValue<=MaxValue)
  257. {
  258. // If we have a valid min-max range, and the value is outside it, return.
  259. if (Value_<MinValue) return;
  260. if (Value_>MaxValue) return;
  261. }
  262. // If the value remains the same, return (don't set the IsModified flag).
  263. if (ValueDouble==Value_) return;
  264. ValueDouble=Value_;
  265. IsModified=true;
  266. }