Added ai command setEquipment
[ryzomcore.git] / ryzom / server / src / ai_service / script_vm.h
blob8fcc9ab8bba863eac5effcb68dc082c15303a3b1
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef __SCRIPT_VM__
21 #define __SCRIPT_VM__
23 #include "nel/misc/smart_ptr.h"
24 //#include "ai_grp.h"
26 #include <limits>
28 namespace AIVM
31 /****************************************************************************/
32 /* Compiler classes */
33 /****************************************************************************/
34 //////////////////////////////////////////////////////////////////////////////
35 // Helper classes //
36 //////////////////////////////////////////////////////////////////////////////
38 /// A helper class seperating a string in substrings seperated by a pattern.
39 /** Be carefull, this objet keeps a reference to the string.
41 class CStringSeparator
43 public:
44 CStringSeparator(std::string const& str, std::string const& pattern);
45 virtual ~CStringSeparator();
46 void reset() const;
47 std::string get() const;
48 bool hasNext() const;
49 protected:
50 void calcNext() const;
51 private:
52 mutable size_t _Index;
53 mutable size_t _NewIndex;
54 mutable size_t _Delta;
55 mutable size_t _StartIndex;
56 std::string const& _Str;
57 std::string const _Motif;
60 /****************************************************************************/
61 /* Script Virtual Machine classes */
62 /****************************************************************************/
64 //////////////////////////////////////////////////////////////////////////////
65 // ByteCode interpretation //
66 //////////////////////////////////////////////////////////////////////////////
68 class CByteCode : public NLMISC::CRefCount
70 public:
71 CByteCode(std::string const& sourceName);
72 std::vector<size_t> _opcodes;
73 std::string const _sourceName;
76 class CByteCodeEntry {
77 public:
78 CByteCodeEntry()
79 : _Index(std::numeric_limits<size_t>::max())
82 CByteCodeEntry(NLMISC::CSmartPtr<CByteCode const> code, size_t index)
83 : _Code(code)
84 , _Index(index)
87 bool isValid()const
89 return _Index != std::numeric_limits<size_t>::max();
91 NLMISC::CSmartPtr<CByteCode const>& code() { return _Code; }
92 size_t& index() { return _Index; }
93 NLMISC::CSmartPtr<CByteCode const> const& code() const { return _Code; }
94 size_t const& index() const { return _Index; }
95 private:
96 NLMISC::CSmartPtr<CByteCode const> _Code;
97 size_t _Index;
100 //////////////////////////////////////////////////////////////////////////////
102 class IScriptContext;
104 class CScriptStack
106 public:
107 enum TStackTypes { ENone, EOther, EString, EFloat, EContext };
109 class CStackEntry
111 public:
112 CStackEntry();
113 ~CStackEntry();
115 void clean();
117 CStackEntry& operator=(float const& f);
118 CStackEntry& operator=(int const& i);
119 CStackEntry& operator=(std::string const& str);
120 CStackEntry& operator=(IScriptContext* si);
122 bool operator==(CStackEntry const& other) const;
123 bool operator!=(CStackEntry const& other) const;
124 bool operator<=(CStackEntry const& other) const;
125 bool operator>=(CStackEntry const& other) const;
126 bool operator<(CStackEntry const& other) const;
127 bool operator>(CStackEntry const& other) const;
129 operator float&();
130 operator int&();
131 operator std::string&();
132 operator IScriptContext*();
133 TStackTypes type() const;
135 protected:
136 std::string& getString();
137 std::string const& getString() const;
138 IScriptContext* getIScriptContext();
139 int& getInt();
140 int const& getInt() const;
141 float& getFloat();
142 float const& getFloat() const;
144 union
146 int _vali;
147 uintptr_t _valp;
150 TStackTypes _type;
153 void push(float const& val);
154 void push(std::string const& val);
155 void push(IScriptContext* val);
156 void push(int val);
158 CStackEntry& top(); // is this an optimisation of the method below ?
159 CStackEntry& top(int index);
161 void pop();
163 #if !FINAL_VERSION
164 size_t size()
166 return _Stack.size();
168 #endif
170 private:
171 std::deque<CStackEntry> _Stack;
174 //////////////////////////////////////////////////////////////////////////////
176 class IScriptContext
178 public:
179 virtual std::string getContextName() = 0;
180 virtual void interpretCodeOnChildren(CByteCodeEntry const& codeScriptEntry) = 0;
182 virtual float getLogicVar(NLMISC::TStringId varId) = 0;
183 virtual void setLogicVar(NLMISC::TStringId varId, float value) = 0;
184 virtual std::string getStrLogicVar(NLMISC::TStringId varId) = 0;
185 virtual void setStrLogicVar(NLMISC::TStringId varId, std::string const& value) = 0;
186 virtual IScriptContext* getCtxLogicVar(NLMISC::TStringId varId) = 0;
187 virtual void setCtxLogicVar(NLMISC::TStringId varId, IScriptContext* value) = 0;
189 virtual IScriptContext* findContext(NLMISC::TStringId const strId) = 0;
191 virtual void setScriptCallBack(NLMISC::TStringId const& eventName, CByteCodeEntry const& codeScriptEntry) = 0;
192 virtual CByteCodeEntry const* getScriptCallBackPtr(NLMISC::TStringId const& eventName) const = 0;
193 virtual void callScriptCallBack(IScriptContext* caller, NLMISC::TStringId const& funcName, int mode = 0, std::string const& inParamsSig = "", std::string const& outParamsSig = "", CScriptStack* stack = NULL) = 0;
194 virtual void callNativeCallBack(IScriptContext* caller, std::string const& funcName, int mode = 0, std::string const& inParamsSig = "", std::string const& outParamsSig = "", CScriptStack* stack = NULL) = 0;
197 class CScriptVM
199 public:
200 // Operations behave on stack elems.
201 enum EOpcode
203 /*00*/ INVALID_OPCODE=0,
204 /*01*/ EOP, // End Of Program
205 // Need: - After: -
206 // Need: FuncName, NbParams, Params .. After: ReturnValue (1)
207 /*02*/ EQ, // == StackBef: Value1,Value2 StackAft: Value1==Value2 (Boolean as float)
208 /*03*/ NEQ, // != StackBef: Value1,Value2 StackAft: Value1!=Value2 (Boolean as float)
209 /*04*/ INF, // < StackBef: Value1,Value2 StackAft: Value1<Value2 (Boolean as float)
210 /*05*/ INFEQ, // <= StackBef: Value1,Value2 StackAft: Value1<=Value2 (Boolean as float)
211 /*06*/ SUP, // > StackBef: Value1,Value2 StackAft: Value1>Value2 (Boolean as float)
212 /*07*/ SUPEQ, // >= StackBef: Value1,Value2 StackAft: Value1>=Value2 (Boolean as float)
213 /*08*/ ADD, // + StackBef: Value1,Value2 StackAft: Value1+Value2
214 /*09*/ SUB, // - StackBef: Value1,Value2 StackAft: Value1-Value2
215 /*0a*/ MUL, // * StackBef: Value1,Value2 StackAft: Value1/Value2
216 /*0b*/ DIV, // / StackBef: Value1,Value2 StackAft: Value1/Value2 !Exception Gestion.
217 /*0c*/ AND, // && StackBef: Value1,Value2 StackAft: Value1&&Value2
218 /*0d*/ OR, // || StackBef: Value1,Value2 StackAft: Value1||Value2
219 /*0e*/ NOT, // ! StackBef: Value StackAft: !Value
220 /*0f*/ PUSH_ON_STACK, // Set a Value (Float,TStringId .. etc) StackBef: - StackAft: Value
221 /*10*/ POP, // Pop StackBef: Value StackAft: -
222 /*11*/ SET_VAR_VAL, // Set a value to a float variable. Code: VarName StackBef: VarValue StackAft: -
223 /*12*/ SET_STR_VAR_VAL, // Set a value to a string variable. Code: VarName StackBef: VarValue StackAft: -
224 /*13*/ SET_CTX_VAR_VAL, // Set a value to a context variable. Code: VarName StackBef: VarValue StackAft: -
225 /*14*/ PUSH_VAR_VAL, // Push the value of a float variable. Code: VarName StackBef: - StackAft: VarValue
226 /*15*/ PUSH_STR_VAR_VAL, // Push the value of a string variable. Code: VarName StackBef: - StackAft: VarValue
227 /*16*/ PUSH_CTX_VAR_VAL, // Push the value of a context variable. Code: VarName StackBef: - StackAft: VarValue
228 /*17*/ // SET_OTHER_VAR_VAL, // Set a value to a float variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
229 /*18*/ // SET_OTHER_STR_VAR_VAL, // Set a value to a string variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
230 /*19*/ // SET_OTHER_CTX_VAR_VAL, // Set a value to a context variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
231 /*1a*/ // PUSH_OTHER_VAR_VAL, // Push the value of a float variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
232 /*1b*/ // PUSH_OTHER_STR_VAR_VAL, // Push the value of a string variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
233 /*1c*/ // PUSH_OTHER_CTX_VAR_VAL, // Push the value of a context variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
234 /*1d*/ SET_CONTEXT_VAR_VAL, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
235 /*1e*/ SET_CONTEXT_STR_VAR_VAL, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
236 /*1f*/ SET_CONTEXT_CTX_VAR_VAL, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
237 /*20*/ PUSH_CONTEXT_VAR_VAL, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
238 /*21*/ PUSH_CONTEXT_STR_VAR_VAL, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
239 /*22*/ PUSH_CONTEXT_CTX_VAR_VAL, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
240 /*23*/ JUMP, // Jump + nb size_t to jump (relative). Code: JumpOffset StackBef: - StackAft: - //< May be innaccurate
241 /*24*/ JE, // Jump if last stack value is FALSE(==0). Code: JumpOffset StackBef: Bool(float) StackAft: - //< May be innaccurate
242 /*25*/ JNE, // Jump if last stack value is TRUE(==1). Code: JumpOffset StackBef: Bool(float) StackAft: - //< May be innaccurate
243 /*26*/ PUSH_PRINT_STRING,
244 /*27*/ PUSH_PRINT_VAR,
245 /*28*/ PUSH_PRINT_STR_VAR,
246 /*29*/ PRINT_STRING,
247 /*2a*/ LOG_STRING,
248 /*2b*/ FUNCTION,
249 /*2c*/ CALL,
250 /*2d*/ PUSH_THIS,
251 /*2e*/ PUSH_GROUP,
252 /*2f*/ PUSH_STRING,
253 /*30*/ ASSIGN_FUNC_FROM,
254 /*31*/ NATIVE_CALL,
255 /*32*/ RAND,
256 /*33*/ RANDEND,
257 /*34*/ RET, // Get the value on the pile to retrieve the good IP (absolute).
258 /*35*/ ONCHILDREN,
259 /*36*/ SWITCH,
260 /*37*/ INCR,
261 /*38*/ DECR,
262 /*39*/ CONCAT,
263 /*3a*/ FTOS,
266 public:
267 void interpretCode(
268 IScriptContext* thisContext,
269 IScriptContext* parentContext,
270 IScriptContext* callerContext,
271 CByteCodeEntry const& codeScriptEntry);
272 static CScriptVM* getInstance();
273 static void destroyInstance();
274 private:
275 uint32 rand32(uint32 mod)
277 if (mod==0) return 0;
278 return ((((uint32)_Random.rand())<<16) + (uint32)_Random.rand()) % mod;
280 static CScriptVM* _Instance;
281 NLMISC::CRandom _Random;
284 //////////////////////////////////////////////////////////////////////////////
286 class CLibrary
288 public:
289 static CLibrary& getInstance();
290 static void destroyInstance();
292 void addLib(std::string const& name, std::string const& code);
293 void addLib(std::string const& name, std::vector<std::string> const& code);
294 void addLib(std::string const& name, NLMISC::CSmartPtr<CByteCode const> const& byteCode);
295 NLMISC::CSmartPtr<CByteCode const> getLib(std::string const& name);
297 protected:
298 CLibrary() { }
300 private:
301 typedef std::map<std::string, NLMISC::CSmartPtr<CByteCode const> > TLibContainer;
302 static CLibrary* _instance;
303 static TLibContainer _libs;
306 /****************************************************************************/
307 /* Inlined functions */
308 /****************************************************************************/
310 inline
311 CByteCode::CByteCode(std::string const& sourceName)
312 : _sourceName(sourceName)
316 inline
317 CLibrary& CLibrary::getInstance()
319 if (_instance==NULL)
320 _instance = new CLibrary();
321 return *_instance;
324 inline
325 void CLibrary::destroyInstance()
327 if (_instance!=NULL)
329 delete _instance;
330 _instance = NULL;
334 inline
335 CScriptStack::CStackEntry::CStackEntry()
336 : _type(ENone)
340 inline
341 CScriptStack::CStackEntry::~CStackEntry()
343 clean();
346 inline
347 void CScriptStack::CStackEntry::clean()
349 if (_type==EString)
350 delete &getString();
353 inline
354 CScriptStack::CStackEntry& CScriptStack::CStackEntry::operator=(float const& f)
356 clean();
357 _vali = *((int*)&f);
358 _type = EFloat;
359 return *this;
361 inline
362 CScriptStack::CStackEntry& CScriptStack::CStackEntry::operator=(int const& i)
364 clean();
365 _vali = i;
366 _type = EOther;
367 return *this;
369 inline
370 CScriptStack::CStackEntry& CScriptStack::CStackEntry::operator=(std::string const& str)
372 clean();
373 std::string* const strPt = new std::string(str);
374 _valp = *((uintptr_t*)&strPt);
375 _type = EString;
376 return *this;
378 inline
379 CScriptStack::CStackEntry& CScriptStack::CStackEntry::operator=(IScriptContext* sc)
381 clean();
382 _valp = *((uintptr_t*)&sc);
383 _type = EContext;
384 return *this;
387 inline
388 bool CScriptStack::CStackEntry::operator==(CStackEntry const& other) const
390 nlassert(_type==other._type);
391 switch (_type)
393 case EString:
394 return getString()==other.getString();
395 case EFloat:
396 return getFloat()==other.getFloat();
397 case EContext:
398 return _valp==other._valp;
399 case EOther:
400 default:
401 return _vali==other._vali;
405 inline
406 bool CScriptStack::CStackEntry::operator!=(CStackEntry const& other) const
408 return !(*this == other);
411 inline
412 bool CScriptStack::CStackEntry::operator<=(CStackEntry const& other) const
414 return !(*this > other);
417 inline
418 bool CScriptStack::CStackEntry::operator>=(CStackEntry const& other) const
420 return !(*this < other);
423 inline
424 bool CScriptStack::CStackEntry::operator<(CStackEntry const& other) const
426 nlassert(_type==other._type);
427 switch (_type)
429 case EString:
430 return getString()<other.getString();
431 case EFloat:
432 return getFloat()<other.getFloat();
433 case EContext:
434 return _valp<other._valp;
435 case EOther:
436 default:
437 return _vali<other._vali;
441 inline
442 bool CScriptStack::CStackEntry::operator>(CStackEntry const& other) const
444 nlassert(_type==other._type);
445 switch (_type)
447 case EString:
448 return getString()>other.getString();
449 case EFloat:
450 return getFloat()>other.getFloat();
451 case EContext:
452 return _valp>other._valp;
453 case EOther:
454 default:
455 return _vali>other._vali;
459 inline
460 CScriptStack::CStackEntry::operator float&()
462 return getFloat();
464 inline
465 CScriptStack::CStackEntry::operator int&()
467 return getInt();
469 inline
470 CScriptStack::CStackEntry::operator std::string&()
472 return getString();
474 inline
475 CScriptStack::CStackEntry::operator IScriptContext*()
477 return getIScriptContext();
480 inline
481 CScriptStack::TStackTypes CScriptStack::CStackEntry::type() const
483 return _type;
486 inline
487 std::string& CScriptStack::CStackEntry::getString()
489 nlassert(_type==EString);
490 return *(*((std::string**)&_valp));
492 inline
493 std::string const& CScriptStack::CStackEntry::getString() const
495 nlassert(_type==EString);
496 return *(*((std::string**)&_valp));
498 inline
499 IScriptContext* CScriptStack::CStackEntry::getIScriptContext()
501 nlassert(_type==EContext);
502 return *((IScriptContext**)&_valp);
504 inline
505 int& CScriptStack::CStackEntry::getInt()
507 nlassert(_type==EOther);
508 return _vali;
510 inline
511 int const& CScriptStack::CStackEntry::getInt() const
513 nlassert(_type==EOther);
514 return _vali;
516 inline
517 float& CScriptStack::CStackEntry::getFloat()
519 nlassert(_type==EFloat);
520 return *((float*)&_vali);
522 inline
523 float const& CScriptStack::CStackEntry::getFloat() const
525 nlassert(_type==EFloat);
526 return *((float const*)&_vali);
529 inline
530 void CScriptStack::push(float const& val)
532 _Stack.push_back(CStackEntry());
533 _Stack.back() = val;
535 inline
536 void CScriptStack::push(std::string const& val)
538 _Stack.push_back(CStackEntry());
539 _Stack.back() = val;
541 inline
542 void CScriptStack::push(IScriptContext* val)
544 _Stack.push_back(CStackEntry());
545 _Stack.back() = val;
547 inline
548 void CScriptStack::push(int val)
550 _Stack.push_back(CStackEntry());
551 _Stack.back() = val;
554 inline
555 CScriptStack::CStackEntry& CScriptStack::top() // is this an optimisation of the method below ?
557 return _Stack.back();
559 inline
560 CScriptStack::CStackEntry& CScriptStack::top(int index)
562 return *(_Stack.rbegin()+index);
565 inline
566 void CScriptStack::pop()
568 _Stack.pop_back();
571 inline
572 CStringSeparator::CStringSeparator(const std::string &str, const std::string &motif)
573 :_Index(0)
574 ,_NewIndex(0)
575 ,_Delta(0)
576 ,_StartIndex(0)
577 ,_Str(str)
578 ,_Motif(motif)
581 inline
582 CStringSeparator::~CStringSeparator()
585 inline
586 void CStringSeparator::reset() const
588 _Index=0;
589 _NewIndex=0;
590 _Delta=0;
591 _StartIndex=0;
593 inline
594 std::string CStringSeparator::get() const
596 #if !FINAL_VERSION
597 nlassert(_Delta>0);
598 #endif
599 return _Str.substr(_StartIndex, _Delta);
601 inline
602 bool CStringSeparator::hasNext() const
604 calcNext();
605 return _Delta>0;
607 inline
608 void CStringSeparator::calcNext() const
610 _Delta = 0;
611 while ( _Index!=std::string::npos
612 && _Delta==0)
614 _NewIndex = _Str.find_first_of(_Motif, _Index);
615 _StartIndex = _Index;
616 _Delta = ((_NewIndex==std::string::npos)?_Str.size():_NewIndex)-_Index;
617 if (_NewIndex==std::string::npos)
619 _Index = std::string::npos;
620 break;
622 _Index = _Str.find_first_not_of(_Motif, _NewIndex);
626 } // namespace
628 #endif