*New DefScript API functions: loadconf, applyconf, applypermissions; log, logdebug, logdetail (according to debug level set in conf).

-> moved conf loading from core to scripts.
*New DefScript call: _leaveworld.def
*Fixed crash when calling _leaveworld on ~WorldSession()
* some updates to internal variable name handling
* added new macro: @n : newline (\n)
* cleanups
* added a bunch of new scripts + examples
This commit is contained in:
False.Genesis 2007-01-29 15:09:11 +00:00
parent 9d0dd30a0c
commit b15aff0b5d
31 changed files with 315 additions and 98 deletions

View File

@ -13,6 +13,8 @@ SAY .gmon
// you can also teleport on every startup to a certain player...
// simple: use the .goname command as usual.
// SAY .goname Gamemaster
// or teleport to a specific loacation...
// .tele gmisland
// to know everything worked fine, etc
SAY [${@version_short}] login successful.

View File

@ -0,0 +1,3 @@
#permission=255
// EXECUTED WHEN THE WORLD IS LEFT

View File

@ -2,5 +2,5 @@
// EXECUTED EVERYTIME A WHISPER IS BEEING RECIEVED
REPLY No need to whisper me, i am not yet programmed for it!
// comment out the following line if you dont need it
REPLY,0 No need to whisper me, i am not yet programmed for it!

View File

@ -4,51 +4,31 @@
OUT * DefScript StartUp [${@version_short}]...
// preload the script here, however its not important to load it now. it will get
// loaded automatically if needed
loaddef _enterworld
loaddef _onwhisper
loaddef _nopermission
loaddef _setconf
loaddef yell
loaddef say
loaddef whisper
loaddef outv
loaddef sayv
loaddef reply
loaddef quit
// Load required conf files.
LOADCONF PseuWoW.conf
LOADCONF users.conf
// Apply the configureation
APPLYCONF
// Apply user permissions
APPLYPERMISSIONS
// preload the scripts, however its not important to load them now.
//they will get loaded automatically if needed
LOADALL
// RELOADDEF myscript
// ...
// remove dangerous variables
OUT * Cleaning up variables...
UNSET #ACCPASS
UNSET #ACCNAME
OUT * Dangerous variables removed.
OUT * Assigning permissions for internal functions...
// this is important because players could reset permissions for dangerous functions
SETSCRIPTPERMISSION,setscriptpermission 255
SETSCRIPTPERMISSION,out 0
SETSCRIPTPERMISSION,set 255
SETSCRIPTPERMISSION,default 255
SETSCRIPTPERMISSION,unset 255
SETSCRIPTPERMISSION,shdn 255
SETSCRIPTPERMISSION,loaddef 255
SETSCRIPTPERMISSION,reloaddef 255
SETSCRIPTPERMISSION,pause 255
SETSCRIPTPERMISSION,emote 0
SETSCRIPTPERMISSION,savecache 10
SETSCRIPTPERMISSION,sendchatmessage 255
OUT * Permissions set.
CLEANUPVARS
// set permissions for internal functions
INTERNAL_PERM
// do more stuff here in future...
OUT * StartUp complete!

View File

@ -9,4 +9,5 @@
#permission=10
SET,lang ${@1}
DEFAULT,lang 0
SENDCHATMESSAGE,14,{${lang}},{${@def}},{${@0}}
SENDCHATMESSAGE,14,{${lang}},{${@def}},{${@0}}
UNSET lang

View File

@ -0,0 +1,6 @@
OUT * Cleaning up variables...
UNSET #ACCPASS
UNSET #ACCNAME
OUT * Dangerous variables removed.

View File

@ -0,0 +1,19 @@
#permission=255
// EXAMPLE SCRIPT!!!
// expected args:
// @def: variable name
// purpose: multiply a given variable with 3 and add 1
// this line is the most important part:
// get the name of the function calling this script,
// and modify its variable. note that we treat this variable as global!
// example: script "foo" has a variable x and calls this script with x as default argument.
// result: the variable name will be: "#foo::x"
set,v #${@caller}::${@def}
// v now stores the variable name of the var we want to change.
// side note: the # marks the var as global. if we didnt do this, the var name would be "example_3xadd1::foo::x"
// do some math
mul,{${v}} 3
add,{${v}} 1

