collapse collapse
* User Info
 
 
Welcome, Guest. Please login or register.
* Search

* Board Stats
  • stats Total Members: 989
  • stats Total Posts: 18363
  • stats Total Topics: 2500
  • stats Total Categories: 7
  • stats Total Boards: 35
  • stats Most Online: 1144

Author Topic: Help files using XML  (Read 4245 times)

0 Members and 1 Guest are viewing this topic.

Offline Visceru

  • BeBot Rookie
  • *
  • Posts: 10
  • Karma: +0/-0
Help files using XML
« on: July 12, 2007, 02:44:05 am »
I had a quick Q and R regarding the possibility of moving online docs outside the .php files in the suggestions forum here.

There didn't seem that much interest in going that way so I wrote something I can use.  I figured it would be easier to manually take care of 1 custom file (bothelp.php) rather than getting all my custom help overwritten in every module every time there's a bot release.

I thought I'd post it here in its current state as it's working, even if it's not feature-complete yet.  Maybe if you do like the format you could help with some of the writing or translation into another language.  I've only included a couple of example help files.

I also welcome advice on the PHP :)

Notes:
  • It's backwards compatible.  It falls back on any help found in the $this -> help[] array if there's no xml found
  • You can put multiple modules in each xml file, depending on whether you want lots of small files or one big one
  • Supports multiple concurrent languages.  With a small adjustment to a function and an extra column on the #___user table, help file language can be set per user .  I haven't done that yet so that it would be easy to try out this bothelp.php without it messing around with your tables.
  • You still get the unified colour formatting and layout on the windows
  • It seperates module-wide descriptions from command-level documentation and provides clickable links between the two.

Here's bothelp.php and I've attached a zip file that shows the folder structure and has some example help files.  At the moment it defaults the language to EN (English) and also has IC for In Character help (read more on that in the link above)

Code: [Select]
<?
/*
* BotHelp.php - Bot Help Systems using external XML files
*
* BeBot - An Anarchy Online Chat Automaton
* Copyright (C) 2004 Jonas Jax
* Copyright (C) 2005 Thomas J. Stens� and ShadowRealm Creations
*
* Developed by:
* - Blondengy (RK1)
* - Khalem (RK1)
*
* See Credits file for all aknowledgements.
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 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 General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
*  USA
*
* File last changed at $LastChangedDate: 2007-06-07 11:01:01 +0200 (Thu, 07 Jun 2007) $
* Revision: $Id: BotHelp.php 590 2007-06-07 09:01:01Z alreadythere $
*/


$bothelp_core = new BotHelp_Core($bot);

$commands["tell"]["help"] = &$bothelp_core;
$commands["gc"]["help"] = &$bothelp_core;
$commands["pgmsg"]["help"] = &$bothelp_core;



