• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Optibug

Level 11
Joined
Nov 4, 2007
Messages
337
Well, the name 'Optibug' is quite strange. But I couldn't think of a better one.
I made this to make debugging more clear.
I like automatic-working-systems, so you don't need extra functions.
You just have to use BJDebugMsg.

What does this exactly do?
It prevents that systems spam the same error message like
100 times per second. Messages that are similar are only displayed
once in X (20) seconds when you use BJDebugMsg and this system.
But it has got mechanisms to prevent big performance losses, too.
Read the systems code for further information.

JASS:
library Optibug requires Table
//===========================================================================
// Information: 
//==============
//  Do you know the stupid fact that you want to debug your systems, and they spam exactly the same
//  message like 100 times per second? Well, this solves that problem.
//  But I have to warn you: This will hook BJDebugMsg.
//  So it wouldn't be such useful if you used BJDebugMsg for displaying messages to all players.
//
//  What does this exactly do?
//  It registers the usages of the BJDebugMsg function and ensures that messages that are 'similar'
//  are only displayed one time in X seconds. If the displayed strings are just are bit different, like
//  if they contain different integers, the system updates them and marks them as 'similar'.
//
//  Bad about this is, that it uses really a lot of your CPU. You can prevent causing too much
//  lag, by modifying the constants.
//
//===========================================================================
// Implementation: 
//===============
//
//  1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
//     edit to use this tool. The 'JassNewGen' is used very commonly and offers other
//     nice features. You can find it at:
//     [url]http://www.wc3c.net/showthread.php?t=90999[/url]

