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

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Plugins
. . -> [Subject]  Problems with OnPluginConnect
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Problems with OnPluginConnect

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


Pages: 1 2  

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Mon 20 Apr 2009 07:23 AM (UTC)

Amended on Mon 20 Apr 2009 04:17 PM (UTC) by David Haley

Message
I'm having some rather odd problems, and I'm not sure what's going on. I'm using my ATCP plugin, which broadcasts to other plugins to ask if they need any modules enabled, then sends the resulting 'hello' ATCP message to the server. I have four plugins that use this functionality currently, each requesting one module: room_brief, char_vitals, and two requests for room_exits.

When I load up MUSHclient and connect, the message sends for char_vitals and room_brief, but not room_exits. Disabling one of the room_exits plugins fixes this problem, but I'm not sure why. (The code that sets the modules is located in EnableModule())

The second problem that I'm experiencing is, when I disconnect and then reconnect, sometimes (pretty frequently) no modules are enabled even though I know the broadcast is being responded to. I have -no- idea what's causing this.

Help would be majorly appreciated! =/

MUSHclient version is 4.40.


codes = {
  ["IAC WILL ATCP"] = "\255\251\200", -- server-sent
  ["IAC WONT ATCP"] = "\255\252\200", -- server-sent
  ["IAC DO ATCP"]   = "\255\253\200", -- client-sent, enables ATCP
  ["IAC SB ATCP"]   = "\255\250\200", -- begins an ATCP packet
  ["IAC SE"]        = "\255\240",     -- ends an ATCP packet
  ["IAC WILL EOR"]  = "\255\251\025", -- ???
}

client_id =  "MUSHclient " .. Version()
nexus_opts = {}
commands = {}

mods = {auth        = {version = "1"},
        char_name   = {version = "1"},
        char_vitals = {version = "1"},
        room_brief  = {version = "1"},
        room_exits  = {version = "1"},
        map_display = {version = "1"},
        composer    = {version = "1"},
        keepalive   = {version = "1"},
        topvote     = {version = "1"},
        ping        = {version = "1"},
       }

OnPluginConnect = function()
  -- alert other plugins to EnableModule now.
  BroadcastPlugin(0, "")

  local msg = "hello " .. client_id .. "\10"
  local line = ""

  for k, v in pairs(nexus_opts) do
    line = line .. k .. ", "
    msg = msg .. k .. " " .. v .. "\10"
  end

  Note(line:sub(1, line:len() - 2))

  SendPkt(codes["IAC DO ATCP"] .. codes["IAC SB ATCP"] .. msg .. codes["IAC SE"])
end

OnPluginDisconnect = function()
  nexus_opts = {}
  commands = {}
end

OnPluginPacketReceived = function(packet)
  if string.find (packet, codes["IAC WILL ATCP"]) then
    packet = string.gsub (packet, "(.-)" .. codes["IAC WILL ATCP"] .. "(.-)", "%1%2")
  end
  if string.find (packet, codes["IAC WONT ATCP"]) then
    packet = string.gsub (packet, "(.-)" .. codes["IAC WONT ATCP"] .. "(.-)", "%1%2")
  end
  if string.find (packet, codes["IAC WILL EOR"]) then
    packet = string.gsub (packet, "(.-)" .. codes["IAC WILL EOR"] .. "(.-)", "%1%2")
  end

  local packet, atcp, parsed = parseATCP(packet)
  -- pack up the messages and send them to listeners
  for msg, line in pairs(parsed) do
    BroadcastPlugin(1, msg .. "|" .. line)
  end

  return packet
end

-- splits an ATCP message into header and content lines
split_atcp = function(msg)
  -- find a Something.Something marker
  -- (i.e. Room.Brief, Char.Vitals)
                -- match1
  local start, en, head = string.find(msg, "^(%w+%.%w+)")
                                   -- PCRE: ^(\w+\.\w+)

  local cont = string.sub(msg, en+2)

  -- make sure we got anything at all
  if start then
    return head, cont
  else
  -- was a dud message (nothing between the begin/end bytes)
    return nil
  end
end

leftovers = ""
PAT = codes["IAC SB ATCP"] .. "(.-)" .. codes["IAC SE"]