/*
The Class itself...
*/
class BotHelp_Core
{
var $bot;
var $modulehelp;
var $commandhelp;
//var $default_language;

/*
Constructor:
Hands over a referance to the "Bot" class.
*/
function BotHelp_Core (&$bot)
{
$this -> bot = &$bot;
$this -> modulehelp  = array();
$this -> commandhelp = array();
$bot -> settings -> create("BotHelp", "Language", "EN", "Help file language.", "EN;IC");

$default_language = $this -> bot -> settings -> get("BotHelp", "Language");
if(!preg_match("/^[a-z0-9]+$/i", $default_language))
{
$bot -> log("HELP", "ERROR", "Help language settings '$lang' invalid. Defaulting to English (EN).");
$bot -> settings -> save("BotHelp", "Language", "EN");
}

// Read all xml files we can find under all language folders
// Ie.  ./help/EN/*.xml  , ./help/IC/*.xml  ,  ./custom/help/EN/*.xml , etc etc
// Loading the custom help folder first means it takes precedence over base help files.
$this -> ReadHelpFromDir("./custom/help/");
$this -> ReadHelpFromDir("./help/");

//Debugging: Have a peek at the structure of these arrays.
//print_r($this -> modulehelp);
//print_r($this -> commandhelp);

}


/*
This gets called on a tell with the command
*/
function tell($name, $msg)
{
$reply = $this -> command_handler($name, $msg, "tell");
if ($reply != FALSE)
$this -> bot -> send_tell($name, "$reply");
}

function gc($name, $msg)
{
$this -> tell($name, $msg);
}

function pgmsg($name, $msg)
{
$this -> tell($name, $msg);
}

function command_handler($name, $msg, $origin)
{
$vars = explode(' ', $msg);
unset($vars[0]);
$lang = $this -> get_user_help_language($name);

switch($vars[1])
{
case '':
return($this -> show_help_menu($name));
break;
case 'tell':
case 'gc':
case 'pgmsg':
return($this -> show_help_menu($name, $vars[1]));
break;
case 'module':
$return = $this -> formatXMLModuleHelp($name, $vars[2], $lang);
if($return['error'])
return($return['errordesc']);
else
return($return['content']);
break;
default:
return($this -> show_help($name, $vars[1], $lang));
break;
}
}


function show_help_menu($name, $section = 'all')
{
switch($section)
{
case 'all':
$window = $this -> get_commands($name, 'tell');
$window .= $this -> get_commands($name, 'gc');
$window .= $this -> get_commands($name, 'pgmsg');
return($this -> bot -> make_blob('Help', $window));
break;
default:
$window = $this -> get_commands($name, $section);
return($this -> bot -> make_blob('Help', $window));
break;
}
}


/*
Gets commands for a given channel
*/
function get_commands($name, $channel)
{
$window = "<br><br>-- Commands usable in $channel --<br>";
ksort($this -> bot -> commands[$channel]);
foreach($this -> bot -> commands[$channel] as $command => $module)
{
if(is_array($module -> help) && $this -> bot -> accesscontrol -> check_rights($name, $command, $channel))
{
$window .= "<a href='chatcmd:///tell <botname> <pre>help $command'>$command</a> ";
}
}
return($window);
}


function show_help($name, $command, $lang="EN")
{
$return['error'] = FALSE;
$return['errordesc'] = '';
$return['content'] = '';

if(isset($this -> commandhelp[$lang][$command]))
{
$return = $this -> formatXMLHelp($command, $lang);
}
elseif(isset($this -> bot -> commands['tell'][$command] -> help))
{
$return = $this -> FormatOldHelp($command, $this -> bot -> commands['tell'][$command] -> help);
}
elseif(isset($this -> bot -> commands['gc'][$command] -> help))
{
$return = $this -> FormatOldHelp($command, $this -> bot -> commands['gc'][$command] -> help);
}
elseif(isset($this -> bot -> commands['pgmsg'][$command] -> help))
{
$return = $this -> FormatOldHelp($command, $this -> bot -> commands['pgmsg'][$command] -> help);
}
else
{
$return['error'] = true;
$return['errordesc'] = "Command '$command' not recognised or has no help.";
}

if ($return['error']== false &&
!($this -> bot -> accesscontrol -> check_rights($name, $command, "tell")
|| $this -> bot -> accesscontrol -> check_rights($name, $command, "gc")
|| $this -> bot -> accesscontrol -> check_rights($name, $command, "pgmsg")))
{
$return['error'] = true;
$return['errordesc'] = "You don't have access to this command.";
}

if($return['error'])
return($return['errordesc']);
else
return($return['content']);
}


// This function needs to be deprecated as soon as
// (if ever) we stop putting documentation inside the actual modules.
function FormatOldHelp($command, $help)
{
$return['error'] = FALSE;
$return['errordesc'] = '';
$return['content'] = '';
$window = "##blob_title## ::::: HELP ON " . strtoupper($command) . " :::::##end##<br><br>";
$window .= $help['description'].'<br><br>';
foreach ($help['command'] as $key => $value)
{
// Only show help for the specific command, not all help for module!
$parts = explode(' ', $key);
if (strcasecmp($command, $parts[0]) == 0)
{
$key = str_replace('<', '&lt;', $key);
$value = str_replace('<', '&lt;', $value);
$window .= " ##highlight##<pre>$key##end## - $value<br>";
}
}
$window .= '<br>##highlight##NOTES:##end##<br>'.$help['notes'];
$return['content'] = 'help on '.$this -> bot -> make_blob($command, $window);
return($return);
}


//Parses all .XML files under all language subfolders using the ParseHelpXML function
function ReadHelpFromDir($dir)
{
if (!is_dir($dir))
{
$this -> bot -> log("HELP", "ERROR", "$dir is not a valid directory.");
return;
}

$folder1 = dir($dir);
while ($lang = $folder1->read())
{
if (!is_dir($dir.$lang."/") || !preg_match("/^[a-z0-9]+$/i", $lang))
{
//$this -> bot -> log("HELP", "ERROR", "'$lang' is not a valid language folder in '$dir$lang/'");
continue;
}

$folder = dir($dir.$lang."/");
while ($helpfile = $folder->read())
{
if (!is_dir($helpfile) && !preg_match("/^_/", $helpfile) && preg_match("/\.xml$/i", $helpfile))
{
$return = $this -> ParseHelpXml($dir . $lang . "/" . $helpfile, $lang);
if($return['error'])
$this -> bot -> log("HELP", "ERROR", $return['errordesc']);
else
$this -> bot -> log("HELP", "LOAD", $return['content']);
}
}
$folder->close();

}
$folder1->close();

}


//  Parse $filename looking for the help tags.
//  Store all the Module-level information in (array)$modulehelp
//  and all the command-level information in (array)$commandhelp
function ParseHelpXml($filename, $lang)
{
$return['error'] = FALSE;
$return['errordesc'] = '';
$return['content'] = '';


$helpfile = file_get_contents($filename);
if (!$helpfile)
{
$return['error'] = TRUE;
  $return['errordesc'] = "Could not load helpfile: " . $filename;
$this -> bot -> log("HELP", "ERROR", "Could not load " . $filename);
}
else
{
//Help files can contain multiple <module> tags under the root tag.
$module = explode("<module>", $helpfile);

$find    = array("<", ">");
$replace = array("&lt;", "&gt;");

for ($i = 1; $i < count($module); $i++)
{
$name = strtolower($this -> bot -> xmlparse($module[$i], "mod_name"));
if(!preg_match("/^[a-z0-9\-_]+$/i", $name))
{
$this -> bot -> log("HELP", "WARN", "Bad module name '" . $name . "' in ".$filename.". Use only letters, numbers dash and underscore. Skipping this module.");
}
elseif(isset($this -> modulehelp[$lang][$name]))
{
$this -> bot -> log("HELP", "WARN", "Module '" . $name . "' already exists. Skipping it in " .$filename. ".");
}
else
{
$this -> modulehelp[$lang][$name]['author']      = $this -> bot -> xmlparse($module[$i], "mod_author");
$this -> modulehelp[$lang][$name]['version']     = $this -> bot -> xmlparse($module[$i], "mod_version");
$this -> modulehelp[$lang][$name]['link']        = $this -> bot -> xmlparse($module[$i], "mod_link");
$this -> modulehelp[$lang][$name]['description'] = $this -> bot -> xmlparse($module[$i], "mod_desc");
$this -> modulehelp[$lang][$name]['notes']       = $this -> bot -> xmlparse($module[$i], "mod_notes");
$this -> modulehelp[$lang][$name]['admin_notes'] = $this -> bot -> xmlparse($module[$i], "mod_admin_notes");


//Then go through each command in the module and add it to the $commandhelp array.
$commands = explode("<command>", $module[$i]);
for ($j = 1; $j < count($commands); $j++)
{
$fullCommand = strtolower($this -> bot -> xmlparse($commands[$j], "cmd_name"));

list($cmdName, $cmdParams) = explode (" ", $fullCommand, 2);
//Use the first array value to store the module this command belongs to.
if (!isset($this -> commandhelp[$lang][$cmdName]))
$this -> commandhelp[$lang][$cmdName][0] = $name;

//Add this command to a list. Used later to append to the module information.
$commandList[] = $cmdName;
$cmdNumber = count($this -> commandhelp[$lang][$cmdName]);

$description = $this -> bot -> xmlparse($commands[$j], "cmd_desc");
$example = $this -> bot -> xmlparse($commands[$j], "cmd_example");

if(!empty($cmdParams))   $this -> commandhelp[$lang][$cmdName][$cmdNumber]["parameters"]  = $cmdParams;
if(!empty($description)) $this -> commandhelp[$lang][$cmdName][$cmdNumber]["description"] = $description;
if(!empty($example))     $this -> commandhelp[$lang][$cmdName][$cmdNumber]["example"]     = $example;
}

//Add here it is. Slap the list into the module info array.
$this -> modulehelp[$lang][$name]['commandlist'] = implode(",",array_unique($commandList));
unset($commands);
}
}

$return['content'] = $filename . " : " . strlen($helpfile) . " bytes read.";
return $return;
}
}


//Creates the actual text blob the user sees when they click the link
function formatXMLHelp($command, $lang="EN")
{
$return['error'] = FALSE;
$return['errordesc'] = '';
$return['content'] = '';

$window = "##blob_title## ::::: HELP ON " . strtoupper($command) . " :::::##end##<br><br>##normal##";
$commandCount = count($this -> commandhelp[$lang][$command]);

for ($i = 1; $i < $commandCount; $i++)
{
$item = $this -> commandhelp[$lang][$command][$i];
$window .= "##highlight##" . $command . " " . $item['parameters'] . "##end##: ";
$window .= $item['description']."<br>  ";
if (!empty($item['example']))
$window .= "##blob_text##" . $item['example'] . "##end##<br>";
$window .= "<br>";
}
$module = $this -> commandhelp[$lang][$command][0];
if (!empty($this -> modulehelp[$lang][$module]['notes']))
$window .= "##blob_title##  :::::  Module notes  :::::<br>##end## " . $this -> modulehelp[$lang][$module]['notes'] . "<br>";
$window .= "<br>This command is in the <a href='chatcmd:///tell <botname> <pre>help module ".
$module."'>".ucfirst($module)."</a> module.##end##";

//Replace attributes in <> symbols with &lt; and &gt;, but not the ones the bot uses.
$window = preg_replace("/<(?!botname|br|pre|font|\/font|div|\/div|a href|\/a)(.+?)>/", '&lt;$1&gt;', $window);
$return['content'] = 'help on '.$this -> bot -> make_blob($command, $window);
return($return);
}


// Creates the text blob for the module-level help. This gives a summary and
// will show all commands for a given module.
function formatXMLModuleHelp($name,$command="**", $lang="EN")
{
$return['error'] = FALSE;
$return['errordesc'] = '';
$return['content'] = '';

if(!isset($this -> modulehelp[$lang][$command]))
{
$return['error'] = TRUE;
$return['errordesc'] = 'Module not found';
}
else
{
$window  = "<div align=center>".
"##blob_title## ::::: HELP ON " . strtoupper($command) ." MODULE :::::##end##<br>".
"##highlight##By:##end## " . $this -> modulehelp[$lang][$command]['author'] . "  ".
"##highlight##v##end##" . $this -> modulehelp[$lang][$command]['version'] . "</div><br>".
"##blob_text##" . $this -> modulehelp[$lang][$command]['description'] . "<br>";

if(!empty($this -> modulehelp[$lang][$command]['link']))
$window .= $this -> modulehelp[$lang][$command]['link'] . "<br>";
if(!empty($this -> modulehelp[$lang][$command]['notes']))
$window .= "<br>##highlight##Notes:##end## " . $this -> modulehelp[$lang][$command]['notes'] . "<br>";
if($this -> bot -> security -> check_access($name, "admin") && !empty($this -> modulehelp[$lang][$command]['admin_notes']))
$window .= "<br>##highlight##Admin Notes:##end## " . $this -> modulehelp[$lang][$command]['admin_notes'] . "<br>";
$window .= "<br>Commands available in this module:<br>";

$commandList = explode(",",$this -> modulehelp[$lang][$command]['commandlist']);
foreach($commandList as $item)
{
$window .="<a href='chatcmd:///tell <botname> <pre>help " . $item . "'>" . $item . "</a>  ";
}

//Replace attributes in <> symbols with &lt; and &gt;, but not the ones the bot uses.
$window = preg_replace("/<(?!botname|br|pre|font|\/font|div|\/div|a href|\/a)(.+?)>/", '&lt;$1&gt;', $window);
$return['content'] = 'help on module: '.$this -> bot -> make_blob($command . " module", $window);
}
return($return);
}


// For the future: Once help file language prefs are stored in the #___User table
// we can return user prefs here if they've set their help to a different language.
function get_user_help_language($name)
{
return $this -> bot -> settings -> get("BotHelp", "Language");
}
}
?>
« Last Edit: July 12, 2007, 02:52:19 am by Visceru »