View File

@ -0,0 +1,13 @@
// EXAMPLE SCRIPT!!!
// purpose: demonstrate the #onload part that gets executed everytime the script is loaded
// result: on the first call the number '1001' will be written, 2nd call '1002', etc.
#permission=255
#onload
out Loading "loadtest.def" --[[
set,mytest 1000
out finished ]]--
#endonload
add,mytest 1
out ${mytest}

3
bin/scripts/exit.def Normal file
View File

@ -0,0 +1,3 @@
// just a name alternative
QUIT

4
bin/scripts/gc.def Normal file
View File

@ -0,0 +1,4 @@
// example script to write into channel "generalchat"
// usage: "gc bla bla..."
chan,generalchat ${@def}

View File

@ -0,0 +1,47 @@
OUT * Assigning permissions for internal functions...
set,p 255
// this is important because players could reset permissions for dangerous functions
SETSCRIPTPERMISSION,setscriptpermission 255
SETSCRIPTPERMISSION,out ${p}
SETSCRIPTPERMISSION,set ${p}
SETSCRIPTPERMISSION,default ${p}
SETSCRIPTPERMISSION,unset ${p}
SETSCRIPTPERMISSION,shdn ${p}
SETSCRIPTPERMISSION,loaddef ${p}
SETSCRIPTPERMISSION,reloaddef ${p}
SETSCRIPTPERMISSION,toint ${p}
SETSCRIPTPERMISSION,add ${p}
SETSCRIPTPERMISSION,sub ${p}
SETSCRIPTPERMISSION,mul ${p}
SETSCRIPTPERMISSION,div ${p}
SETSCRIPTPERMISSION,mod ${p}
SETSCRIPTPERMISSION,pow ${p}
SETSCRIPTPERMISSION,bitor ${p}
SETSCRIPTPERMISSION,bitand ${p}
SETSCRIPTPERMISSION,bitxor ${p}
SETSCRIPTPERMISSION,sendchatmessage ${p}
SETSCRIPTPERMISSION,pause ${p}
// emotes are not relly dangerous, allow for all users
SETSCRIPTPERMISSION,emote 0
SETSCRIPTPERMISSION,savecache ${p}
SETSCRIPTPERMISSION,sendchatmessage ${p}
SETSCRIPTPERMISSION,joinchannel ${p}
SETSCRIPTPERMISSION,leavechannel ${p}
SETSCRIPTPERMISSION,loadconf ${p}
SETSCRIPTPERMISSION,applyconf ${p}
SETSCRIPTPERMISSION,applypermissions ${p}
SETSCRIPTPERMISSION,log ${p}
SETSCRIPTPERMISSION,logdetail ${p}
SETSCRIPTPERMISSION,logdebug ${p}
UNSET p
OUT * Permissions set.

27
bin/scripts/loadall.def Normal file
View File

@ -0,0 +1,27 @@
// preloads the most important scripts
OUT Loading DefScripts...
RELOADDEF _enterworld
RELOADDEF _leaveworld
RELOADDEF _nopermission
RELOADDEF _onwhisper
RELOADDEF cleanupvars
RELOADDEF internal_perm
RELOADDEF chan
RELOADDEF quit
RELOADDEF reply
RELOADDEF say
RELOADDEF yell
RELOADDEF whisper
RELOADDEF makechatitem
RELOADDEF gc
RELOADDEF sayred
RELOADDEF outv
RELOADDEF sayv
RELOADDEF s
RELOADDEF y
OUT * DefScripts loaded.

View File

@ -0,0 +1,21 @@
#permission=255
// expected args:
// @def: item id
// @0: variable name to write into
// @1 (optional): color (in hex format: 00FF00 = pure green)
SET,i ${@def}
SET,target ${@0}
SET,color ${@1}
DEFAULT,i 0
TOINT,i ${i}
DEFAULT,target chatitem
DEFAULT,color 6679FF
SET,v #${@caller}::${target}
SET,${v} |cff${color}|Hitem:${i}:0:0:0|h[Item ${i}]|h|r
UNSET i
UNSET v
UNSET color
UNSET target

