Some thoughts about faxbot()

fronobulax

Developer
Staff member
In response to https://kolmafia.us/showthread.php?23587-Checking-Easyfax-doesn-t-time-out I started looking at the code.

My specific concern was the ash command faxbot() but some of these comments apply to fax support in general.

At present faxbot() will only request a monster from the first faxbot that has it. It returns true if a monster was successfully faxed but false does not mean the attempt was unsuccessful. Sometimes false means the attempt was made and definitely failed but sometimes it just means the attempt was made and the status is unknown. Since the faxbot command checks for a photocopied monster in inventory and offers the chance to dump the fax or abort, several scripts ignore the return from faxbot() and instead detect success or failure from the presence of the photocopied monster.

There is dead code that once aborted the command if chat was not running but that code is disabled, presumably in 2012.

The faxbot online status is based upon /whois and is not changed by the non-success of fax attempts. This is as it should be IMO.

The faxbot() command iterates over all bots and returns the result from the first one. An attempt (temp code change) was made to check the next bot when the first one failed, but if chat was not running the result was getting a fax from one bot, not knowing the status, and then getting a fax from the next bot. (Tangentially, I did not see the expected prompt from a photocopied monster present so I don't know whether I don't quite understand the code or what so there is some work to be done).

AFAIK there is no easy way for a script writer to detect that a bot did not return the desired fax and try a different bot.

I can see several possibilities.

Status Quo - leave things as they are.

Add ash functions so that a scripter knows which bots are available and whether a monster is available from a specific bot. This essentially moves the iterate over bots until success or end of list from mafia to the script.

Create int robust_faxbot() that returns 1 if the requested monster was faxed, 0 if there is already a photocopied monster (possibly unknown) in inventory and -1 if it failed.

Modify faxbot() so that it checks other bots in case of failure and uses the presence/absence of the photocopied monster to define success/failure.

And there are always things I have not thought about.

I am inclined towards the latter but it will make some code in some scripts unnecessary.

This is essentially my response to an unmade Feature Request to try all known bots before failing to get a fax.

Thoughts? Comments?
 
This is a tricky one. I think the existing workarounds don't handle having to change a faxbot well at all (in fact, having private clans is yet another workaround for this to avoid relying on a missing faxbot).

The faxbot() function is very unique compared to other functions because it has an interaction with open chat (very much an unexpected behavior for newer customers).

I agree with your asserton about online status. Generally, once the faxbot is online, it stays online until rollover (or until someone pollutes my DNS...)

I don't think changing the faxbot() function is necessarily a good idea, although, I have no idea how many workflows would be broken by it and it doesn't have current run significance so it may be worthwhile to say: we need to redo this, sorry for the change. That said, faxbot() seems to treat the lack of chat response as a complete failure and doesn't even check if the fax occurred and the message was lost. Of course, we wouldn't expect the message to get lost so it typically is a failure in that case but it isn't that unusual of a case to not have chat open (I haven't opened it since 2018 and I can't really support telling scripters that they'd have to have chat open).

It is also possible that the we get the wrong fax because it changed before we got to it. I've had that happen once (I don't know if mafia checks for that but I have in script).

I'll go back to what I recall thinking when I wrote fax code: I wished faxbot() would check the fax machine when it thinks it fails and use that to determine the situation and discarding the fax if it is not a match. That might have some issues with special named monsters (chatty pirate male/female) though. So, I don't know what a good answer is.
 

fronobulax

Developer
Staff member
If I call faxbot() with chat already open then true means it got a fax (confirmed) by chat and false meansit got no response in chat within the timeout.

If I call faxbot() with chat closed then faxbot() always returns false but often there is a photocopied monster and it is the correct monster. The most robust scripts actually use the photocopied monster as a means of deciding whether the fax request failed, or not.

My interest comes from a case where chat is open, the fax fails on the monster but the same monster is available from another faxbot. mafia could decide to try the other bot before returning failure.

If you have not visited the Altar of Literacy faxbot() returns failure when it tries to determine the status via /whois.

I have no experience clanhopping and using faxbot(). I also don't recall an experience where there were multiple manipulations of the fax machine so that the monster was not the expected one, but I can see how it might happen

I think internally mafia uses monster ID. Does that address the "specially named" monster concern?

I thought I could tweak faxbot() to check other bots on failure and not break any existing scripts but I am less certain.

Thanks.
 
I think internally mafia uses monster ID. Does that address the "specially named" monster concern?

The rest is above my paygrade, but I assume mafia recognized the monster from its name as mentioned in the item description of the photocopied monster, so converting that into an id number might actually introduce errors rather than reduce them.
 
I think there has been an issued raised that mafia can not detect if chat is open. Although, I suppose you could track requests to newchatmessages.php (not sure if that is it) but I haven't really thought it all out either. But yeah, it seems like you have the right idea and checking the photocopy is always a good idea.

