Planeshift
|
00001 /* 00002 * mathscript.h by Keith Fulton <[email protected]> 00003 * 00004 * Copyright (C) 2010 Atomic Blue ([email protected], http://www.atomicblue.org) 00005 * 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation (version 2 of the License) 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * 00018 */ 00019 #ifndef __MATHSCRIPT_H__ 00020 #define __MATHSCRIPT_H__ 00021 00022 #include <../tools/fparser/fparser.h> 00023 #include <csutil/csstring.h> 00024 #include <csutil/hash.h> 00025 #include <csutil/randomgen.h> 00026 #include <csutil/set.h> 00027 #include <csutil/strset.h> 00028 #include <util/scriptvar.h> 00029 #include <csutil/weakreferenced.h> 00030 #include <csutil/weakref.h> 00031 00032 #ifdef _MSC_VER 00033 double round(double value); 00034 #endif 00035 00036 class MathScript; 00037 class MathVar; 00038 struct iDataConnection; 00039 00051 class MathScriptEngine 00052 { 00053 protected: 00054 csHash<MathScript*, csString> scripts; 00055 static csRandomGen rng; 00056 00057 static csStringSet stringLiterals; 00058 static csStringSet customCompoundFunctions; 00059 00060 00061 csString mathScriptTable; 00062 00063 public: 00064 union IDConverter 00065 { 00066 double value; // masked float value 00067 struct 00068 { 00069 #ifdef CS_LITTLE_ENDIAN 00070 CS_ALIGNED_MEMBER(uint32 value,1); // value of the ID 00071 CS_ALIGNED_MEMBER(uint16 ignored,1); // ignored part 00072 CS_ALIGNED_MEMBER(uint16 mask,1); // mask used to identify strings/objects 00073 #else 00074 CS_ALIGNED_MEMBER(uint16 mask,1); // mask used to identify strings/objects 00075 CS_ALIGNED_MEMBER(uint16 ignored,1); // ignored part 00076 CS_ALIGNED_MEMBER(uint32 value,1); // value of the ID 00077 #endif 00078 } ID; 00079 uintptr_t p; // packed pointer 00080 }; 00081 00082 MathScriptEngine(iDataConnection* db, const csString& mathScriptTable); 00083 ~MathScriptEngine(); 00084 00086 MathScript* FindScript(const csString& name); 00087 00091 void ReloadScripts(iDataConnection* db); 00092 00097 bool LoadScripts(iDataConnection* db, bool reload = false); 00098 00102 void UnloadScripts(); 00103 00108 static CS::StringIDValue GetCompoundFunction(const csString& name) 00109 { 00110 return customCompoundFunctions.Request(name); 00111 } 00112 00114 static const char* Request(uint32 ID) 00115 { 00116 return stringLiterals.Request(ID); 00117 } 00118 00120 static const char* Request(double f) 00121 { 00122 // initialize ID conversion 00123 IDConverter ID; 00124 ID.value = f; 00125 ID.ID.mask &= 0xFFF0; 00126 00127 // check the mask matches our string mask 00128 if(ID.ID.mask != 0xFFF0) 00129 { 00130 // not a string 00131 return ""; 00132 } 00133 00134 // we seem to have an ID here, retrieve the associated 00135 // string and return it 00136 return Request(ID.ID.value); 00137 } 00138 00140 static uint32 RequestID(const char* str) 00141 { 00142 return stringLiterals.Request(str); 00143 } 00144 00146 static double Request(const char* str) 00147 { 00148 // intialize the ID conversion 00149 IDConverter ID; 00150 00151 // set our string mask so the value will be recognizable 00152 ID.ID.mask = 0xFFF0; 00153 00154 // initialize the part we won't use 00155 ID.ID.ignored = 0; 00156 00157 // retrieve the ID 00158 ID.ID.value = RequestID(str); 00159 00160 // return the masked value 00161 return ID.value; 00162 } 00163 00165 static bool HasString(const char* str) 00166 { 00167 return stringLiterals.Contains(str); 00168 } 00169 00174 static double CustomCompoundFunc(const double * parms); 00175 00177 static double RandomGen(const double *dummy); 00178 00180 static csString FormatMessage(const csString& formatString, size_t arg_count, const double* parms); 00181 }; 00182 00188 class MathEnvironment 00189 { 00190 private: 00191 MathVar* GetVar(const char* name); 00192 00194 uint32* UID; 00196 csHash<iScriptableVar*,uint32> scriptableVariables; 00198 csHash<uint32,iScriptableVar*> scriptableRegistry; 00199 00201 csStringSet stringLiterals; 00202 00203 const MathEnvironment *parent; 00204 csHash<MathVar*, csString> variables; 00205 00206 void Init(); 00207 00208 // environments mustn't be copy-constructed 00209 MathEnvironment(const MathEnvironment&); 00210 00211 public: 00212 MathEnvironment() : UID(new uint32),parent(NULL) 00213 { 00214 *UID = 0; 00215 Init(); 00216 } 00217 MathEnvironment(const MathEnvironment *parent) : UID(parent->UID),parent(parent) 00218 { 00219 Init(); 00220 } 00221 ~MathEnvironment(); 00222 00224 void Define(const char *name, double value); 00225 00227 void Define(const char *name, iScriptableVar* obj); 00228 00230 void Define(const char *name, const char* str); 00231 00233 bool HasString(const char* p) const; 00234 00236 bool HasObject(iScriptableVar* p) const; 00237 00239 csString GetString(double id) const; 00240 00242 double GetValue(iScriptableVar* p); 00243 00245 iScriptableVar* GetPointer(double id) const; 00246 00248 double GetValue(const char* p); 00249 00250 MathVar* Lookup(const char *name) const; 00251 void DumpAllVars() const; 00252 00254 void InterpolateString(csString & str) const; 00255 }; 00256 00258 enum MathType 00259 { 00260 VARTYPE_VALUE, 00261 VARTYPE_STR, 00262 VARTYPE_OBJ 00263 }; 00264 00270 class MathVar 00271 { 00272 protected: 00273 double value; 00274 MathEnvironment* parent; 00275 00276 typedef void (*MathScriptVarCallback)(void* arg); 00277 MathScriptVarCallback changedVarCallback; 00278 void* changedVarCallbackArg; 00279 00280 public: 00281 MathVar(MathEnvironment* parent) : value(0.f),parent(parent), 00282 changedVarCallback(NULL), 00283 changedVarCallbackArg(NULL) 00284 { 00285 } 00286 00287 void SetChangedCallback(MathScriptVarCallback callback, void* arg) 00288 { 00289 changedVarCallback = callback; 00290 changedVarCallbackArg = arg; 00291 } 00292 00293 void SetValue(double v); 00294 void SetObject(iScriptableVar* p); 00295 void SetString(const char* p); 00296 00297 MathType Type() const; 00298 00299 inline int GetRoundValue() const 00300 { 00301 return (int)round(GetValue()); 00302 } 00303 00304 inline double GetValue() const 00305 { 00306 return value; 00307 } 00308 00309 inline iScriptableVar* GetObject() const 00310 { 00311 return parent->GetPointer(value); 00312 } 00313 00314 inline csString GetString() const 00315 { 00316 return parent->GetString(value); 00317 } 00318 00319 csString ToString() const; 00320 csString Dump() const; 00321 }; 00322 00330 class MathExpression 00331 { 00332 protected: 00333 enum 00334 { 00335 MATH_NONE = 0, // NOP 00336 MATH_COND = 1, // is a conditional 00337 MATH_EXP = 2, // has expression 00338 MATH_LOOP = 4, // is a loop 00339 MATH_ASSIGN = 8, // is an assignment 00340 MATH_BREAK = 16, // flow control break 00341 00342 // aliases 00343 MATH_WHILE = MATH_COND | MATH_EXP | MATH_LOOP, 00344 MATH_IF = MATH_COND | MATH_EXP, 00345 MATH_ELSE = MATH_COND, 00346 MATH_DO = MATH_EXP | MATH_LOOP 00347 }; 00348 size_t opcode; // opcode of this expression 00349 00350 MathExpression(); // may only be constructed via MathExpression::Create 00351 00352 bool Parse(const char *expression); 00353 00354 struct PropertyRef 00355 { 00356 csString object; // name of the object this property refers to 00357 csString property; // property to be retrieved 00358 00359 // required to be used in csHash as used by csSet 00360 uint GetHash() const 00361 { 00362 return (object+":"+property).GetHash(); 00363 } 00364 00365 // required by csComparator used in csHash used by csSet 00366 bool operator<(const PropertyRef& rhs) const 00367 { 00368 return (object+":"+property) < (rhs.object+":"+rhs.property); 00369 } 00370 }; 00371 00372 csSet<csString> requiredVars; 00373 csSet<csString> requiredObjs; 00374 csSet<PropertyRef> propertyRefs; 00375 mutable FunctionParser fp; 00376 00377 const char *name; // used for debugging 00378 00379 public: 00380 virtual ~MathExpression() {} 00381 static MathExpression* Create(const char *expression, const char *name = ""); 00382 00383 virtual double Evaluate(MathEnvironment *env) const; 00384 00385 size_t GetOpcode() const 00386 { 00387 return opcode; 00388 } 00389 00390 void SetOpcode(size_t newOpcode) 00391 { 00392 opcode = newOpcode; 00393 } 00394 }; 00395 00404 class MathStatement : public MathExpression 00405 { 00406 protected: 00407 MathStatement() { } // may only be constructed via MathStatement::Create 00408 00409 csString assignee; 00410 00411 public: 00412 static MathStatement* Create(const csString & expression, const char *name); 00413 double Evaluate(MathEnvironment *env) const; 00414 }; 00415 00420 class EmptyMathStatement : public MathExpression 00421 { 00422 public: 00423 EmptyMathStatement() 00424 { 00425 opcode = MATH_NONE; 00426 } 00427 00428 double Evaluate(MathEnvironment* /*env*/) const 00429 { 00430 return 0; 00431 } 00432 }; 00433 00434 00442 class MathScript : private MathExpression 00443 { 00444 protected: 00445 MathScript(const char *name) : name(name) { } // may only be constructed using MathScript::Create 00446 csString name; 00447 csArray<MathExpression*> scriptLines; 00448 00449 public: 00450 static MathScript* Create(const char *name, const csString & script); 00451 static void Destroy(MathScript* &mathScript); 00452 00453 ~MathScript(); 00454 00455 const csString & Name() const 00456 { 00457 return name; 00458 } 00459 00460 void CopyAndDestroy(MathScript* other); 00461 00462 double Evaluate(MathEnvironment *env) const; 00463 }; 00464 00467 #endif 00468