7
bin/scripts/outv.def Normal file
View File

@ -0,0 +1,7 @@
#permission=0
SET,vn #${@caller}::${@def}
SET,vv,onfail,{<value not set>} ${${vn}}
OUT * Var '${@def}' = '${vv}'
UNSET vv
UNSET vn

View File

@ -1,7 +1,8 @@
#permission=255
SET,player ${@thiswhisper_name}
SET,lang ${@thiswhisper_lang}
SET,lang ${@0}
DEAULT,lang ${@thiswhisper_lang}
SET,msg ${@def}
WHISPER,{${player}},{${lang}} ${msg}

2
bin/scripts/s.def Normal file
View File

@ -0,0 +1,2 @@
#permission=0
SAY,{${@0}} ${@def}

View File

@ -5,7 +5,7 @@ SET,msg ${@def}
default,lang 0
OUT * Saying '${msg}' in lang ${lang}
LOGDEBUG * Saying '${msg}' in lang ${lang}
SENDCHATMESSAGE,0,${lang},{${msg}}
UNSET lang

5
bin/scripts/sayitem.def Normal file
View File

@ -0,0 +1,5 @@
// example script to "say" a clickable item (in WoW)
MAKECHATITEM,i ${@def}
SAY ${i}
UNSET i

4
bin/scripts/sayred.def Normal file
View File

@ -0,0 +1,4 @@
// example script how to output colored text
#permission=0
SAY,${@0} |cffFF0000 ${@def}

11
bin/scripts/sayv.def Normal file
View File

