Planeshift

mathscript.h

Go to the documentation of this file.
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