parseATCP = function(packet)
  -- tacks on any remainder from the last packet
  local packet = leftovers .. packet
  leftovers = ""

  local atcp, parsed = {}, {}

  -- passed to string.gsub() below
  -- used to handle each capture
  local replace_func = function(cap)
    head, cont = split_atcp(cap, parsed)

    -- make sure we got something
    if head ~= nil then
      parsed[head] = cont
      table.insert(atcp, cap)
    end
    return ""
  end

  -- catch atcp messages, remove inline
  packet = string.gsub (packet, PAT, replace_func)

  -- finds any leftovers from an unfinished ATCP message
  local s,e,msg = string.find (packet, "(\255[^\255]-\255?)$")
  if s then
    if (#msg == 1) or ( (#msg > 2) and string.find (msg, "^\255\250\200") ) 
       or ( (#msg > 1) and string.find (msg, "^\255\250") ) then 
      leftovers = msg
      packet = string.sub (packet, 1, s-1)
    end
  end
  return packet, atcp, parsed
end


EnableModule = function(lines)
  if type(lines) == "string" then
    lines = utils.split(lines, ",")
  elseif type(lines) ~= "table" then
    error("Invalid argument to EnableModule: " .. lines .. "\10")
  end
  -- lines should be a table at this point

  for _, m in ipairs(lines) do
    Note(m)

    v = mods[m]
    if v then
      nexus_opts[m] = v.version

      -- import module commands
      v.version = nil
      for i, j in pairs(v) do
        Note("Loading command " .. i .. ": " .. j)
        commands[i] = j
      end
    end
  end
end

'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 #1 on Mon 20 Apr 2009 04:18 PM (UTC)
Message
(I took the liberty of fixing the forum code in your post to prevent the subscripting from italicizing the rest of the program.)

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 #2 on Mon 20 Apr 2009 06:45 PM (UTC)
Message
Thanks <_<

'Soludra' on Achaea

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Tue 21 Apr 2009 03:29 AM (UTC)
Message
This doesn't look right to me:


if type(lines) == "string" then
    lines = utils.split(lines, ",")
  elseif type(lines) ~= "table" then
    error("Invalid argument to EnableModule: " .. lines .. "\10")
  end
  -- lines should be a table at this point


This is the function that is called back from the BroadcastPlugin is that it?

You know, with elseif, if the first condition matches it won't do the second test? If you are expecting to break up the incoming line into a table, and then check you have a table, you need two if statements, like this:


if type(lines) == "string" then
    lines = utils.split(lines, ",")
end

if type(lines) ~= "table" then
    error("Invalid argument to EnableModule: " .. lines .. "\10")
end

 -- lines should be a table at this point

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #4 on Tue 21 Apr 2009 03:30 AM (UTC)
Message
Also, this works, but is a different style to what I use elsewhere:


EnableModule = function(lines)
  -- blah blah
end -- function EnableModule


I prefer the syntactic sugar that makes it clearer we are starting a function definition:


function EnableModule (lines)
  -- blah blah
end -- function EnableModule


For me, the keyword "function" stands out more at the start of the line.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Tue 21 Apr 2009 03:32 AM (UTC)
Message
Quote:

["IAC WILL EOR"] = "\255\251\025", -- ???


See: http://www.faqs.org/rfcs/rfc885.html

This is the END-OF-RECORD option.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #6 on Tue 21 Apr 2009 03:35 AM (UTC)
Message
Quote:

error("Invalid argument to EnableModule: " .. lines .. "\10")



BTW, \10 is the newline character, so it is more usual to use \n.

In any case I don't think you need it, error messages are not normally terminated by a newline, Lua adds that anyway.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #7 on Tue 21 Apr 2009 03:36 AM (UTC)
Message
Quote:

if type(lines) ~= "table" then
error("Invalid argument to EnableModule: " .. lines .. "\10")
end


In fact, this is a good use for assert, ie.


assert (type (lines) == "table", "Invalid argument to EnableModule: " .. lines)


- Nick Gammon

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

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #8 on Tue 21 Apr 2009 04:18 AM (UTC)
Message
Whew, lots of replies.

Quote:

if type(lines) == "string" then
lines = utils.split(lines, ",")
elseif type(lines) ~= "table" then
error("Invalid argument to EnableModule: " .. lines .. "\10")
end
-- lines should be a table at this point

The argument should come in as either a string or a table. If it's a string, I convert it to a table. I don't need to check that, because I know it's already a table. If it's not a string, it checks the elseif. If it's not a table already, I don't care what it is, it's wrong! ;)

Quote:

This is the END-OF-RECORD option.

Ah, thanks. Didn't particularly know what it was for or why I needed to watch for it in the packets, since I based this plugin off of another.


Quote:

BTW, \10 is the newline character, so it is more usual to use \n.

In any case I don't think you need it, error messages are not normally terminated by a newline, Lua adds that anyway.

I've had strange experiences with needing arbitrary amounts of slashes before the \n, and when I used \10 at some random point in time it worked, so it became a habit. Not technically the best way to start a habit, I suppose.




Anyways, I still haven't discovered why it's not working depending on how many times I've called OnPluginConnect. It only seems to work the first time I open the world and connect, which implies that something's up with my 'mods' table, and I'm printing the contents of 'mods' every time I connect, so nothing's off there...

'Soludra' on Achaea

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #9 on Tue 21 Apr 2009 06:34 AM (UTC)
Message
Personally I think this is confusing:


  local packet, atcp, parsed = parseATCP(packet)


You are redefining packet here (creating a new local variable of the same name). I think it is OK to do it, but it is confusing.

Quote:

... no modules are enabled even though I know the broadcast is being responded to ...


What do you mean by that exactly? What variable/table is being set or not set, and how do you know this?

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #10 on Tue 21 Apr 2009 06:46 AM (UTC)
Message
Quote:

I've had strange experiences with needing arbitrary amounts of slashes before the \n, and when I used \10 at some random point in time it worked, so it became a habit.


If you use send-to-script, then \n gets expanded to a newline before it hits the script engine, and thus may cause problems (eg. unterminated literal strings). However \10 would not be have so expanded.

But when you move your scripts to a script file, then this pre-expansion is not done, and you can just code in the normal way.

- Nick Gammon

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

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #11 on Tue 21 Apr 2009 06:58 AM (UTC)
Message
Quote:
You are redefining packet here (creating a new local variable of the same name). I think it is OK to do it, but it is confusing.

You're probably right, though that code was there already. I think the idea is that we're replacing the old packet with the ATCP-less packet.


Quote:
What do you mean by that exactly? What variable/table is being set or not set, and how do you know this?

I checked nexus_opts after BroadcastPlugin(0, "") and it was empty, and I also put a Note() in OnBroadcastPlugin of one of my ATCP-using plugins that shows that, yes, it is indeed receiving the broadcast (and responding). I also put Note()s in EnableModule to check what was going on in there.

'Soludra' on Achaea

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #12 on Tue 21 Apr 2009 07:23 AM (UTC)
Message
Some test plugins I just wrote seem to indicate that the BroadcastPlugin and CallPlugin functions work exactly as I expected, even if you disconnect and reconnect.

Exactly what are your debugging displays showing? Is EnableModule doing what it should and putting things into the nexus_opts table? If so, I don't see why it should be empty afterwards.

- Nick Gammon

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

Posted by Nick Gammon   Australia  (21,322 posts)  [Biography] bio   Forum Administrator
Date Reply #13 on Tue 21 Apr 2009 07:24 AM (UTC)
Message
Is your plugin exactly what you posted here? If you start adding "local" here and there it can completely change how it will work.

- Nick Gammon

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

Posted by Twisol   USA  (2,257 posts)  [Biography] bio
Date Reply #14 on Tue 21 Apr 2009 07:37 AM (UTC)

Amended on Tue 21 Apr 2009 07:38 AM (UTC) by Twisol

Message
Word for word. Given, I removed some comments and functions that weren't even used at all (SendATCP and the mods.<module>.<command> functions; none of my plugins use those), but apart from that I didn't add any extra 'local's or anything. The only reason I removed stuff at all was to fit the X000-character limit on posts.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[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.


11,466 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

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 FutureQuest]