khanat-opennel-code/code/ryzom/tools/leveldesign/mission_compiler_lib/mission_compiler.h
2010-09-24 10:27:31 +02:00

542 lines
16 KiB
C++

// 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);
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);