String.gsub-ing packets?

Posted by Rivius on Sun 08 Jan 2012 04:41 PM — 4 posts, 20,563 views.

#0
In a game I play, if a line is detected to be an illusion, you will get a subsequent line telling you so. eg.


A cloudy tendril lashes at you, filling your mind with disturbing images.
Your eye immediately notices the flaws in what is obviously an illusion.


I've decided that instead of going through the pain of using triggers to ignore the afflictions added by the previous line (since one can use illusions to do far more than make you think you've been hit with something), I modified the packets directly to be prefixed by some text so that they wouldn't be matched. This is the code I am using now within a plugin:


function OnPluginPacketReceived(text)
	local i = string.find(text, "\nYour eye immediately notices the flaws in what is obviously an illusion%.")
	if i then
		local t = string.sub(text, 1, i - 1)
		t = string.gsub(t, "%[", "%%[")
		return string.gsub(text, t, string.gsub(t, "\n", "\nIllusion Detected: "))
	end
end


The problem is, this works for most illusions, but some seem to escape it somehow. I'm not sure why, either. I figured there's just something wrong with the way I'm substituting things and I'm hoping someone has a better way to go about it that would work for every line. The example I provided in the beginning is one line that simply didn't detect once.

Most things detect just fine, however, such as:


Illusion Detected: A sudden headache makes you rub your temples for relief.
Your eye immediately notices the flaws in what is obviously an illusion.


^ is an output after successful modification.
USA #1
Due to the vagaries of the Internet, packets aren't guaranteed to be received exactly as they were sent. In the absolute worst case, you can receive a single character at a time (which will probably never happen, but it's not disallowed). What might be happening is that you're getting a packet where the second line is cut off part of the way through, or even separated from the first line completely, and the rest is received in the next packet. MUSHclient guarantees that triggers will always have a full line to match on, but OnPluginPacketReceived bypasses that mechanism.

Furthermore, it might be possible to receive two illusions in a single network packet. As it stands, your code will only modify the first. You can use the Debug Packets window to view the raw data in each incoming and outgoing packet, which can help to confirm my guesses.


local EOL = "\n"

function detect_illusions(l1, l2)
  if l2 == "Your eye immediately notices the flaws in what is obviously an illusion." then
    l1 = "Illusion Detected: " .. l1
  end
  
  return l1
end

local prev_text = ""
function OnPluginPacketReceived(text)
  text = prev_text .. text

  local lines = utils.split(text, EOL)

  -- save incomplete line
  prev_text = table.remove(lines) or ""
  -- also save previous line so we can check it after
  -- the incomplete line is finished
  prev_text = (table.remove(lines) or "").. prev_text

  local prev_line = table.remove(lines, 1)
  for i,line in ipairs(lines) do
    line = detect_illusions(prev_line, line)
    prev_line, lines[i] = line, line
  end

  return table.concat(lines, EOL)
end


This approach basically means that the most recent line received won't be displayed, but if there's a way to tell for sure that a line isn't an illusion - for example, if illusions cannot contain colors - you can flush the buffer there. Of course, this code doesn't handle color sequences, and stuff like MXP or telnet negotiation sequences is included in the packet, unlike triggers where it's just the text.

(Also, I haven't tested this code. I hope it helps though!)
Amended on Sun 08 Jan 2012 09:30 PM by Twisol
Australia Forum Administrator #2
Data may cross packet boundaries also. There was a plugin a while back that built up a "whole" packet by waiting for a newline, or something like that.
#3
Hi, again. I've reapproached this topic a bit, as I've found need for it once more. This is the current version of my code, and it successfully handles multi-line illusions:


function OnPluginPacketReceived(pkt)
	local imtch = string.match(pkt, "(.*)[\r\n]Your eye immediately notices the flaws in what is obviously an illusion%.[\r\n]")
	if imtch then
		local fixed = string.gsub(imtch, "\n", "\nIllusion filtered and ignored: ")
		pkt = string.gsub(pkt, string.gsub(imtch, "([%[%]])", "%%%1"), fixed)
	end
	return pkt
end
end


I'm not sure if that's the best way in the world to do it, but it works fine in most illusions, including coloured ones. However, there is another type of illusion that is placed in a room and only fires upon entrance. It looks like this:

http://dl.dropbox.com/u/16429247/gamm.html

And my code doesn't seem to modify these lines as desired. I'm completely unsure of why this is and would like to find a way to investigate and get around this.


Also, a question, is this recommendable speed-wise, or should I just abandon this approach altogether?