Offline Visceru

  • BeBot Rookie
  • *
  • Posts: 10
  • Karma: +0/-0
Re: Help files using XML
« Reply #1 on: July 12, 2007, 02:44:51 am »
And here is an example of the XML:

Code: [Select]
<?xml version="1.0" encoding="UTF-8"?>
<helpfile>
<module>
<mod_name>Say</mod_name>
<mod_author>Visceru</mod_author>
<mod_version>0.1</mod_version>
<mod_link></mod_link>
<mod_desc>Makes <botname> say what you tell it to.</mod_desc>
<mod_notes>This is another test!  These are custom help files!</mod_notes>
<mod_admin_notes>Abuse the members through the bot. Lovely.</mod_admin_notes>

<command>
<cmd_name>say [text]</cmd_name>
<cmd_desc>Make the bot say [text] on the guild and guest channels.</cmd_desc>
<cmd_example>/tell <botname> say Hey there! How are you today?</cmd_example>
</command>
<command>
<cmd_name>whosaidthat</cmd_name>
<cmd_desc>Find out who made the bot say the last thing it said.</cmd_desc>
</command>

</module>
</helpfile>


Offline Visceru

  • BeBot Rookie
  • *
  • Posts: 10
  • Karma: +0/-0
Re: Help files using XML
« Reply #2 on: July 12, 2007, 02:58:11 am »
Oh yes, and the zip file is set up to be extracted into the main bot folder, so you just have to comment out the core/bothelp.php to use it.

 

* Recent Posts
[AoC] special char for items module by bitnykk
[February 09, 2024, 09:41:18 pm]


0.8.x updates for AoC by bitnykk
[January 30, 2024, 11:16:08 pm]


0.8.x updates for AO by bitnykk
[January 30, 2024, 11:15:37 pm]


BeBot still alive & kicking ! by bitnykk
[December 17, 2023, 12:58:44 am]


Bebot and Rasberry by bitnykk
[November 29, 2023, 11:04:14 pm]

* Who's Online
  • Dot Guests: 462
  • Dot Hidden: 0
  • Dot Users: 0

There aren't any users online.
* Forum Staff
bitnykk admin bitnykk
Administrator
Khalem admin Khalem
Administrator
WeZoN gmod WeZoN
Global Moderator
SimplePortal 2.3.7 © 2008-2024, SimplePortal