System unitgroup

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
unitgroup is an attempt to replace the [ljass]native group[/ljass] type with a non native one (a struct type)
which is much easier to work with and is hopefully faster =).

Reasons that make the native group type "hard" to work with is that it doesn't know it's size (how many units there are),
requires enumeration callbacks (ForGroup) or FirstOfGroup enumerating for every operation performed on the group including
counting the number of units which are not really a good practice and doesn't have random access.

Requirements:
jasshelper compiler by Vexorian​
AutoIndex by grim001 or​
UnitIndexer by Nestharus​


The API is presented in C/C++ / C# / cJass / Galaxy Script function notation for brevity in pairs in which the
top one is the [ljass]group[/ljass] function name (if present) and the bottom is the [ljass]unitgroup[/ljass] alternative:

[ljass]group CreateGroup()[/ljass]
[ljass]static unitgroup new()[/ljass]

-- no native or bj available but possible --
[ljass]static unitgroup copy(unitgroup which_unitgroup)[/ljass]

[ljass]void GroupClear(group g)[/ljass]
[ljass]void clear()[/ljass]

[ljass]void DestroyGroup(group g)[/ljass]
[ljass]void delete()[/ljass]

[ljass]void GroupRemoveUnit(group g, unit u)[/ljass]
[ljass]void remove_unit(unit u)[/ljass]

[ljass]void GroupAddUnit(group g, unit u)[/ljass]
[ljass]void push_unit(unit u)[/ljass]

[ljass]bool IsUnitInGroup(unit u, group g)[/ljass]
[ljass]bool has_unit(unit u)[/ljass]

[ljass]unit GroupPickRandomUnit(group g)[/ljass]
[ljass]unit random_unit()[/ljass]

[ljass]void GroupEnumUnitsOfType(group g, string unitname, boolexpr filter)[/ljass]
[ljass]void enum_units_by_id(int id, int player, int max_count)[/ljass]

