// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/string_common.h" #include "nel/misc/path.h" #include "nel/misc/sstring.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/factory.h" #include "nel/ligo/primitive.h" #include "nel/ligo/primitive_utils.h" #include "nel/ligo/ligo_config.h" #include "../../../common/src/game_share/string_manager_sender.h" #include "nel/misc/string_conversion.h" #include <string> #include <numeric> class CMissionData; class IStep; const std::string NL("\n\r"); /// Exception thows when the parser meet somethink invalid. struct EParseException { EParseException(NLLIGO::IPrimitive *prim, const char *why) : Primitive(prim), Why(why) { } NLLIGO::IPrimitive *Primitive; std::string Why; }; // utility to untag a variable (tag are the '$' added before and after the var name) inline void untagVar(std::string &var) { if (!var.empty()) { if (var[0] != '$') var = ""; else { var = var.substr(1); if (var[var.size()-1] != '$') var = ""; else var = var.substr(0, var.size()-1); } } } // utility to 'tabulate' the lines in a string void tabulateLine(std::string &text, uint nbTabs); /* Interface class for variables types*/ class IVar { public: typedef NLLIGO::IPrimitive * TCtorParam; enum TVarType { vt_integer, vt_npc, vt_item, vt_place, vt_text }; IVar(TVarType type, NLLIGO::IPrimitive *prim) { _VarType = type; _VarName = getPrimProperty(prim, "var_name"); } // force virtual destructor virtual ~IVar() {} /** Return the variable type. Should return a string to * limit coupling with implementation ? */ TVarType getVarType() const { return _VarType; } /** Return the type of the variable as defined in the string manager. * Can return NB_ENTITY_TYPES for compiler variable that don't match * to a type in the string manager. */ virtual STRING_MANAGER::TParamType getStringManagerType()=0; /// Return the name of the variable. const std::string getVarName() const { return _VarName; } /// Evaluate the content of the variable with an optional sub part. virtual std::string evalVar(const std::string &subPart) = 0; /** Factory method to create new variable. Caller become responsible * for deleting the allocated variable. */ static IVar *createVar(CMissionData &md, NLLIGO::IPrimitive *prim); /// Generate variable declaration in mission script virtual std::string genDecl(CMissionData &md) = 0; /// Generate the phrase virtual std::string genPhrase() { static std::string emptyString; return emptyString; } protected: /// Helper function to read a primitive property. std::string getPrimProperty(NLLIGO::IPrimitive *prim, const std::string &propName) { std::string *s; if (prim->getPropertyByName(propName.c_str(), s)) return *s; else return ""; } /// Helper function to read a primitive array property std::vector<std::string> getPrimPropertyArray(NLLIGO::IPrimitive *prim, const std::string &propName) { std::vector<std::string> *sv; if (prim->getPropertyByName(propName.c_str(), sv)) return *sv; else return std::vector<std::string>(); } protected: /// Variable type. TVarType _VarType; /// Variable name. std::string _VarName; }; class CMissionData; /** Class for text management. * Handle different expression of text such * phrase identifier, reference to text variable * or literal string. * The class also handle the parameter list for * the phrase. */ class CPhrase { public: /// Structure to store phrase parameters infos. struct TParamInfo { /// The name of the parameter std::string ParamName; /// Compiler param std::string CompilerParam; /// The type of the parameters (as defined in the string manager). STRING_MANAGER::TParamType ParamType; TParamInfo() : ParamType(STRING_MANAGER::NB_PARAM_TYPES) { } TParamInfo(const std::string &name, STRING_MANAGER::TParamType type, const std::string &compilerParam = "") : ParamName(name), ParamType(type), CompilerParam(compilerParam) { } }; typedef std::vector<std::vector<TParamInfo> > TPredefParams; private: /** Number of variant for this phrase. * Zero denote that there is no variant, thus no need to add * a postfix number after the phrase identifier for literal * generated phrase. */ uint32 _NumEntry; /** The phrase id. This is the identifier that must be use with the * string manager. */ std::string _PhraseId; /** String literal value. When the user fill a quoted string, then * this property receive the string value of the quoted string. */ std::vector<std::string> _PhraseLiterals; /** Suffixe for literal string identifier */ std::string _Suffixe; /// The list of default parameters. TPredefParams _DefaultParams; /// The list of additional parameters. std::vector<TParamInfo> _AdditionalParams; public: /// init the phrase void initPhrase (CMissionData &md, NLLIGO::IPrimitive *prim, const std::vector<std::string> &texts, uint32 numEntry = 0, const TPredefParams &predefParams = TPredefParams()); /// generate the common string script for any script instruction. std::string genScript(CMissionData &md); /** generate the phrase file content. Return empty string * if the phrase is not a literal. */ std::string genPhrase(); /// Test if the phrase is empty bool isEmpty(); /// Test if the phrase contains some additionnal parameters bool asAdditionnalParams(); }; /* Class for jumps */ struct TJumpInfo { std::string StepName; std::string JumpName; bool Discardable; TJumpInfo(const std::string &stepName, const std::string &jumpName = std::string(), bool discardable = true) : StepName(stepName), JumpName(jumpName), Discardable(discardable) {} bool operator <(const TJumpInfo &other) const { return StepName < other.StepName; } }; /* Class for mission information storing */ class CMissionData : public NLMISC::CRefCount { public: CMissionData(); ~CMissionData(); // void setAlias(const std::string &alias) { _Alias = alias; } // const std::string &getAlias() { return _Alias; } void setMissionName(const std::string &missionName); const std::string &getMissionName(); const std::string &getGiverPrimitive() { return _GiverPrimitive; } void setGiverPrimitive(const std::string &giverPrimitive) { _GiverPrimitive = giverPrimitive; } const std::string &getGiverName() { return _MissionGiver; } void setGiverName(const std::string &giverName) { _MissionGiver = giverName; } bool addVariable(NLLIGO::IPrimitive *prim, IVar *var); IVar *getVariable(const std::string &varName); bool addStep(IStep *step); void addStepName(const std::string &name, IStep *step) { _StepsByNames[name] = step; } IStep *getNextStep(IStep *current); IStep *getStepByName(const std::string &stepName); std::string generateMissionScript(const std::string &primFileName); std::string generatePhraseFile(); std::string generateDotScript(); void parseMissionHeader(NLLIGO::IPrimitive *prim); void initHeaderPhrase(NLLIGO::IPrimitive *prim); void parsePrerequisites(NLLIGO::IPrimitive *prim); std::string replaceVar(NLLIGO::IPrimitive *prim, const std::string &str); std::vector<std::string> replaceVar(NLLIGO::IPrimitive *prim, const std::vector<std::string> &strs); std::string getProperty(NLLIGO::IPrimitive *prim, const std::string &propertyName, bool replaceVar, bool canFail); std::vector<std::string> getPropertyArray(NLLIGO::IPrimitive *prim, const std::string &propertyName, bool replaceVar, bool canFail); bool isThereAJumpTo(const std::string &stepName); bool isGuildMission() const { return _Guild; } private: std::string genPreRequisites(); // forbidden copy constructor ! CMissionData(const CMissionData &other) { nlstop; } // std::string _Alias; std::string _MissionName; std::string _MissionGiver; std::string _GiverPrimitive; bool _MonoInstance; bool _RunOnce; bool _Replayable; bool _Solo; bool _Guild; bool _NotInJournal; bool _AutoRemoveFromJournal; // When mission ends (fail or success) automatically remove it from the journal std::string _MissionCategory; uint32 _PlayerReplayTimer; uint32 _GlobalReplayTimer; bool _NotProposed; bool _NonAbandonnable; bool _NeedValidation; bool _FailIfInventoryIsFull; std::string _MissionIcon; std::vector<std::string> _MissionTitleRaw; CPhrase _MissionTitle; std::vector<std::string> _MissionDescriptionRaw; CPhrase _MissionDescription; bool _MissionAuto; std::vector<std::string> _MissionAutoMenuRaw; CPhrase _MissionAutoMenu; ////// Pre requisites ///////// struct TReqSkill { std::string Skill; std::string MinLevel; std::string MaxLevel; }; struct TReqFame { std::string Faction; std::string Fame; }; std::vector<TReqSkill> _ReqSkills; std::vector<std::string> _ReqMissionDone; std::vector<std::string> _ReqMissionNotDone; std::vector<std::string> _ReqMissionRunning; std::vector<std::string> _ReqMissionNotRunning; std::vector<std::string> _ReqWearItem; std::vector<std::string> _ReqOwnItem; std::string _ReqTitle; std::vector<TReqFame> _ReqFames; bool _ReqGuild; std::string _ReqGrade; std::string _ReqTeamSize; std::vector<std::string> _ReqBrick; std::string _ReqSeason; // bool _ReqEncycloTasksDone; std::string _ReqEncyclo; std::string _ReqEncycloNeg; std::string _ReqEventFaction; /// The list of parent missions std::set<std::string> _ParentMissions; /// The list of variable by name std::map<std::string, IVar*> _Variables; /// The list of variable in primitive order std::vector<IVar*> _VariablesOrder; /// the list of step in execution order std::vector<IStep*> _Steps; /// The list of step sorted by step name std::map<std::string, IStep *> _StepsByNames; std::set<TJumpInfo> _JumpPoints; }; typedef NLMISC::CSmartPtr<CMissionData> TMissionDataPtr; /** This class manage the compilation of missions contained under a * primitive file node. */ class CMissionCompiler { public: /** Generate the dot language script for the missions under the specified node. * This method is primarily used for world editor mission display. */ // std::vector<std::string> generateDotScript(NLLIGO::NLLIGO::IPrimitive *rootPrim); bool generateDotScript(NLLIGO::IPrimitive *missionPrim, std::string &dotScript, std::string &log); /** compile one mission. The primitive node must be * a mission tree root node. * fileName must receive the primitive file name. It is used */ bool compileMission(NLLIGO::IPrimitive *rootPrim, const std::string &primFileName); /** Compile all the missions found under the given primitive node. * The primitive tree is searched recursively ti find all the * mission tree nodes. * All the compiled missions are stored internaly in precompiled form. */ bool compileMissions(NLLIGO::IPrimitive *rootPrim, const std::string &primFileName); /** Install the generated script into the destination primitive files */ bool installCompiledMission(NLLIGO::CLigoConfig &ligoConfig, const std::string &primFileName); /// Publish the modified to the path parameter bool publishFiles(const std::string &serverPathPrim, const std::string &serverPathText, const std::string &localPathText); /// Search for text in the file : add it if it's not in bool includeText(const std::string filename, const std::string text); /// Parse the pre requisite node of a mission. bool parsePreRequisite(CMissionData &md, NLLIGO::IPrimitive *preReq); /// Parse the steps of a missions. bool parseSteps(CMissionData &md, NLLIGO::IPrimitive *steps, IStep *parent=NULL); bool parseOneStep(CMissionData &md, NLLIGO::IPrimitive *stepToParse, IStep *parent, bool bEndOfBranch); /// Helper to retrive a property in a primitive node. std::string getProp(NLLIGO::IPrimitive *prim, const std::string &propName); /// Helper to retreive the class name of a primitive node. std::string getClass(NLLIGO::IPrimitive *prim); /// Parse the variable of a missions. bool parseVariables(CMissionData &md, NLLIGO::IPrimitive *variables); /// Get full paths of files to publish uint getFileToPublishCount() { return (uint)_FilesToPublish.size(); } std::string getFileToPublish(uint index) { nlassert(index < _FilesToPublish.size()); return _FilesToPublish[index]; } std::vector <TMissionDataPtr> &getMissions() { return _CompiledMission; } uint getMissionsCount() { return (uint)_CompiledMission.size(); } TMissionDataPtr getMission(uint index) { nlassert(index < _CompiledMission.size()); return _CompiledMission[index]; } private: /// Storage for loaded primitive struct TLoadedPrimitive { NLLIGO::CPrimitives *PrimDoc; std::string FullFileName; TLoadedPrimitive() : PrimDoc(NULL) {} TLoadedPrimitive(NLLIGO::CPrimitives *primDoc, const std::string &fullFileName) : PrimDoc(primDoc), FullFileName(fullFileName) { } }; /// Storage for precompiled missions. std::vector <TMissionDataPtr> _CompiledMission; /// Storage for files to publish std::vector<std::string> _FilesToPublish; }; // Class to easily handle var and var name pair struct TCompilerVarName { typedef std::vector <std::vector<struct TCompilerVarName> > TPredefParams; // Default parameter name std::string _DefaultName; // Type of script parameter STRING_MANAGER::TParamType _ParamType; // the name of the compiler var, like 'the_creature' in $the_creature$ = chab1 std::string _VarName; // the value of the compiler var line 'chab1' in $the_creature$ = chab1 std::string _VarValue; void init(const std::string &defaultName, STRING_MANAGER::TParamType type, CMissionData &md, NLLIGO::IPrimitive *prim, const std::string propName); void initWithText(const std::string &defaultName, STRING_MANAGER::TParamType type, CMissionData &md, NLLIGO::IPrimitive *prim, const std::string &text); CPhrase::TParamInfo getParamInfo() const; bool empty() const; operator const std::string () const; operator CPhrase::TParamInfo() const; //static void getPhrasePredef(const TCompilerVarName::TPredefParams& compilerParams, CPhrase::TPredefParams& params); static std::vector<TCompilerVarName> getPropertyArrayWithText(const std::string &defaultName, STRING_MANAGER::TParamType type, CMissionData &md, NLLIGO::IPrimitive *prim, const std::string & arrayProperyName); static std::vector<TCompilerVarName> getPropertyArrayWithTextStaticDefaultName(const std::string &defaultName, STRING_MANAGER::TParamType type, CMissionData &md, NLLIGO::IPrimitive *prim, const std::string & arrayProperyName); }; std::string operator+(const TCompilerVarName& left, const std::string & right); std::string operator+(const std::string & left, const TCompilerVarName& right);