Technical information on the gnome

This page contains technical info and may go over many viewer's heads. It is provided for information purposes only and is not guaranteed to be 100% accurate. In addition, questions on this information may not be able to get answered on the forum.

Database structure

PingGnome uses a MySQL database to store data. To view the exact schema for the database, go here. The latest version of the table status can be found here.

Gnome's script

PingGnome runs on a StealthBot, which uses the Microsoft Scripting Library to handle plugins. While StealthBot may not the best choice for a data collection script, it is still very flexible.

A connection to the database is made from the get-go, and is constantly updated with every event. All four bots (west, east, europe, asia) run off the same executable, and logs are enabled. This generates very large log files, so I developed a program to troll through them and remove any information that does not pertain to data/information collection.

The code aspect of the bot is fairly simple. SQL queries are passed to update channel and user data. Checks and balances are abundant, such as making sure not to insert duplicate records or appending a channel to a user if the channel is public and the user has been seen in a private channel. Usernames are trimmed to remove the gateway (@USWest) and numbers (#2), as the product and whole name are more valuable. A blacklist is in place, which blocks channels or users on all realms from using the bot. Here is the subroutine for the "ping name" command as of December, 2008:

'PingGnome Script by The_Lynxy 'Clan R1SK @ USWest '--------------------------------------------------------------- 'ReportPing() function as of Dec 5, 2008 '--------------------------------------------------------------- 'Useful information: 'bUsername=Target person to ping 'CallingName=Person who asked for request ' 'lastReportTime=time of last ping report. duh. 'AntiPingMeSpam=Scripting dictionary to prevent spam of same command ' 'PingerAddQ() is this script's queue processing sub, but does other things (such as send to WebBot) 'CheckBlacklist() returns if the current channel/user is blacklisted. 'GetExtendedRealm() returns a string if the current realm table differs from what bot is connected to 'FixLongUsername() trims @uswest off name and #2 etc 'PingerDateDiff() returns the time the player was last seen, in nice format 'Pinger_GetClientsForUser() does just what it says. Returns a string containing each client seen for that user '--------------------------------------------------------------- Sub ReportPing(bUsername, bFlags, bMessage, bPing, IsSelf, CallingName) Dim Username, Flags, Message, Ping Username=bUsername Flags=bFlags Message=bMessage Ping=bPing if Ping=-38 then exit sub if instr(Flags,"/w") then whisperTo="/w " & Mid(Flags,instr(Flags,"/w")+2) & " " if waitingToJoin=1 then exit sub if CheckBlacklist(Username)=1 and whisperTo="" then exit sub if Len(Username)>50 then exit sub if Timer-lastReportTime<0 then lastReportTime=0 if IsSelf<>2 then if Timer-lastReportTime<3 then exit sub if Timer-lastReportTime<6 and IsScanning=1 then exit sub if IsScanning=1 then PingsInChan=PingsInChan+1 if IsScanning=1 and PingsInChan=6 then PingerAddQ whisperTo & "Maximum query limit per channel exceeded" exit sub end if if IsScanning=1 and PingsInChan>5 then exit sub if IsScanning=1 then if instr(lcase(PingsInChanUsers),lcase(username) & " ") then exit sub PingsInChanUsers=PingsInChanUsers & Username & " " end if end if lastReportTime=Timer if AntiPingMeSpam.Exists(CallingName) then spamArray=AntiPingMeSpam.Item(CallingName) if GetGTC()-spamArray(0)<0 then spamArray(0)=0 if GetGTC()-spamArray(0)<30000 and spamArray(1)=Ping and lcase(spamArray(2))=lcase(Username) then Exit Sub elseif GetGTC()-spamArray(0)<30000 and lcase(spamArray(2))=lcase(Username) then whisperTo="/w " & FullUsername & " " end if AntiPingMeSpam.Item(CallingName)=Array(GetGTC(),Ping,Username) else AntiPingMeSpam.Add CallingName,Array(GetGTC(),Ping,Username) end if if instr(Message,"*") or instr(Message,"?") then PingerAddQ whisperTo & "[Error] The ""ping"" command does not accept wildcards; use ""search"" command instead." exit sub end if myClient=GetInternalDataByUsername(Username,3) if instr(Username," ") then myClient=Mid(Username,instr(Username," ")+1) Username=Mid(Username,1,instr(Username," ")-1) IsSelf=1 end if if myClient="-5" then myClient="" if len(myClient)>0 and len(myClient)<>4 then PingerAddQ whisperTo & "[Error] There is an obvious error in the specified product parameter" exit sub end if myPing=GetInternalDataByUsername(Username,2) if myPing=-5 then myPing=GetInternalDataByUsername(Username & "@" & RealmTable,2) end if Username=FixLongUsername(Username) Username=Replace(Username,"""","""""") Username=Replace(Username,"'","''") Message=Replace(Message,"""","""""") Message=Replace(Message,"'","''") 'Message=Replace(Message,"[","[[]") 'Message=Replace(Message,"]","[]]") xtraSQL="" if IsSelf=1 then if myClient<>"" then xtraSQL="`client` = '" & myClient & "' AND " end if end if sql = "SELECT `lowest_ping`,`highest_ping`,`average_ping`,`last_ping`,`channel`,`times_seen`,`first_seen`,`last_seen`,`username`,`client` FROM `" & RealmTable & "` WHERE " & xtraSQL & "`username` = '" & Username & "' ORDER BY `last_seen` DESC" sql if Pinger_rec.EOF=False then dim lowping, highping, avgping, lastping, tChannel, tTimes, tFirst, tLast lowping = Pinger_rec("lowest_ping") highping = Pinger_rec("highest_ping") avgping = Pinger_rec("average_ping") lastping = Pinger_rec("last_ping") tChannel = Pinger_rec("channel") tTimes = Pinger_rec("times_seen") tFirst = Pinger_rec("first_seen") tLast = Pinger_rec("last_seen") Username = Pinger_rec("username") posClient=" [" & Pinger_rec("client") & "]" tChanList=Split(tChannel,"") if UBound(tChanList)>1 then ttlChans=UBound(tChanList) & " channels" else ttlChans="1 channel" end if if instr(tChannel,"") then tChannel=Mid(tChannel,1,instr(tChannel,"")-1) end if if IsSelf=2 then GlobalReport=GlobalReport & Username & ":" & avgping & " " else if len(posClient)<>7 then posClient=" [Unknown]" end if if myPing<>-5 then posCurPing=" [Current: " & myPing & "] " else posCurPing="" end if if lastping<>myPing then posLastPing=" [Last:" & lastping & "]" else posLastPing="" end if if tChannel="" then tChannel="" if InStr(tFirst, " ") then tFirst=Mid(tFirst, 1, InStr(tFirst, " ") - 1) if InStr(tLast, " ") then tLast=Mid(tLast, 1, InStr(tLast, " ") - 1) Pinger_GetSeenOld "lastseen " & Pinger_rec("username") & " " & Pinger_rec("client"),sayText,theDay,wName,wCli,tChannel 'theDay=Pinger_GetSeen(Username, Client, "", "last") addLastSeen="" compMinsAgo=DateDiff("n",theDay,Now) if compMinsAgo>2 then posLastSeen=PingerDateDiff(theDay,Now) addLastSeen=" [Last seen: " & posLastSeen & "]" end if tReport=whisperTo & GetExtendedRealm tReport=tReport & Username tReport=tReport & posClient & posCurPing & posLastPing tReport=tReport & "[Lowest:" & lowping & "] " tReport=tReport & "[Highest:" & highping & "] " tReport=tReport & "[Average:" & avgping & "] " tReport=tReport & "[Seen: " & tTimes & " " & vbsIIF(tTimes=1,"time","times") tReport=tReport & " in " & ttlChans & " since " & tFirst & "]" tReport=tReport & addLastSeen 'in channel" & ttlChans & ": " & tChannel & "]" '[Lookup time: " & Int((Timer - lastReportTime) * 1000) & "ms]" PingerAddQ tReport end if Else if IsSelf<>2 then if myClient<>"" then possCli=Pinger_GetClientsForUser(Username) if possCli="" then PingerAddQ whisperTo & "[Error] " & GetExtendedRealm & Username & " (" & UCase(myClient) & ") not found in database." else PingerAddQ whisperTo & "[Error] " & GetExtendedRealm & "No records for " & Username & " using " & UCase(myClient) & ". Clients found: " & possCli end if else PingerAddQ whisperTo & "[Error] " & GetExtendedRealm & Username & " not found in database." end if end if End If Pinger_rec.close End Sub
The above information is only provided for informational purposes, and I will not provide any help with this sample script.

A lot of the script is very messy and inefficient. Many functions could be created that would greatly improve performance as well as make nicer code, but the whole script just needs to be rewritten (which will eventually happen).

While scanning, gnome detects if someone is talking to it by checking if their message contains the whole word "gnome" or "ping". If it does, it detects what other words are in the sentence to form it's response. For example, if any hateful words are found, it assumes you are talking bad to it. If no words are detected, it picks a random number and it's response is a random saying, which are mainly statistical. Example:
tRnd=int(rnd(8)*8) select case tRnd case 0 Set rs = Pinger_conn.Execute("SELECT ROUND(AVG(average_ping)) FROM " & RealmTable & " WHERE average_ping>0 AND average_ping<10000") PingerAddQ gUser & ", did you know the average ping of " & RealmTable & " is " & rs.Fields(0) & " ms?" TalkingToType=4 case 1 Set rs = Pinger_conn.Execute("SELECT COUNT(*) FROM " & RealmTable & " WHERE channel LIKE '%" & myChannel & "%'") PingerAddQ gUser & ", did you know I have seen " & rs.Fields(0) & " different users in this very channel?" TalkingToType=4 case 2 PingerAddQ "If Mittens saved the penguins based on his beliefs, and Mittens beliefs were not in his direct control, does Mittens really have free will?" TalkingToType=5 case 3 Set rs = Pinger_conn.Execute("SELECT * FROM " & RealmTable & "_chans WHERE channel='" & myChannel & "'") If rs.EOF Then PingerAddQ "/me looks at " & gUser & " in a panic. What am I doing here!?" else numBan=Int(CStr(rs.Fields("ban"))) numRes=Int(CStr(rs.Fields("restricted"))) numSuc=Int(CStr(rs.Fields("success"))) numPer=int(100/(numRes+numSuc)*numRes) if numBan=0 then msgBan="I have never been banned from this channel (Nice!)" else percBan=Round(100/(numSuc+numBan)*numBan,1) msgBan="I have been banned from this channel " & numBan & " time" & vbsIIF(numBan=1,"","s") & " (" & percBan & "%)" if numBan=1 and percBan<33 then msgBan=msgBan & " (lol..)" end if end if msgRes=", and that this channel is restricted " & numPer & "% of the time?" PingerAddQ gUser & ", did you know " & msgBan & msgRes TalkingToType=4 end if

Every 2 hours, Gnome initiates a scan if she is not already on one. The entire scanning routine is on a timer with a interval of 7 seconds (except for uswest, this server requires a higher join interval or it gets IP banned, I'm not sure why). The list of channels to scan is retrieved once from the channel table with the following SQL query and stored in memory:
SELECT * FROM `" & RealmTable & "_chans` WHERE `dead` IS NULL OR `dead`=0 ORDER BY Rnd(Len(channel))

If 10 channels in a row are restricted, it joins a randomly generated channel, so as to get out of the user's hair. Once a scan is finished, the script trolls the user table looking for any new clans it may have seen while scanning, and adds them to the channel list. All ignore and submit requests are now looked up online.

There any many scheduled tasks that run several times a day to do maintenance on the database, such as checking for dead clans, ranking channels, clearing old webbot chat, and the like.

That is the rundown on the script. Again, help on anything from this page is very limited, as I will not hold your hand if you want to make your own. As FrostWraith from has said, This kind of script should only be run by people who understand how to make it.