[Scripters] How to use SpewStat Events

free(?!) clues!

[Scripters] How to use SpewStat Events

Postby Kannkor » 17 Aug 2024, 10:27

Made a new super easy way to get a return from any spewstat value, even if it takes "time" to process (such as faction, currency etc).

You can attach to event named "OgreEvent_SpewStats", which provides 1 parameter of jsonvalue with all the details.

Lets look at a super simple example.
Now, you SHOULD always be using objects... however, this example includes how to use it in an object, and how to not use an object (using an atom). Pick your preferred way (should be object).
Code: Select all
function main()
{
   variable Object_SpewStatsEvent Obj_SpewStatsEvent
   Event[OgreEvent_SpewStats]:AttachAtom[OgreEvent_SpewStats]

   while 1
      waitframe
}
atom OgreEvent_SpewStats(jsonvalue _JSONValue)
{
   echo ${Time}: atom OgreEvent_SpewStats: ${_JSONValue.AsJSON} Character: ${_JSONValue.Get["Character"]}
}
objectdef Object_SpewStatsEvent
{
   method Initialize()
   {
      Event[OgreEvent_SpewStats]:AttachAtom[This:OgreEvent_SpewStats]
   }
   method OgreEvent_SpewStats(jsonvalue _JSONValue)
   {
      echo ${Time}: method OgreEvent_SpewStats: ${_JSONValue.AsJSON} Character: ${_JSONValue.Get["Character"]}
   }
}


Now, any time a spewstat is issued, you'll get responses. This is done over the uplink.
For example: Lets say we want to look at dungeon marks.
Code: Select all
!c -SpewStat auto "currency_Dungeon Mark"

(I have two characters online, Toon1 and Toon2)
Code: Select all
11:15:41: atom OgreEvent_SpewStats: {"Character":"Toon1","Command":"Currency","Label":"Dungeon Mark","Value":"24412"} Character: Toon1
11:15:41: method OgreEvent_SpewStats: {"Character":"Toon1","Command":"Currency","Label":"Dungeon Mark","Value":"24412"} Character: Toon1
11:15:43: atom OgreEvent_SpewStats: {"Character":"Toon2","Command":"Currency","Label":"Dungeon Mark","Value":"724207"} Character: Toon2
11:15:43: method OgreEvent_SpewStats: {"Character":"Toon2","Command":"Currency","Label":"Dungeon Mark","Value":"724207"} Character: Toon2