I had your same issue but without chat open, I ended up changing the faxbot order in mafia but that solution really only works because I can personally guarantee a faxbot when I want it. My code ended up trying to fax for hours before I had noticed. I wasn't really sure if the issue was partly my fault for not having chat open though.

I did not think of the Altar of Literacy case. I would assume mafia can't send a chat message to the faxbot either. I can't remember if cheesefax accepted fax by kmail but I'd probably not worry about supporting anyone who can't chat.

My clanhopping experience was to clan hop and just pull the copy, it was mandatory during my mass casual scripting to save time. The time I had the wrong monster was due to a connection issue on my side and accidentally requesting from both faxbots.

I think the "special named" monster issue reared its head up more recently with mine worker (female) and mine worker (male) because the photocopy just says mine worker. Unless there is a mosnter ID on the photocopy that I wasn't aware of. It is technically an issue with things like the old astronomer and animated nightstands but I don't think anyone has had a reason to automate those where it wasn't too unreasonable for them to just do those manually. Whereas, there seems to be some reason for the mine workers.

"Failure" just needs to be careful I suppose. Right now, it seems to be handled passively, no chat response -> failure. So, with chat open, it is reasonable to try to make another request (probably). Without chat open, which is a case I think needs to continue to work (but that may be a personal opinion), we would end up requesting from every faxbot and still seeing a failure.

Checking newchatmessages.php automatically could resolve this but it could also eat private messages and that's probably undesirable. If, upon failure, the fax machine were checked before considering moving to the next bot, that seems reasonable? A more complex possibility could be to track whenever chat is checked and if it has been checked X seconds after the chat request (at the timeout I assume) then assume it is a failure, otherwise, assume chat is closed and check the machine.

I say all of this with the awareness of only one way of handling faxbot(). I can't imagine any other use-cases but I could be wrong and I have no idea how other scripts doing their faxing.
 

fronobulax

Developer
Staff member
There are circumstances when mafia correctly knows chat is open but automatically opening it is technically challenging and generally considered A Bad Idea.

When KoL first implemented useful chat commands there was some consternation about mafia using them and thus requiring mafia users to chat. For a long time, mafia would use the chat command if available and fall back to "the old way" if not. I have an illiterate multi so we can at least detect cases where chat is mandatory and "document" that.

Calling faxbot(), having it return false but getting the correct photocopied monster is definitely undocumented behavior that is expected and used.
 
Yeah, automatic opening is totes a bad idea.

I can't imagine there is any other good way to make a faxbot response. Chat messages were probably a good UX and who knows if automation had really been considered (I'm going to guess the faxbots were not made with mafia as a consideration). But, I can't really think of any other good way to indicate a successful fax (and then that would be a burden on the faxbot developers as well).
 

AlbinoRhino

Active member
I can't remember but is the Clan Activity Log something that is always available or can it be hidden behind a permission? If it's detected to be available, then that page could be monitored for the arrival of the monster into the fax machine. It looks like that is what my fax-related code does, (but I'm sure I have whatever permissions that might apply). Also, that involves extra server hits...usually only a couple.
 
It requires permissions. I have code somewhere that uses it when possible but I don't have those permissions in every clan I've been in.
 

zarqon

Well-known member
If I call faxbot() with chat closed then faxbot() always returns false but often there is a photocopied monster and it is the correct monster. The most robust scripts actually use the photocopied monster as a means of deciding whether the fax request failed, or not.

This matches my experience. My logout script will faxputty monsters from a hardcoded list if I haven't fought my fax for the day. My multis are never logged in to chat, and I've never had issues with it. Rather than just checking the photocopied monster, my script also checks the clan log. The relevant excerpt:

PHP:
  // request & retrieve fax
   monster current_faxmachine() {
      matcher pg = create_matcher("\\)\\</a\\> faxed in a (.+?)\\<br\\>",visit_url("clan_log.php"));
      if (pg.find() && vprint("Current monster in fax machine: "+pg.group(1),2)) return to_monster(pg.group(1));
      return $monster[none];
   }
   if (current_faxmachine() == chosen.m) cli_execute("fax get");
   if (get_property("photocopyMonster").to_monster() != chosen.m) {
      if (item_amount($item[photocopied monster]) > 0) cli_execute("fax put");
      print("Requesting a "+chosen.m+"...");
      if (!faxbot(chosen.m) && current_faxmachine() == chosen.m) cli_execute("fax get");
   }

Just adding it to the discussion in case it is helpful.

ETA: Ah, just noticed this was already discussed. I hadn't considered some people may not be able to see the clan log. Nothing to see here, folks.
 

fronobulax

Developer
Staff member
Just for closure I'm going to say that I don't see a compelling case to make some changes. There are things that could be done to improve error reporting and handling but those changes would have side effects and it seems like overall the status quo is acceptable.
 
Top