[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Tips and tricks
. . -> [Subject]  Plugger - A small "structured plugin" aid

Plugger - A small "structured plugin" aid

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Tue 16 Feb 2010 07:37 AM (UTC)

Amended on Tue 16 Feb 2010 08:04 AM (UTC) by Twisol

Message
I wrote this small XML library to make it easier to write and maintain my structured plugins. One of the first things it does is "fix" the path and cpath to be relative to the structured plugin's directory rather than the plugins/ directory. It also creates a plugger.path() function to easily get a path relative to the plugin's directory.

The last thing it does is execute a require("scripts.main") call, seeking a main.lua file within the scripts/ subfolder. Coupled with a form of scripted trigger/alias/timer creation, such as direct MUSHclient API or my Reflex library, the only XML files you really need are this one and the plugin file itself.

I wrapped this library in XML to make it easy for a plugin author to package and include without going through too many contortions. I could have done raw Lua instead, but this isn't (and arguably shouldn't be) a standard-distribution library, so it's easier to package with the plugin itself than to require that it be installed separately into the MUSHclient/lua/ folder.

<!DOCTYPE script>

<script><![CDATA[

plugger = {}
plugger.path = function(subdir)
  if not subdir then
    subdir = ""
  else
    subdir = subdir:gsub("%.", "\\")
    if subdir:sub(#subdir) ~= "\\" then
      subdir = subdir .. "\\"
    end
  end
  
  return GetPluginInfo(GetPluginID(), 20) .. subdir
end

-- fix the lua path
do
  local path = utils.split(package.path, ";")
  path[1] = plugger.path() .. "?.lua"
  table.insert(path, 2, plugger.path() .. "libraries\\?.lua")
  table.insert(path, 3, plugger.path() .. "libraries\\?\\init.lua")
  package.path = table.concat(path, ";")
  
  local cpath = utils.split(package.cpath, ";")
  cpath[1] = plugger.path() .. "?.dll"
  table.insert(cpath, 2, plugger.path() .. "libraries\\?.dll")
  package.cpath = table.concat(cpath, ";")
end

require("scripts.main")

]]></script>

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #1 on Tue 16 Feb 2010 07:40 AM (UTC)

Amended on Tue 16 Feb 2010 07:41 AM (UTC) by Twisol

Message
An example plugin.xml file that uses Plugger:

plugin.xml
<!DOCTYPE muclient> 

<muclient> 
<plugin
   name="roomname"
   author="Soludra"
   id="e94f6bd8509a2b00d10cb226"
   language="Lua"
   purpose="Adds a Nexus room name to the status bar"
   date_written="2008-08-23"
   requires="4.35"
   version="1.0"
   >
</plugin>

<include name="$PLUGINDIR\libraries\plugger.xml" />

</muclient>


scripts/main.lua
-- Used to load the ATCP interface
PPI = require("ppi")

-- Will contain the ATCP interface
atcp = nil


-- Executed when you get an ATCP message!
OnRoomBrief = function(message, content)
  SetStatus(content .. ".")
end

-- Loads the ATCP library
OnPluginListChanged = function()
  local atcp, reloaded = PPI.Load("7c08e2961c5e20e5bdbf7fc5")
  if not atcp then
    -- Normally, you might put an error or a warning note here.
    -- Roomname won't do anything if ATCP isn't available, so
    -- it's safe to leave it running until ATCP comes online.
  elseif reloaded then
    -- Registers a function to call when Room.Brief is received.
    atcp.Listen("Room.Brief", OnRoomBrief)
  end
end


In effect, this makes plugin.xml a simple, generic metadata file, leaving the actual scripts to do the work. As well, the code in main.lua is largely unaffected.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Maxhrk   USA  (76 posts)  [Biography] bio
Date Reply #2 on Sun 20 Jun 2010 11:41 PM (UTC)

Amended on Wed 30 Jun 2010 05:08 PM (UTC) by Maxhrk

Message
Hello, sorry to animate this thread to life once again, but i have some few questions regards, specifically, PPI.


I want to know how PPI work, so far, i have learned about ppi.load, ppi.expose that are public function(I may miss some of them, the public functions.

in any case, mind give me more examples how ppi can be used with expose, load, etc.

Thanks! :D

EDIT: my goal with this PPi is that i want to listen to any plugins that might want to tell my GMCP plugin like, "hello! i am mapper, i want to hear from you regards room.list and whatever the info it may have, bahbah. bah. THANKS! bye!" so I can register the mapper in list and when i got the GMCP message and if it contains room.info, so I can look up in the table to see which plugin want this kind of information. Then, to give that information to the plugin subscriber(s)

That what i want to know how to use PPI with that I has in mind. Thanks again!
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #3 on Sun 20 Jun 2010 11:57 PM (UTC)

Amended on Mon 21 Jun 2010 12:00 AM (UTC) by Twisol

Message
Maxhrk said:

Hello, sorry to animate this threat to life but i have some few questions regards, specifically, PPI.


I want to know how PPI work, so far, i have learned about ppi.load, ppi.expose that are public function(I may miss some of them, the public functions.

in any case, mind give me more examples how ppi can be used with expose, load, etc.

Thanks! :D


The actual PPI thread is over here [1], this one's for the mini-library that makes structured plugins easier to make.

Here's an example from a post I made in that thread, on page 10:


local PPI = require("ppi")

function OnRoomBrief(msg, content)
  -- called by the ATCP plugin
end

-- (ID, on_success, on_failure)
PPI.OnLoad("7c08e2961c5e20e5bdbf7fc5", function(atcp)
  atcp.Listen("Room.Brief", OnRoomBrief)
end, function(reason)
  -- Optional callback for if it's not available.
end)

function OnPluginListChanged()
  PPI.Refresh()
end


This is pretty much all you need to do on the client side. You need to call PPI.Refresh() in OnPluginListChanged() so the library can track installed plugin. To tell PPI that you want to communicate with a specific plugin, you pass it that plugin's ID in OnLoad, as well as two functions. One function is called when the interface is successfully set up, and it receives the interface itself. The other is optional, called when the interface wasn't loaded and receiving the reason as a string.

Your OnLoad callbacks are called whenever the target plugin is reloaded, too. You primarily just want to use it to initialize. In this case, I'm telling my ATCP plugin what messages I'm listening for. You can also store the interface somewhere else so you can access it later; I don't expect you to do -everything- you need in the initialization callback.

Also, notice that I'm passing a function to the other plugin! This isn't normally possible between plugins, and in fact this involves a little trickery to do. This is important though, because that function will be called when that ATCP message is received. I don't have to do anything else, because PPI and the ATCP plugin do the rest.


On the "service" side (i.e. the ATCP plugin here), you need to use PPI.Expose to register functions that clients can call.

local PPI = require("ppi")
local PPI = require("libraries.ppi")

PPI.Expose("Listen",
  function(message, callback)
    -- stuff here
  end
)


PPI handles passing the parameters and return values back and forth, so you can pretty much treat it as a normal function.


Beyond this extra scaffolding, you write the rest of your plugin pretty normally.

Maxhrk said:
EDIT: my goal with this PPi is that i want to listen to any plugins that might want to tell my GMCP plugin like, "hello! i am mapper, i want to hear from you regards room.list and whatever the info it may have, bahbah. bah. THANKS! bye!" so I can register the mapper in list and when i got the GMCP message and if it contains room.info, so I can look up in the table to see which plugin want this kind of information. Then, to give that information to the plugin subscriber(s)

That what i want to know how to use PPI with that I has in mind. Thanks again!

Take a look at my ATCP plugin and how it uses PPI. You'll probably have to very similar things for GMCP. (The main script file is in ATCP.plugin/scripts/main.lua)

I wrote PPI specifically for this kind of thing. ;)

[1] http://www.gammon.com.au/forum/?id=9970&page=999 (the PPI thread)

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio
Date Reply #4 on Mon 21 Jun 2010 04:39 PM (UTC)
Message
Why's it being called 'GMCP'? I thought that it was ATCP2, since, well, it's no longer being done by people other than Zugg and IRE. It's not very nice to take the name that was supposed to be for the community version. :-)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #5 on Tue 22 Jun 2010 12:17 AM (UTC)
Message
David Haley said:
Why's it being called 'GMCP'? I thought that it was ATCP2, since, well, it's no longer being done by people other than Zugg and IRE. It's not very nice to take the name that was supposed to be for the community version. :-)


http://ironrealms.com/gmcp-doc

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #6 on Tue 22 Jun 2010 04:43 AM (UTC)

Amended on Tue 07 Apr 2015 01:41 AM (UTC) by Nick Gammon

Message
I think GMCP was *my* suggestion:

mudstandards.org/forum/viewtopic.php?f=7&t=50&start=30

Nick Gammon said:

Re: Renaming ATCP

Postby Nick Gammon » Fri Apr 02, 2010 4:27 am

It's not really an automated protocol. What about GMCP - Generic MUD Communication Protocol?



Well at least one of my suggestions made it into the protocol - the name itself. ;)


[EDIT] (April 2015) Warning: Domain name mudstandards.org has been abandoned. That site is now an adult products shop.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio
Date Reply #7 on Tue 22 Jun 2010 04:06 PM (UTC)
Message
Twisol said:

David Haley said:
Why's it being called 'GMCP'? I thought that it was ATCP2, since, well, it's no longer being done by people other than Zugg and IRE. It's not very nice to take the name that was supposed to be for the community version. :-)


http://ironrealms.com/gmcp-doc

Is this supposed to answer my question? Perhaps in the literal sense that you're calling it GMCP because that is what IRE poached. As I said, it's not very polite to take somebody else's name but discard all of their suggestions otherwise.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


26,640 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]