(It's only showing each person twice because we have attached to the event twice, once via atom and once via event)

Examine 2: Looking at resolve
Code: Select all
!c all -spewstats auto resolve irc

Same two characters
Code: Select all
11:17:30: atom OgreEvent_SpewStats: {"Character":"Toon2","Command":"resolve","Label":"Resolve:","Value":"10,330"} Character: Toon2
11:17:30: method OgreEvent_SpewStats: {"Character":"Toon2","Command":"resolve","Label":"Resolve:","Value":"10,330"} Character: Toon2
11:17:30: atom OgreEvent_SpewStats: {"Character":"Toon1","Command":"resolve","Label":"Resolve:","Value":"10,360"} Character: Toon1
11:17:30: method OgreEvent_SpewStats: {"Character":"Toon1","Command":"resolve","Label":"Resolve:","Value":"10,360"} Character: Toon1


Just keep in mind, everything will take "time" to be processed and results sent back to you. Specifically faction/currency/etc. Things that have to open the persona window. Things like resolve that are very fast, still technically take time (measured in mili-seconds, but you still have to account for it).
Note: If it would not have an output normally, it won't have an output here.
Code: Select all
11:20:12: !c -SpewStat auto "!item_Instance Lockout Reset: 7 Day Reuse" irc

This is checking to see if anyone does NOT have a reset item (notice the ! before item) (Both of mine do, so there is no output)
Whereas if we check if we DO have the item
Code: Select all
!c -SpewStat auto "item_Instance Lockout Reset: 7 Day Reuse"

We get a results
Code: Select all
11:21:23: atom OgreEvent_SpewStats: {"Character":"Toon2","Command":"item_Instance Lockout Reset: 7 Day Reuse","Label":"has item:","Value":"Instance Lockout Reset: 7 Day Reuse"} Character: Toon2
11:21:23: method OgreEvent_SpewStats: {"Character":"Toon2","Command":"item_Instance Lockout Reset: 7 Day Reuse","Label":"has item:","Value":"Instance Lockout Reset: 7 Day Reuse"} Character: Toon2
11:21:23: atom OgreEvent_SpewStats: {"Character":"Toon1","Command":"item_Instance Lockout Reset: 7 Day Reuse","Label":"has item:","Value":"Instance Lockout Reset: 7 Day Reuse"} Character: Toon1
11:21:23: method OgreEvent_SpewStats: {"Character":"Toon1","Command":"item_Instance Lockout Reset: 7 Day Reuse","Label":"has item:","Value":"Instance Lockout Reset: 7 Day Reuse"} Character: Toon1


Finally, some outputs (at the time of writing this, only faction) have some additional data.
Code: Select all
!c -SpewStat auto "faction_The city of Qeynos"

Results: Notice the FactionStanding
Code: Select all
11:23:27: atom OgreEvent_SpewStats: {"Character":"Toon1","Command":"Faction","Label":"The City of Qeynos","Value":"13,000","FactionStanding":"amiably"} Character: Toon1
11:23:27: method OgreEvent_SpewStats: {"Character":"Toon1","Command":"Faction","Label":"The City of Qeynos","Value":"13,000","FactionStanding":"amiably"} Character: Toon1
11:23:27: atom OgreEvent_SpewStats: {"Character":"Toon2","Command":"Faction","Label":"The City of Qeynos","Value":"40,000","FactionStanding":"ally"} Character: Toon2
11:23:27: method OgreEvent_SpewStats: {"Character":"Toon2","Command":"Faction","Label":"The City of Qeynos","Value":"40,000","FactionStanding":"ally"} Character: Toon2


Lastly, if you do not want these to output anywhere (all the above examples would output to OgreConsole or IRC), you can use the word "event" to send them exclusively to the event. For example:
Code: Select all
!c -SpewStat auto "currency_City Token" event

Has no output to the console, but the OgreEvents still trigger.
Kannkor
 
Posts: 361
Joined: 06 Nov 2013, 11:49

Re: [Scripters] How to use SpewStat Events

Postby Kannkor » 11 Sep 2024, 23:36

Someone wanted to track some currencies over time, and using these events.

I put together an overly complicated example... oops.
It tracks something (you can change it), and reports back every time you issue the command to check the currency.

Code: Select all
/*
    Currency Example

    Using this as our base
    Please note: You need to change the line #46 to whichever the current one you are using. I was using Copper to test. Example: variable string DataTypeToCollect="Me.Copper"
    I have left some other examples with it for the other ones.
    oc !c -spewstats igw:${Me.Name} "currency_Minted Celebration Token"
    oc !c -spewstats igw:${Me.Name} "currency_Immeasurable Obol"
    oc !c -spewstats igw:${Me.Name} "Me.Platinum"
    oc !c -spewstats igw:${Me.Name} "Me.Copper"
   

    Step 1: Run this script: "run CurrencyExample"
    Step 2: Use the OC command: oc !c -spewstats igw:${Me.Name} "Me.Copper"
    Step 3: Watch your console (not OC) for output
    Step 4: Wait for it to "finish" it's collection (which is the max time, currently set to 5 seconds). Looks like this: [currencyexample]: Different timestamps that exist: 1
    Step 5: Repeat Step 2
    Step 6: Wait for it to finish again, and this time you will have more output
        yyy -> Me.Copper -> Current: 29 Previous: 45 Change: -16
        xxx -> Me.Copper -> Current: 79 Previous: 96 Change: -17

    20:51:30: method OgreEvent_SpewStats: {"Character":"ToonB","Command":"Currency","Label":"Minted Celebration Token","Value":"5046"} Character: ToonB
    20:51:30: method OgreEvent_SpewStats: {"Character":"ToonA","Command":"Currency","Label":"Minted Celebration Token","Value":"13414"} Character: ToonA

    Now we know how the data is coming in, we can decide what we want to do with it.

    The goal here, is to get the amount of tokens we have, then get the amount of tokens we have later, to see what the increase was.
*/

; Gonna use a timer incase we don't get everyone reporting as a fail safe.
#include "${LavishScript.HomeDirectory}/Scripts/OgreCommon/Object_Timer.iss"

; Include my JSONHelper. It has some helper functions that make dealing with JSON within lavish a bit easier
#include "${LavishScript.HomeDirectory}/Scripts/OgreCommon/Object_JSONHelper.iss"
variable Object_JSONHelper Obj_JSONHelper

function main()
{
   variable Object_SpewStatsEvent Obj_SpewStatsEvent
   Event[OgreEvent_SpewStats]:AttachAtom[OgreEvent_SpewStats]

   while 1
      waitframe
}

objectdef Object_SpewStatsEvent
{
    ; Lets limit our data collection to the one specific type we want for now
    ; variable string DataTypeToCollect="Minted Celebration Token"
    ; variable string DataTypeToCollect="Immeasurable Obol"
    variable string DataTypeToCollect="Me.Copper"
   
    ; When we ask everyone to report their currency value, we need a max wait time. We're going to use 10 seconds.
    variable int MaxWaitPeriod=5
    variable Object_Timer Timer_MaxWaitPeriod

    ; This will hold all our data from all reports
    variable jsonvalue DataSet={}

    ; reference to the "current" data point
    variable jsonvalueref CurrentSet

    ; Just a reusable container for jsonvalues
    variable jsonvalue jv={}

    method Initialize()
    {
        Event[OgreEvent_SpewStats]:AttachAtom[This:OgreEvent_SpewStats]

        ; Creating a new event, so after our max wait time expires, it triggers the output. This is the event name I used. If you change it, change it in the call 25 lines down
        LavishScript:RegisterEvent[SpewStatEvent_CurrencyExample]
        Event[SpewStatEvent_CurrencyExample]:AttachAtom[This:SpewStatEvent_CurrencyExample]
    }
    ; I like having an easy, custom echo method for output information
    method Echo(string _Message)
    {
        echo ${Time}: [${Script.Filename}]: ${_Message}
    }
    ; This is the event that is triggered by SpewStats
    method OgreEvent_SpewStats(jsonvalue _JSONValue)
    {
        ; This is just outputing everything. Remove once done testing
        This:Echo["method OgreEvent_SpewStats: ${_JSONValue.AsJSON} Character: ${_JSONValue.Get["Character"]}"]

        ; If it's not the data we want, just return
        if !${_JSONValue.Get["Label"].Equal["${This.DataTypeToCollect}"]}
            return

        ; Do we already have a timer going? If not, start a timer as this is a new "set" of data.
        if !${This.Timer_MaxWaitPeriod.TimeLeft}
            This:NewDataSet

        ; Add our data
        This:AddData[_JSONValue]
    }
    method NewDataSet()
    {
        ; If this is a new "time period" (of 10 seconds) then do some work!
        ; We set the maximum time to wait, and at the end we trigger our event, so it will output the results
        This.Timer_MaxWaitPeriod:SetSeconds[${This.MaxWaitPeriod},"CurrencyExample","-TriggerEventName","SpewStatEvent_CurrencyExample"]

        ; If this is the first one, create our layout - a timestamp array
        if !${This.DataSet.Has["timestamps"]}
            Obj_JSONHelper:AddArray["This.DataSet","timestamps"]

        ; Add the actual timestamp, this will hold the data for everyone reporting
        ; Using JSON in lavish can be really annoying, as it requires a lot of escaping. The JSONHelper removes that and handles strings.
        ; We are just telling it to use our reusable jsonvalue (This.jv) and add time:12345 to it, but in json formatting.
        Obj_JSONHelper:SetJSON["This.jv","time","${Time.Timestamp}"]
        variable int iArray
        ; Add a new array, and add the time:timestamp to it. Save the array location...
        iArray:Set[${Obj_JSONHelper.AddArrayItem["DataSet.Get["timestamps"]","${This.jv.AsJSON}"]}]
        ; Rather than have to search every time, just set a reference to our current data set
        This.CurrentSet:SetReference["This.DataSet.Get["timestamps"].Get[${iArray}]"]

        if !${This.CurrentSet.Reference(exists)}
        {
            ; This shouldn't happen, but if the reference doesn't work, script won't work
            This:Echo["NewDataSet: reference didn't set"]
            Script:End
        }
    }
    method AddData(jsonvalueref _JSONValue)
    {
        ; Create an object with our character name to hold the data, and add the data
        This:Echo["AddData: Adding data for ${_JSONValue.Get["Character"]} -> ${_JSONValue.AsJSON~}"]
        Obj_JSONHelper:AddObject["This.CurrentSet","${_JSONValue.Get["Character"]}","_JSONValue"]
        ; Can uncomment line below if you wish to see what was added.
        ; echo ${This.CurrentSet.AsJSON[multiline]}
    }
    ; This will trigger when our time period of 10 seconds is completed
    method SpewStatEvent_CurrencyExample(string _EventName, jsonvalue _JSONValue)
    {
        ; Do the comparison and output here
        ; Dump everything out for now
        ; echo ${This.DataSet.AsJSON[multiline]}
        This:Echo["Different timestamps that exist: ${This.DataSet.Get["timestamps"].Used}"]

        ; can't compare data with only 1 set!
        if ${This.DataSet.Get["timestamps"].Used} < 2
            return

        ; Lets compare the last 2 sets only
        variable int iIndexNew
        variable int iIndexOld

        variable int iToonIndex
        variable string ToonName
        variable jsoniterator it
        variable int64 iValueNew
        variable int64 iValueOld

        ; We want to capture our two data sets
        iIndexNew:Set[${This.DataSet.Get["timestamps"].Used}]
        iIndexOld:Set[${iIndexNew}]
        iIndexOld:Dec[1]

        echo ...
        ; Keep in mind, 1 of the informations will be the timestamp. The rest will be objects with our data
        This:Echo["Information within our timestamp: ${This.DataSet.Get["timestamps"].Get[${iIndexNew}].Used}"]

        ; Use an iterator to go through the data
        This.DataSet.Get["timestamps"].Get[${iIndexNew}]:GetIterator[it]

        for ( it:First ; ${it.Value(exists)} ; it:Next)
        {
            ; If it's our time, skip it. We can do things with it, if we want.
            if ${it.Key.Equal["time"]}
            {
                continue
            }
            ; While everything else should be objects, we can confirm
            if ${it.Value.Type.Equal["object"]}
            {
                ; Want to see the data coming? Uncomment below
                ; echo [${it.Key} - ${it.Value.Type}] -> ${it.Value}
                ; Lets cache some values
                iValueNew:Set[${it.Value.Get["Value"]}]
                if !${This.DataSet.Get["timestamps"].Get[${iIndexOld}].Has["${it.Key}"]}
                {
                    ; This means our previous report did NOT have this person. You could continue going backwards through the list of data to see if they ever reported it
                    ; for now, you need to have two reports in a row, which should be normal.
                    This:Echo["${it.Key} Current: ${iValueNew}. No previous value."]
                    continue
                }
                ; Capture the value from the previous report so we can compare it
                iValueOld:Set[${This.DataSet.Get["timestamps"].Get[${iIndexOld}].Get["${it.Key}"].Get["Value"]}]
                ; Output our character name (it.key), then the value last reported, followed by the previous value reported, and finally some math on the difference.
                echo ${it.Key} -> ${This.DataTypeToCollect} -> Current: ${iValueNew} Previous: ${iValueOld} Change: ${Math.Calc64[${iValueNew}-${iValueOld}]}
            }
        }
    }
}
Kannkor
 
Posts: 361
Joined: 06 Nov 2013, 11:49


Return to Guides & Strats

Who is online

Users browsing this forum: No registered users and 3 guests

cron