Extending plugins

Posted by Edly on Thu 28 Nov 2019 06:39 PM — 4 posts, 16,277 views.

#0
I'd like to extend the functionality of an existing plugin, but without modifying its code.

Specifically, I want to add a function to the aard_GMCP_mapper.xml plugin that's distributed with the Aardwolf MUSHclient package: "mapper find" but without the wildcards around the query string, so that it only returns exact room name matches. This is very easy to do by editing the xml file, but then I wouldn't be able to download updates to aard_GMCP_mapper.xml without manually merging in the diffs.

Is there a supported way to do this? I tried an XML <import/> tag, but I get errors on plugin install that multiple plugins were found, or if I comment out the <plugin> block for my plugin, that no plugins were found.

I could reimplement this from scratch, but I'd really like to be able to reuse some of the code from aardmapper.lua (e.g. find()), but then I'd need access to the stateful "mapper" object from aard_GMCP_mapper.xml, and I don't think that's possible (by design).
Australia Forum Administrator #1
This is somewhat of a hack, but this appears to work:

Template:saveplugin=Alternative_Mapper
To save and install the Alternative_Mapper plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Alternative_Mapper.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Alternative_Mapper.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<!DOCTYPE muclient [
   <!ENTITY show_vnums "true" >
   <!ENTITY show_timing "false" >
   <!ENTITY show_completed "true" >
   <!ENTITY show_database_mods "false" >
   <!ENTITY show_other_areas "false" >
   <!ENTITY show_up_down "false" >
   <!ENTITY speedwalk_prefix "run" >
]>

<muclient>
<plugin
   name="Alternative_Mapper"
   author="Multiple"
   id="83fdb6092b08fb95e4f85a2f"
   language="Lua"
   purpose="Allows you to modify the Aardwolf mapper"
   save_state="y"
   date_written="2019-11-29 07:01:18"
   requires="4.73"
   version="1.0"
   >
<description trim="y">
<![CDATA[
AUTOMATIC MAPPER by Fiendish
** This is a very improved GMCP version of the original ATCP mapper by Nick Gammon.
** Some GMCP specific code added by Lasher.
** A few features contributed by Spartacus.
** Many major improvements made to the original design by Fiendish.
]]>
</description>
</plugin>

<script>
local show_vnums = &show_vnums;
local show_timing = &show_timing;
local show_completed = &show_completed;
local show_database_mods = &show_database_mods;
local show_other_areas = &show_other_areas;
local show_up_down = &show_up_down;
local speedwalk_prefix = "&speedwalk_prefix;"

<![CDATA[

-- helper import function
function ImportFromPlugin (what)
  local xml = string.match (plugin, string.format ('<%s>.*</%s>', what, what))
  assert (xml, "Could not find the " .. what)
  ImportXML (xml)
  xml = nil -- free memory
end -- ImportFromPlugin

-- read the entire plugin into memory
f = assert (io.open (GetInfo (60) .. "aard_GMCP_mapper.xml", "r"))  -- open it
plugin = f:read ("*a")  -- read all of it
f:close ()  -- close it

-- get the original timers, triggers, aliases
ImportFromPlugin 'timers'
ImportFromPlugin 'triggers'
ImportFromPlugin 'aliases'

-- get the script
script = string.match (plugin, '<script>(.*)</script>')
assert (script, "Could not find the script")
plugin = nil  -- free memory

-- pull out the CDATA stuff from within the script
script = string.match (script, '<!%[CDATA%[(.*)%]%]>')
assert (script, "Could not find the internal script")

-- load the script
assert (loadstring (script)) ()
script = nil -- free memory


-- replace functions here

function map_find (name, line, wildcards)

   local rooms = {}
   local count = 0

   -- find matching rooms using exact match
   local name = wildcards[1]

   if string.sub(wildcards[1],1,1) == "\"" and string.sub(wildcards[1],-1) == "\"" then
      name = string.sub(wildcards[1],2,-2)
   end
   for row in dbnrowsWRAPPER(string.format ("SELECT uid, name FROM rooms WHERE rooms.name = %s", fixsql (name))) do
      table.insert(rooms, {uid=row.uid, reason=true})
      count = count + 1
   end   -- finding room

   -- see if nearby
   mapper.find (name,
      rooms,  -- function
      50,
      show_vnums,  -- show vnum?
      count,      -- how many to expect
      false,       -- don't auto-walk
      nil,
      quick_mode
   )
end -- map_find

]]>
</script> 

</muclient>


What this does is read in the Aardwolf mapper as a text file, import its triggers, timers and aliases, and then import its script file. This should now be effectively a copy of the original plugin (aard_GMCP_mapper.xml).

Now you have the plugin in a script space you control, you can replace functions in it as in the example map_find function above.

So:

  • Remove aard_GMCP_mapper.xml from your plugins list
  • Place this plugin there instead
  • Save the world file and restart the client


Now any future fixes should be automatically implemented, except to the function map_find of course.

An alternative approach for this particular problem would be to ask Fiendish to add a configuration option (like the other ones at the start of the plugin) to make the mapper find not default to wildcards.
Amended on Thu 28 Nov 2019 09:10 PM by Nick Gammon
#2
Wow, thank you for the in depth answer and the amazing response time.

I will look into a feature request to Fiendish as well (or maybe put together a pull request) but it's great to have this option.

If you're in the US then happy Thanksgiving :)
USA Global Moderator #3
Quote:
Specifically, I want to add a function to the aard_GMCP_mapper.xml plugin that's distributed with the Aardwolf MUSHclient package: "mapper find" but without the wildcards around the query string, so that it only returns exact room name matches.

No need to modify. Just put quotation marks around your search string.

( https://github.com/fiendish/aardwolfclientpackage/blob/f3d7a146771b5283a44ad17a771ac13774330216/MUSHclient/worlds/plugins/aard_GMCP_mapper.xml#L3850-L3852 )

I think of everything.