[ljass]void GroupEnumUnitsOfTypeCounted(group g, string unitname, boolexpr filter, int max_count)[/ljass]
[ljass]void enum_units_by_id(int id, int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsOfPlayer(group g, player p, boolexpr filter)[/ljass]
[ljass]void enum_units_of_player(int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsInRect(group g, rect r, boolexpr filter)[/ljass]
[ljass]void enum_units_in_rect(rect r, int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsInRectCounted(group g, rect r, boolexpr filter, int max_count)[/ljass]
[ljass]void enum_units_in_rect(rect r, int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsInRange(group g, real x, real y, real radius, boolexpr filter)[/ljass]
[ljass]void enum_units_in_range(real x, real y, real radius, int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsInRangeCounted(group g, real x, real y, real radius, boolexpr filter, int max_count)[/ljass]
[ljass]void enum_units_in_range(real x, real y, real radius, int p, int max_count)[/ljass]

[ljass]void GroupEnumUnitsSelected(group g, player p, boolexpr filter)[/ljass]
[ljass]void enum_units_selected_by_player(int p, int max_count)[/ljass]

[ljass]bool GroupImmediateOrderById(group g, int order)[/ljass]
[ljass]void immediate_order(int order)[/ljass]

[ljass]bool GroupPointOrderById(group g, int order, real x, real y)[/ljass]
[ljass]void point_order(int order, real x, real y)[/ljass]

[ljass]bool GroupTargetOrderById(group g, int order, widget target)[/ljass]
[ljass]void target_order(int order, widget target)[/ljass]

-- no native or bj available but possible --
[ljass]unit nearest_unit_from_point(real x, real y)[/ljass]

-- no native or bj available but possible --
[ljass]unit nearest_unit_from_unit(unit u)[/ljass]

[ljass]void ForGroup(group g, code callback)[/ljass]
JASS:
// equivalent in Zinc notation:

integer i = 0;
unit u;
for (0 <= i < |unitgroup_instance|.size)
{
    u = |unitgroup_instance|<i>;
    // do stuff with u
}
</i>


[ljass]unit FirstOfGroup(group g)[/ljass]
[ljass]|unitgroup_instance|[0][/ljass]

[ljass]int CountUnitsInGroup(group g)[/ljass]
[ljass]|unitgroup_instance|.size[/ljass]


JASS:
library unitgroup uses optional AutoIndex, optional UnitIndexer

    globals
    
    private constant boolean USE_ARRAYS_FOR_STORAGE = true
   
    // if the above constant is true then only 
    // UNITGROUP_MAX_INSTANCES unitgroups are allowed
    // each with maximum size of UNITGROUP_MAX_SIZE units
    private constant integer UNITGROUP_MAX_INSTANCES = 320
    private constant integer UNITGROUP_MAX_SIZE      = 1024
    private unit array UGC[UNITGROUP_MAX_INSTANCES][UNITGROUP_MAX_SIZE]
    // Note: UNITGROUP_MAX_INSTANCES * UNITGROUP_MAX_SIZE &lt;= 409 550 must be true
    //       else a compile time error will pop

    // else if the above constant is false then
    // 8190 unitgroups are allowed each with
    // an &quot;unlimited&quot; (limited by ram only) amount of units
    private hashtable HT

    // in terms of speed the 2d array (UGC) should be faster
    // so set the constant to true if you prefer speed
    // else set it to false if you want to be safe than sorry =)

    endglobals




    globals

    // used in some enum&lt;*&gt; methods
    constant integer ANY_PLAYER   = -1

    // could be used in all enum&lt;*&gt; methods
    constant integer NO_MAX_COUNT = 0

    private unit    array Units
    private integer       Units_count = 0

    endglobals

    private struct indexer extends array

    static if LIBRARY_AutoIndex then

        static method index takes unit u returns nothing
            set Units[Units_count] = u
            set Units_count = Units_count + 1
        endmethod

        static method deindex takes unit u returns nothing
            local integer i          = 0
            local integer unit_index = 0

            loop
                exitwhen  i &gt;= Units_count
                if Units<i> == u then
                    set unit_index = i
                    exitwhen true
                endif

                set i = i + 1
            endloop

            set Units[unit_index] = Units[Units_count - 1]
            set Units_count = Units_count - 1
        endmethod

        static method onInit takes nothing returns nothing
            call OnUnitIndexed(indexer.index)
            call OnUnitDeindexed(indexer.deindex)
        endmethod

    elseif LIBRARY_UnitIndexer then

        method index takes nothing returns nothing
            set Units[Units_count] = unit
            set Units_count = Units_count + 1
        endmethod

        method deindex takes nothing returns nothing
            local integer i          = 0
            local integer unit_index = 0

            loop
                exitwhen  i &gt;= Units_count
                if Units<i> == unit then
                    set unit_index = i
                    exitwhen true
                endif

                set i = i + 1
            endloop

            set Units[unit_index] = Units[Units_count - 1]
            set Units_count = Units_count - 1

        endmethod
        
        implement optional UnitIndexStruct

    else
        compiletimeexeption e = &quot;You need a unit indexing library =)&quot;
        throw e
    endif

    endstruct


           
    struct unitgroup

        // the number of units in the unitgroup
        readonly integer size


        //! textmacro unitgroup_assert_size takes METHOD_NAME, RETURN_VALUE
                debug if size &lt;= 0 then
                debug     call BJDebugMsg(&quot;unitgroup error: method $METHOD_NAME$: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: unitgroup is empty&quot;)
                debug     return $RETURN_VALUE$
                debug endif
        //! endtextmacro

        method operator[] takes integer i returns unit
            debug if  i &lt; 0 or i &gt;= size  then
            debug     call BJDebugMsg(&quot;unitgroup error: method operator[]: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: array index out of bounds&quot;)
            debug     return null
            debug endif

            static if USE_ARRAYS_FOR_STORAGE then
                return UGC[this]<i>
            else
                return LoadUnitHandle(HT, this, i)
            endif
        endmethod

        method operator[]= takes integer i, unit u returns nothing
            debug if  i &lt; 0 or i &gt;= size  then
            debug     call BJDebugMsg(&quot;unitgroup error: method operator[]=: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: array index out of bounds&quot;)
            debug     return
            debug endif

            static if USE_ARRAYS_FOR_STORAGE then
                set UGC[this]<i> = u
            else
                call SaveUnitHandle(HT, this, i, u)
            endif
        endmethod

        method has_unit takes unit which_unit returns boolean
            local integer i     = 0
            local unit    u     = null
            local boolean found = false

            //! runtextmacro unitgroup_assert_size(&quot;has_unit&quot;, &quot;false&quot;)

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif

                if u == which_unit then
                    set found = true
                    exitwhen true
                endif

                set i = i + 1
            endloop
        
            set u = null
            return found
        endmethod

        method remove_unit takes unit u returns nothing
            local integer i          = 0
            local integer unit_index = -1

            //! runtextmacro unitgroup_assert_size(&quot;remove_unit&quot;, &quot;&quot;)

            if u == null then
                debug call BJDebugMsg(&quot;unitgroup error: method remove_unit: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: attempt to remove null unit&quot;)
                return
            endif
            
            loop
                exitwhen i &gt;= size
                static if USE_ARRAYS_FOR_STORAGE then
                    if u == UGC[this]<i> then
                        set unit_index = i
                        exitwhen true
                    endif
                else
                    if u == LoadUnitHandle(HT, this, i) then
                        set unit_index = i
                        exitwhen true
                    endif
                endif
    
                set i = i + 1
            endloop
                        
            // if the unit was found
            if unit_index != -1 then
                static if USE_ARRAYS_FOR_STORAGE then
                    set UGC[this][unit_index] = UGC[this][size -1]
                    set size = size - 1
                else                        
                    call SaveUnitHandle(HT, this, unit_index, LoadUnitHandle(HT, this, size - 1))
                    set size = size -1
                endif
            endif
        endmethod

        method push_unit takes unit u returns nothing
            static if USE_ARRAYS_FOR_STORAGE then
                set UGC[this][size] = u
            else
                call SaveUnitHandle(HT, this, size, u)
            endif
            set size = size + 1
        endmethod

        method random_unit takes nothing returns unit

            //! runtextmacro unitgroup_assert_size(&quot;random_unit&quot;, &quot;null&quot;)

            static if USE_ARRAYS_FOR_STORAGE then
                return UGC[this][GetRandomInt(0, size -1)]
            else
                return LoadUnitHandle(HT, this, GetRandomInt(0, size - 1))
            endif
        endmethod


        method enum_units_of_player takes integer p, integer max_count returns nothing
            local integer i = 0
            local integer n = 0
            local player  P = null
            local unit    u = null                       

            if p == ANY_PLAYER then
                debug call BJDebugMsg(&quot;unitgroup error: method enum_units_of_player: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: expected a specific player not ANY_PLAYER&quot;)
                return
            endif

            set P = Player(p)
    
            loop
                exitwhen i &gt;= Units_count or (n &gt;= max_count and max_count != NO_MAX_COUNT)
                               
                set u = Units<i>
                if P == GetOwningPlayer(u) then

                    // push the unit
                    static if USE_ARRAYS_FOR_STORAGE then
                        set UGC[this][size] = u
                    else
                        call SaveUnitHandle(HT, this, size, u)
                    endif
                    set size = size + 1 
                endif

                set i = i + 1
                set n = n + 1
            endloop

            set u = null
        endmethod

        method enum_units_by_id takes integer id, integer p, integer max_count returns nothing
            local integer i = 0
            local integer n = 0
            local player  P = null
            local unit    u = null

            if id == 0 then
                debug call BJDebugMsg(&quot;unitgroup error: method enum_units_by_id: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: invalid unit id&quot;)
                return
            endif

            if p != ANY_PLAYER then
                set P = Player(p)
            endif
            
            loop
                exitwhen i &gt;= Units_count or (n &gt;= max_count and max_count != NO_MAX_COUNT)
                               
                set u = Units<i>
                if (p == ANY_PLAYER or P == GetOwningPlayer(u)) and id == GetUnitTypeId(u) then

                    static if USE_ARRAYS_FOR_STORAGE then
                        set UGC[this][size] = u
                    else
                        call SaveUnitHandle(HT, this, size, u)
                    endif
                    set size = size + 1 
                endif

                set i = i + 1
                set n = n + 1
            endloop

            set u = null
        endmethod

        method enum_units_in_rect takes rect r, integer p, integer max_count returns nothing
            local integer i    = 0
            local integer n    = 0
            local player  P    = null
            local unit    u    = null
            local real    ux   = 0
            local real    uy   = 0
            local real    minx = 0
            local real    maxx = 0
            local real    miny = 0
            local real    maxy = 0

            if r == null then
                debug call BJDebugMsg(&quot;unitgroup error: method enum_units_in_rect: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: expected a non null rect&quot;)
                return
            endif

            if p != ANY_PLAYER then
                set P = Player(p)
            endif

            set minx = GetRectMinX(r)
            set maxx = GetRectMaxX(r)
            set miny = GetRectMinY(r)
            set maxy = GetRectMaxY(r)
            
            loop
                exitwhen i &gt;= Units_count or (n &gt;= max_count and max_count != NO_MAX_COUNT)
                               
                set u = Units<i>
                set ux = GetUnitX(u)
                set uy = GetUnitY(u)
                if (p == ANY_PLAYER or P == GetOwningPlayer(u)) and minx &lt; ux and ux &lt; maxx and miny &lt; uy and uy &lt; maxy then

                    static if USE_ARRAYS_FOR_STORAGE then
                        set UGC[this][size] = u
                    else
                        call SaveUnitHandle(HT, this, size, u)
                    endif
                    set size = size + 1 
                endif

                set i = i + 1
                set n = n + 1
            endloop

            set u = null
        endmethod

        method enum_units_in_range takes real x, real y, real radius, integer p, integer max_count returns nothing
            local integer i = 0
            local integer n = 0
            local player  P = null
            local unit    u = null

            if radius &lt;= 0 then
                debug call BJDebugMsg(&quot;unitgroup error: method enum_units_in_range: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: invalid radius&quot;)
                return
            endif

            if p != ANY_PLAYER then
                set P = Player(p)
            endif

            loop
                exitwhen i &gt;= Units_count or (n &gt;= max_count and max_count != NO_MAX_COUNT)
                               
                set u = Units<i>
                if (p == ANY_PLAYER or P == GetOwningPlayer(u)) and IsUnitInRangeXY(u, x, y, radius) then

                    static if USE_ARRAYS_FOR_STORAGE then
                        set UGC[this][size] = u
                    else
                        call SaveUnitHandle(HT, this, size, u)
                    endif
                    set size = size + 1 
                endif

                set i = i + 1
                set n = n + 1
            endloop

            set u = null
        endmethod

        method enum_units_selected_by_player takes integer p, integer max_count returns nothing
            local integer i = 0
            local integer n = 0
            local player  P = null
            local unit    u = null

            if p == ANY_PLAYER then
                debug call BJDebugMsg(&quot;unitgroup error: method enum_units_selected_by_player: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: expected a specific player not ANY_PLAYER&quot;)
                return
            endif

            set P = Player(p)

            loop
                exitwhen i &gt;= Units_count or (n &gt;= max_count and max_count != NO_MAX_COUNT)
                               
                set u = Units<i>
                if IsUnitSelected(u, P) then

                    static if USE_ARRAYS_FOR_STORAGE then
                        set UGC[this][size] = u
                    else
                        call SaveUnitHandle(HT, this, size, u)
                    endif
                    set size = size + 1 
                endif

                set i = i + 1
                set n = n + 1
            endloop

            set u = null
        endmethod


        method immediate_order takes integer order returns nothing
            local integer i = 0
            local unit    u = null

            //! runtextmacro unitgroup_assert_size(&quot;immediate_order&quot;, &quot;&quot;)

            if order == 0 then
                debug call BJDebugMsg(&quot;unitgroup error: method immediate_order: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: ivalid order&quot;)
                return
            endif

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif

                call IssueImmediateOrderById(u, order)

                set i = i + 1
            endloop

            set u = null
        endmethod

        method point_order takes integer order, real x, real y returns nothing
            local integer i = 0
            local unit    u = null

            //! runtextmacro unitgroup_assert_size(&quot;point_order&quot;, &quot;&quot;)

            if order == 0 then
                debug call BJDebugMsg(&quot;unitgroup error: method point_order: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: ivalid order&quot;)
                return
            endif

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif

                call IssuePointOrderById(u, order, x, y)

                set i = i + 1
            endloop

            set u = null
        endmethod

        method target_order takes integer order, widget target returns nothing
            local integer i = 0
            local unit    u = null

            //! runtextmacro unitgroup_assert_size(&quot;target_order&quot;, &quot;&quot;)

            if order == 0 then
                debug call BJDebugMsg(&quot;unitgroup error: method target_order: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: ivalid order&quot;)
                return
            elseif target == null then
                debug call BJDebugMsg(&quot;unitgroup error: method target_order: &quot; + &quot;instance id = &quot; + I2S(this) + &quot;: expected a non null target&quot;)
                return
            endif

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif

                call IssueTargetOrderById(u, order, target)

                set i = i + 1
            endloop

            set u = null
        endmethod


        method nearest_unit_from_point takes real x, real y returns unit
            local integer i                 = 0
            local unit    u                 = null
            local real    ux                = 0
            local real    uy                = 0
            local real    curr_min_distance = 9999999
            local unit    nearest_unit      = null
            local real    dx                = 0
            local real    dy                = 0
            local real    distance          = 0

            //! runtextmacro unitgroup_assert_size(&quot;nearest_unit_from_point&quot;, &quot;null&quot;)

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif
                
                set ux = GetUnitX(u)
                set uy = GetUnitY(u)
                set dx = ux - x
                set dy = uy - y
                set distance = SquareRoot(dx * dx + dy * dy)

                if curr_min_distance &gt; distance then
                    set curr_min_distance = distance
                    set nearest_unit = u
                endif

                set i = i + 1
            endloop
                    
            set u = null

            return nearest_unit
        endmethod

        method nearest_unit_from_unit takes unit which_unit returns unit
            local integer i                 = 0
            local unit    u                 = null
            local real    ux                = 0
            local real    uy                = 0
            local real    curr_min_distance = 9999999
            local unit    nearest_unit      = null
            local real    dx                = 0
            local real    dy                = 0
            local real    distance          = 0
            local real    x                 = GetUnitX(which_unit)
            local real    y                 = GetUnitY(which_unit)

            //! runtextmacro unitgroup_assert_size(&quot;nearest_unit_from_unit&quot;, &quot;null&quot;)

            loop
                exitwhen i &gt;= size

                static if USE_ARRAYS_FOR_STORAGE then
                    set u = UGC[this]<i>
                else
                    set u = LoadUnitHandle(HT, this, i)
                endif

                if u != which_unit then
                
                    set ux = GetUnitX(u)
                    set uy = GetUnitY(u)
                    set dx = ux - x
                    set dy = uy - y
                    set distance = SquareRoot(dx * dx + dy * dy)

                    if curr_min_distance &gt; distance then
                        set curr_min_distance = distance
                        set nearest_unit = u
                    endif

                endif

                set i = i + 1
            endloop
                    
            set u = null

            return nearest_unit
        endmethod


        static method new takes nothing returns unitgroup
            local unitgroup ug = allocate()

            debug static if USE_ARRAYS_FOR_STORAGE then
            debug    if integer(ug) &gt; UNITGROUP_MAX_INSTANCES then
            debug        call BJDebugMsg(&quot;unitgroup error: constructor: out of unitgroups&quot;)
            debug        return unitgroup(0)
            debug    endif
            debug  endif

            set ug.size = 0

            return ug
        endmethod

        static method copy takes unitgroup which_unitgroup returns unitgroup
            local unitgroup ug = allocate()
            local integer   i  = 0

            debug static if USE_ARRAYS_FOR_STORAGE then
            debug    if integer(ug) &gt; UNITGROUP_MAX_INSTANCES then
            debug        call BJDebugMsg(&quot;unitgroup error: copy constructor: out of unitgroups&quot;)
            debug        return unitgroup(0)
            debug    endif
            debug  endif

            loop
                exitwhen i &gt;= which_unitgroup.size

                static if USE_ARRAYS_FOR_STORAGE then
                    set UGC[ug]<i> = UGC[which_unitgroup]<i>
                else
                    call SaveUnitHandle(HT, ug, i, LoadUnitHandle(HT, which_unitgroup, i))
                endif

                set i = i + 1
            endloop

            set ug.size = which_unitgroup.size

            return ug
        endmethod

        method clear takes nothing returns nothing
            set size = 0
        endmethod

        method delete takes nothing returns nothing
            call deallocate()
        endmethod

        private static method onInit takes nothing returns nothing
            static if USE_ARRAYS_FOR_STORAGE then
            else
                set HT = InitHashtable()
            endif
        endmethod

    endstruct
    
endlibrary
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
A good idea, but a linked list group will be much faster.
And someone already benchmarked custom group, it is still slower than native group.

So, there is no point to reinvent the wheel.
 

Laiev

Hey Listen!!
Reaction score
187
[ljass]library unitgroup uses optional AutoIndex, optional UnitIndexer[/ljass]

AutoIndex? Serious? You should support AIDS instead of AutoIndex.

Not everyone code in [ljass]zinc[/ljass], so you should change this:

[ljass]unit random_unit()[/ljass]

Sorry but is just bad.

[ljass].unitRandom() -> unit[/ljass]

And so for the others.
 

Laiev

Hey Listen!!
Reaction score
187
JASS:
/*~*/
        private static method onInit takes nothing returns nothing
            static if USE_ARRAYS_FOR_STORAGE then
            else
                set HT = InitHashtable()
            endif
        endmethod


Why not:

JASS:
/*~*/
        private static method onInit takes nothing returns nothing
            static if not USE_ARRAYS_FOR_STORAGE then
                set HT = InitHashtable()
            endif
        endmethod


Or better:

JASS:
/*~*/
        private module M
            private static method onInit takes nothing returns nothing
                static if not USE_ARRAYS_FOR_STORAGE then
                    set HT = InitHashtable()
                endif
            endmethod
        endmodule
        private struct S extends array
            implement M
        endstruct


?

Also you leak your function of nearest unit :)
 

tooltiperror

Super Moderator
Reaction score
231
Idea has been revisited many times. Speed gains are negligible (or nonexistent) and this has been debated ad nauseam.

Graveyarded unless a very strong rebuttal is provided to the points in the GroupTools thread.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • jonas jonas:
    where did you go?
  • The Helper The Helper:
    Jefferson TX on a Paranormal Investigation of a haunted bed and breakfast - I got some friends that are paranormal investigators and they have an RV and do YouTubes
    +1
  • The Helper The Helper:
    It was a lot of fun. The RV was bad ass
  • jonas jonas:
    That sounds like fun!
    +1
  • The Helper The Helper:
    it was a blast!
  • The Helper The Helper:
    I am going to post the Youtube of the investigation in the forums when it is ready
    +1
  • jonas jonas:
    cool!
  • vypur85 vypur85:
    Sounds cool TH.
  • tom_mai78101 tom_mai78101:
    I was on a Legend of Zelda marathon...
  • tom_mai78101 tom_mai78101:
    Am still doing it now
    +1
  • jonas jonas:
    which one(s) are you playing?
  • jonas jonas:
    I played a little bit of the switch title two weeks ago and found it quite boring
  • The Helper The Helper:
    just got back from San Antonio this weekend had the best Buffalo Chicken Cheesesteak sandwhich in Universal City, TX - place was called Yous Guys freaking awesome! Hope everyone had a fantastic weekend!
    +1
  • The Helper The Helper:
    Happy Tuesday!
  • The Helper The Helper:
    We have been getting crazy numbers reported by the forum of people online the bots are going crazy on us I think it is AI training bots going at it at least that is what it looks like to me.
  • The Helper The Helper:
    Most legit traffic is tracked on multiple Analytics and we have Cloud Flare setup to block a ton of stuff but still there is large amount of bots that seem to escape detection and show up in the user list of the forum. I have been watching this bullshit for a year and still cannot figure it out it is drving me crazy lol.
    +1
  • Ghan Ghan:
    Beep boop
    +1
  • The Helper The Helper:
    hears robot sounds while 250 bots are on the forum lol
  • The Helper The Helper:
    Happy Saturday!
    +1
  • The Helper The Helper:
    and then it was Thursday...
    +2
  • tom_mai78101 tom_mai78101:
    And then Monday
    +1
  • The Helper The Helper:
    I got the day off today!
    +1
  • tom_mai78101 tom_mai78101:
    How...? (T-T)
  • The Helper The Helper:
    I took the day off. I work for myself so I can do that.
    +1
  • Varine Varine:
    Well I'm already over summer

    The Helper Discord

    Members online

    No members online now.

    Affiliates

    Hive Workshop NUON Dome World Editor Tutorials

    Network Sponsors

    Apex Steel Pipe - Buys and sells Steel Pipe.
    Top