@ -0,0 +1,11 @@
#permission=0
SET,vn ${@def}
SET,vl ${@0}
DEFAULT,vl 0
SET,vv,onfail,{<value not set>} ${#${@def}}
SAY,{${vl}} * Var '${vn}' = '${vv}'
UNSET vv
UNSET vn
UNSET vl

2
bin/scripts/y.def Normal file
View File

@ -0,0 +1,2 @@
#permission=0
YELL,{${@0}} ${@def}

View File

@ -6,7 +6,7 @@ SET,msg ${@def}
default,lang 0
OUT * Yelling '${msg}' in lang ${lang}
LOGDEBUG * Yelling '${msg}' in lang ${lang}
SENDCHATMESSAGE,5,${lang},{${msg}}
UNSET lang

View File

@ -67,6 +67,12 @@ DefScriptFunctionTable *DefScriptPackage::_GetFunctionTable(void) const
{"sendchatmessage",&DefScriptPackage::SCSendChatMessage},
{"joinchannel",&DefScriptPackage::SCjoinchannel},
{"leavechannel",&DefScriptPackage::SCleavechannel},
{"loadconf",&DefScriptPackage::SCloadconf},
{"applyconf",&DefScriptPackage::SCapplyconf},
{"applypermissions",&DefScriptPackage::SCapplypermissions},
{"log",&DefScriptPackage::SClog},
{"logdetail",&DefScriptPackage::SClogdetail},
{"logdebug",&DefScriptPackage::SClogdebug},
// table termination
{NULL,NULL}
@ -111,19 +117,22 @@ bool DefScriptPackage::LoadByName(std::string name){
}
bool DefScriptPackage::LoadScriptFromFile(std::string fn, std::string sn){
std::string label, value;
if(fn.empty() || sn.empty()) return false;
std::string label, value, line;
std::fstream f;
bool load_debug=false,load_notify=false, exec=false;
char z;
f.open(fn.c_str(),std::ios_base::in);
if(!f.is_open())
return false;
std::string line;
char z;
bool load_debug=false,load_notify=false;
if(GetScript(sn))
delete GetScript(sn);
DefScript *newscript = new DefScript(this);
Script[sn] = newscript;
Script[sn]->SetName(sn); // necessary that the script knows its own name
while(!f.eof()){
line.clear();
while (true) {
@ -156,17 +165,25 @@ bool DefScriptPackage::LoadScriptFromFile(std::string fn, std::string sn){
load_notify=true;
if(line=="debug")
Script[sn]->SetDebug(true);
if(line=="onload")
exec=true;
if(line=="endonload" || line=="/onload")
exec=false;
//...
continue; // line was an option, not script content
}
if(load_debug)
std::cout<<"~LOAD: "<<line<<"\n";
Script[sn]->AddLine(line);
if(!exec)
Script[sn]->AddLine(line);
else
{
this->RunSingleLineFromScript(line,Script[sn]);
}
}
f.close();
Script[sn]->SetName(sn); // necessary that the script knows its own name
if(load_notify)
std::cout << "+> Script '" << sn << "' [" << fn << "] successfully loaded.\n";
@ -297,6 +314,15 @@ bool DefScriptPackage::RunSingleLine(std::string line){
return Interpret(curSet);
}
bool DefScriptPackage::RunSingleLineFromScript(std::string line, DefScript *pScript){
CmdSet Set(pScript);
DefXChgResult final=ReplaceVars(line,&Set,false);
CmdSet curSet=SplitLine(final.str);
curSet.myname=pScript->GetName(); // temp fix, this needs to be cleaned up later
return Interpret(curSet);
}
CmdSet DefScriptPackage::SplitLine(std::string line){
unsigned int i=0;
@ -432,8 +458,7 @@ CmdSet DefScriptPackage::RemoveBrackets(CmdSet oldSet){
DefXChgResult DefScriptPackage::ReplaceVars(std::string str, CmdSet *pSet, bool isVar){
unsigned int
unsigned int
openingBracket=0, // defines the position from where the recursive call is started
closingBracket=0, // the closing bracket
bracketsOpen=0, // amount of brackets opened
@ -449,9 +474,6 @@ DefXChgResult DefScriptPackage::ReplaceVars(std::string str, CmdSet *pSet, bool
std::string subStr;
DefXChgResult xchg;
//while(str.at(0)==' ' || str.at(0)=='\t')
// str.erase(0,1); // trim spaces if there are any
for(unsigned int i=0;i<str.length();i++)
{
@ -529,6 +551,8 @@ DefXChgResult DefScriptPackage::ReplaceVars(std::string str, CmdSet *pSet, bool
str=pSet->cmd;
else if(pSet && subs=="caller")
str=pSet->caller;
else if(subs=="n")
str="\n";
else if(variables.Exists(vname))
str=variables.Get(vname);
else
@ -550,20 +574,24 @@ DefXChgResult DefScriptPackage::ReplaceVars(std::string str, CmdSet *pSet, bool
xchg.str = str;
if(hasChanged)
xchg.changed=true;
//printf("XCHG:%u: \"%s\"\n",xchg.changed,xchg.str.c_str());
return xchg;
}
std::string DefScriptPackage::_NormalizeVarName(std::string vn_in, std::string sn){
std::string vn=vn_in;
if(sn.empty())
return vn;
if(vn.at(0)=='#')
while(vn.at(0)=='#')
bool global=false;
while(true)
{
if(sn.empty())
return vn;
if(vn.at(0)=='#')
global = true;
if(vn.at(0)=='#' || vn.at(0)==':')
vn.erase(0,1);
else if(vn.at(0)=='@')
;// do nothing for now
else
else
break;
}
if( (!global) && (vn.at(0)!='@') )
vn=sn+"::"+vn;
return vn;

View File

@ -110,6 +110,7 @@ private:
bool Interpret(CmdSet);
CmdSet RemoveBrackets(CmdSet);
std::string RemoveBracketsFromString(std::string);
bool RunSingleLineFromScript(std::string line, DefScript *pScript);
DefScriptFunctionTable *_GetFunctionTable(void) const;
DefScriptFunctionTable *functionTable;
unsigned int functions;
@ -147,6 +148,12 @@ private:
bool SCshdn(CmdSet);
bool SCjoinchannel(CmdSet);
bool SCleavechannel(CmdSet);
bool SCloadconf(CmdSet);
bool SCapplypermissions(CmdSet);
bool SCapplyconf(CmdSet);
bool SClog(CmdSet);
bool SClogdetail(CmdSet);
bool SClogdebug(CmdSet);
// Own variable declarations
std::map<std::string, unsigned char> my_usrPermissionMap;

View File

@ -115,6 +115,45 @@ bool DefScriptPackage::SCleavechannel(CmdSet Set){
return true;
}
bool DefScriptPackage::SCloadconf(CmdSet Set){
if(Set.defaultarg.empty())
return true;
std::string fn;
if(Set.defaultarg.find('/')==std::string::npos && Set.defaultarg.find('\\')==std::string::npos)
fn += ((PseuInstance*)parentMethod)->GetConfDir();
fn += Set.defaultarg;
if(variables.ReadVarsFromFile(fn))
log("Loaded conf file [%s]",fn.c_str());
else
log("Error loading conf file [%s]",fn.c_str());
return true;
}
bool DefScriptPackage::SCapplypermissions(CmdSet Set){
this->My_LoadUserPermissions(variables);
return true;
}
bool DefScriptPackage::SCapplyconf(CmdSet Set){
((PseuInstance*)parentMethod)->GetConf()->ApplyFromVarSet(variables);
return true;
}
bool DefScriptPackage::SClog(CmdSet Set){
log(Set.defaultarg.c_str());
return true;
}
bool DefScriptPackage::SClogdetail(CmdSet Set){
logdetail(Set.defaultarg.c_str());
return true;
}
bool DefScriptPackage::SClogdebug(CmdSet Set){
logdebug(Set.defaultarg.c_str());
return true;
}
void DefScriptPackage::My_LoadUserPermissions(VarSet &vs)
{

View File

@ -57,6 +57,7 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run)
PseuInstance::~PseuInstance()
{
delete _wsession;
if(GetConf()->enablecli && _cli)
{
_cli->stop();
@ -64,7 +65,6 @@ PseuInstance::~PseuInstance()
delete _scp;
delete _conf;
//delete _rsession; // deleted by SocketHandler!!!!!
delete _wsession;
log_close();
}
@ -88,26 +88,6 @@ bool PseuInstance::Init(void) {
_scp=new DefScriptPackage();
_scp->SetParentMethod((void*)this);
_conf=new PseuInstanceConf();
log("Reading PseuWoW.conf...");
if(!_scp->variables.ReadVarsFromFile(_confdir + "PseuWoW.conf"))
{
log("Error reading conf file [%s]",_confdir.append("PseuWoW.conf").c_str());
return false;
}
logdetail("Applying configuration...");
_conf->ApplyFromVarSet(_scp->variables);
log("Reading user permissions...");
if(_scp->variables.ReadVarsFromFile(_confdir + "users.conf"))
{
log("-> Done reading users.");
}
else
{
log("Error reading conf file [%s] - NO PERMISSIONS SET!",_confdir.append("users.conf").c_str());
}
logdebug("Setting up DefScripts path '%s'",_scpdir.c_str());
_scp->SetPath(_scpdir);
@ -116,9 +96,6 @@ bool PseuInstance::Init(void) {
_scp->variables.Set("@version_short",_ver_short);
_scp->variables.Set("@version",_ver);
logdetail("Applying user permissions...");
_scp->My_LoadUserPermissions(_scp->variables);
log("Loading DefScripts from folder '%s'",_scpdir.c_str());
if(!_scp->RunScript("_startup",NULL))
{
@ -136,7 +113,7 @@ bool PseuInstance::Init(void) {
log("Errors while initializing, proc halted!!");
if(GetConf()->exitonerror)
exit(0);
while(true)SDL_Delay(1000);
while(true)this->Sleep(1000);
}
log("Init complete.\n");
@ -165,9 +142,11 @@ void PseuInstance::Run(void)
}
_startrealm=false; // the realm is started now
while((!_stop) && (!_startrealm))
while( (!_stop) && (!_startrealm) )
{
Update();
if(_error)
_stop=true;
}
}
while(GetConf()->reconnect && (!_stop));
@ -186,7 +165,7 @@ void PseuInstance::Run(void)
log("Exiting on error is disabled, PseuWoW is now IDLE");
log("-- Press enter to exit --");
char crap[100];
fgets(crap,sizeof(crap),stdin);
fgets(crap,sizeof(crap),stdin); // workaround, need to press enter 2x for now
}
}
@ -203,7 +182,7 @@ void PseuInstance::Update()
}
if(_wsession && !_wsession->IsValid())
{
_wsession->Start(); // update the worldSESSION, which will update the worldsocket itself
_wsession->Start();
}
if(_wsession && _wsession->IsValid())
{
@ -261,6 +240,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
enablecli=(bool)atoi(v.Get("ENABLECLI").c_str());
allowgamecmd=(bool)atoi(v.Get("ALLOWGAMECMD").c_str());
enablechatai=(bool)atoi(v.Get("ENABLECHATAI").c_str());
notifyping=(bool)atoi(v.Get("NOTIFYPING").c_str());
// clientversion is a bit more complicated to add
{

View File

@ -43,6 +43,7 @@ class PseuInstanceConf
bool allowgamecmd;
bool enablecli;
bool enablechatai;
bool notifyping;
};
@ -62,9 +63,11 @@ class PseuInstance
DefScriptPackage *GetScripts(void) { return _scp; }
PseuInstanceRunnable *GetRunnable(void) { return _runnable; }
void SetConfDir(std::string dir) { _confdir = dir; }
std::string GetConfDir(void) { return _confdir; }
void SetScpDir(std::string dir) { _scpdir = dir; }
void SetSessionKey(BigNumber key) { _sessionkey = key; }
BigNumber GetSessionKey(void) { return _sessionkey; }
void SetError(void) { _error = true; }

View File

@ -402,7 +402,7 @@ void RealmSocket::_HandleLogonProof(void)
log("Auth failed, M2 differs!");
printf("My M2 :"); printchex((char*)_m2,20,true);
printf("Srv M2:"); printchex((char*)lp.M2,20,true);
GetInstance()->SetError();
}
}

View File

@ -72,7 +72,7 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet)
}
}
logdetail("%s joined channel %s", channel.c_str());
log("%s joined channel %s", channel.c_str());
break;
// Player leaved channel you are on
@ -87,7 +87,7 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet)
}
}
logdetail("%s leaved channel %s", channel.c_str());
log("%s left channel %s", channel.c_str());
break;
// You joined channel successfully

View File

@ -192,6 +192,7 @@ void WorldSession::_OnLeaveWorld(void)
if(_logged)
{
_logged=false;
GetInstance()->GetScripts()->RunScript("_leaveworld",NULL);
}
}
@ -276,7 +277,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
recvPacket >> num;
if(num==0){
log("No chars found!\n");
GetInstance()->Stop();
GetInstance()->SetError();
return;
}
logdetail("W: Chars in list: %u\n",num);
@ -326,7 +327,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
}
if(!char_found){
log("Character \"%s\" was not found on char list!",GetInstance()->GetConf()->charname.c_str());
GetInstance()->Stop();
GetInstance()->SetError();
return;
} else {
log("Entering World with Character \"%s\"...",GetInstance()->GetConf()->charname.c_str());
@ -476,7 +477,8 @@ void WorldSession::_HandlePongOpcode(WorldPacket& recvPacket)
{
uint32 pong;
recvPacket >> pong;
log("Recieved Ping reply: %u ms latency.",clock()-pong);
if(GetInstance()->GetConf()->notifyping)
log("Recieved Ping reply: %u ms latency.",clock()-pong);
}
void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket)
{

View File

@ -72,7 +72,7 @@ void WorldSocket::OnRead()
if(_opcode > 800) // no opcode has yet a number over 800
{
printf("CRYPT ERROR: opcode=%u, remain=%u\n",_opcode,_remaining);
GetSession()->GetInstance()->Stop();
GetSession()->GetInstance()->SetError();
// if the crypt gets messy its hardly possible to recover it, especially if we dont know
// the lentgh of the following data part
// TODO: invent some way how to recover the crypt (reconnect?)