//  2. Make a new trigger, and convert it to custom text. Insert everything
//     the library contains into that trigger.
//
//  3. Download a system called 'Table' from this link:
//     [url]http://www.wc3c.net/showthread.php?t=101246[/url]
//     Do the same installation stuff for 'Table' as for this system.
//
//  4. Save your map and enjoy :-)
//    
//===========================================================================
// The constants:
// ==============
//
//   RECYCLE_INTERVAL    : How often are errors displayed? When do their values get recycled?
//   MIN_STRING_MATCH    : This system checks if strings from the data storage match with new strings.
//                         How similar must two strings be to be 'similar'?
//   PASS_INTERVAL       : How often are data passed to the recycler? Unimportant!
//   MAX_INSTANCES       : How many instances of different debug messages shall this handle maximally (right adverb?)?
//   PERFORMANCE_VALUE   : If the Optibug func is used for more than PERFORMANCE_VALUE times in RECYCLE_INTERVAL seconds,
//                         the system stops doing it's job: Because it would screw up ypur computers otherwise.
//
// =================================================================================================================
    globals
        private constant real RECYCLE_INTERVAL     = 20.
        private constant real MIN_STRING_MATCH     = 70.
        private constant real PASS_INTERVAL        = 1.5
        private constant integer MAX_INSTANCES     = 15
        private constant integer PERFORMANCE_VALUE = 250
    endglobals
    
    globals
        private integer passCount = 0
        private string array passData
        
        private integer recycleCount = 0
        private string array recycleData
        
        private timer Recycler = CreateTimer()
        private timer PassTimer = CreateTimer()
        private StringTable RegisterTable
        private boolean RecycleThreadRunning = false
        private integer PF_counter = 0
    endglobals
    
    private function RecycleData takes nothing returns nothing
        loop
            exitwhen recycleCount == 0
            set recycleData[recycleCount] = ""
            set recycleCount = recycleCount - 1
        endloop
        set RecycleThreadRunning = false
        call StartPassTimer.execute()
        set PF_counter = 0
    endfunction
    
    private function PassData takes nothing returns nothing
        if RecycleThreadRunning == false then
            loop
                exitwhen passCount == 0
                set recycleCount = recycleCount + 1
                set recycleData[recycleCount] = passData[passCount]
                set passCount = passCount - 1
            endloop
            set RecycleThreadRunning = true
            call PauseTimer(PassTimer)
            call TimerStart(Recycler,RECYCLE_INTERVAL,false,function RecycleData)
        endif
    endfunction
    
   function StartPassTimer takes nothing returns nothing
        call TimerStart(PassTimer,PASS_INTERVAL,true,function PassData)
    endfunction
    
    private function IsStringSimilarTo takes string a, string b, real percentage returns boolean
        local string tempa
        local string tempb
        local integer max = StringLength(a)+StringLength(b)
        local integer similar = 0
        loop
            exitwhen a == "" or b == ""
            set tempa = SubString(a,StringLength(a)-1,StringLength(a))
            set a = SubString(a,0,StringLength(a)-1)
            set tempb = SubString(b,StringLength(b)-1,StringLength(b))
            set b = SubString(b,0,StringLength(b)-1)
            if tempa == tempb then
                set similar = similar + 2
            else
                if StringLength(a) > StringLength(b) then
                    set b = b+tempa
                elseif StringLength(b) > StringLength(a) then
                    set a = a+tempb
                endif
            endif
        endloop
        if I2R(similar)/I2R(max) >= percentage*0.01 then
            return true
        endif
        return false
    endfunction

    // Check if the new string is similar to any registered string.
    // At the same time this refreshes the errors.
    private function MatchesSomeData takes string whichOne returns boolean
        local integer i = 0
        local boolean bool = false
        
        
        // We kill two birds with one stone here:
        // We check, wether the string is similar to one from the data storage
        // And we 'redisplay' everything.
        loop
            set i = i + 1
            exitwhen i > passCount
            if bool == false then
                if IsStringSimilarTo(whichOne,passData[i],MIN_STRING_MATCH) then
                    set passData[i] = whichOne
                    set bool = true
                else
                    call DisplayTextToPlayer(GetLocalPlayer(),0,0,passData[i])
                endif
            else
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,passData[i])
            endif
        endloop
        
        set i = 0
        loop
            set i = i + 1
            exitwhen i > recycleCount
            if bool == false then
                if IsStringSimilarTo(whichOne,recycleData[i],MIN_STRING_MATCH) then
                    set recycleData[i] = whichOne
                    set bool = true
                else
                    call DisplayTextToPlayer(GetLocalPlayer(),0,0,recycleData[i])
                endif
            else
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,recycleData[i])
            endif
        endloop
        
        return bool
    endfunction
    
    private function Optibug takes string s returns nothing
        if passCount + recycleCount < MAX_INSTANCES then
            set PF_counter = PF_counter + 1
            if PF_counter < PERFORMANCE_VALUE then
                call ClearTextMessages()
                // Displaying the messages is included in 'MatchedSomeData'
                if MatchesSomeData(s) == false then
                    set passCount = passCount + 1
                    set passData[passCount] = s
                endif
            endif
        else
            if passCount + recycleCount == MAX_INSTANCES + 1 then
                call DisplayTextToPlayer(GetLocalPlayer(),0,0,"Disabled 'Optibug' due to heavy performance flaws.")
            endif
        endif
    endfunction
    
    hook BJDebugMsg Optibug
    
    private function Init takes nothing returns nothing
        call StartPassTimer()
    endfunction
endlibrary

Feel free to post constructive feedback.
 
Level 8
Joined
Oct 3, 2008
Messages
367
If you're getting ERROR at all you're doing something wrong (I thought that was obvious). :smile:

If your message appears a hundred times, it's most likely something in a timer callback. And since it's supposed to be rather descriptive, it can be fixed rather easily.

Honestly, I don't see much of a point to this script.
 
Level 11
Joined
Feb 22, 2006
Messages
752
When I'm debugging a map. I don't really care if debug messages flood my screen. I'm not playing the map anyway I'm trying to see what's wrong with it. And usually you WANT to see every message esp if they are printing out game states. Otherwise you might miss something.

And if I get tired of having 100 errors popping up at once, it's not too hard to go back and comment out some debugging lines.
 
Top