• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

My map crashes - ChatBoard System

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
- Error message: "Unable to allocate id for an object of type: MsgBoard__ChatString
- This happens after around 60 Entries.
- At 70-80 Entries the map crash.


JASS:
library MsgBoard 
    
    globals
        private constant integer CAPACITY               = 50    // from 0 to (CAPACITY - 1)
        private constant integer BOARD_ROWS             = 26    // 26       // This should probably be defined inside the Board Struct   
        private constant real    BOARD_WIDTH            = 30.
        private constant integer BREAK_LENGTH           = R2I(BOARD_WIDTH*2.55) 
        private constant integer LAST_ROW               = -1
    endglobals

    struct CircularBuffer
        private string array s[CAPACITY]
        private integer head = 0
        private integer tail = -1
        readonly integer size = 0
        
        static method create takes nothing returns CircularBuffer
            return .allocate()
        endmethod
        
        method add takes string str returns nothing
            set .tail = .tail + 1
            if .size == CAPACITY then
                set .head = .head + 1
            else
                set .size = .size + 1
            endif
            if .head == CAPACITY then
                set .head = 0
            endif
            if .tail == CAPACITY then
                set .tail = 0
            endif
            set .s[.tail] = str
        endmethod
        
        method getString takes integer index returns string
            local integer a = .head + index
            if a < CAPACITY then
                return .s[a]
            elseif index < CAPACITY then
                return .s[a - CAPACITY]
            endif
            return ""
        endmethod
    endstruct
    
    private struct ChatString
        string array word[60]
        string array line[BOARD_ROWS]
        integer n = 0
        
        static method create takes string s returns ChatString
            local thistype this = .allocate()
            local integer i = 0
            local integer j = 0
            local integer sLength = StringLength(s)
            local string char = ""
            set sLength = StringLength(s) 
            loop
                exitwhen i > sLength
                set char = SubString(s, i, i + 1)
                if char != " "  then 
                    set word[j] = word[j] + char
                else
                    set line[n] = line[n] + word[j] + " "
                    set j = j + 1
                endif
                set i = i + 1
                if i == BREAK_LENGTH*(1 + this.n) then
                    set this.n = this.n + 1
                endif
            endloop
            set line[n] = line[n] + word[j]
            return this
        endmethod
    endstruct
    
    struct MsgBoard
        private multiboard mb
        private CircularBuffer cb
        private player p
        private integer displacement = 0
    
        method show takes boolean revealed returns nothing
            if GetLocalPlayer() == .p then
                call MultiboardDisplay(.mb, revealed)
            endif
        endmethod
        
        static method create takes player p returns thistype
            local thistype this = .allocate()
            set this.cb = CircularBuffer.create()
            set this.p = p
            set this.mb = CreateMultiboard()
            call MultiboardSetRowCount(this.mb, BOARD_ROWS)
            call MultiboardSetColumnCount(this.mb, 1)
            call MultiboardSetTitleText(this.mb, User.nameColored[GetPlayerId(p)] + "'s Message Board") // Change this line
            call this.show(true)
            // This needs to be addressed
            call MultiboardSetItemStyleBJ(this.mb, 0, 0, true, false)
            call MultiboardSetItemWidthBJ(this.mb, 0, 0, BOARD_WIDTH)
            return this
        endmethod
        
        // cb.getString(cb.size - 1) - 1 Gets the last possible String row from the CircularBuffer
        // cb.getString(0)           - Returns the first stored row, still saved.
        
        method update takes nothing returns nothing 
            local integer last = cb.size - 1 - .displacement
            local integer curLast =  last - .displacement
            local integer i = last
            local integer j = BOARD_ROWS
            local integer k = i - j 
            if k < 0 then
                set k = 0
            endif
            loop
                exitwhen j == 0
                if i >= 0 then
                    // This needs to be addressed.
                    //call MultiboardSetItemValueBJ(.mb, 1, j, I2S(i + 1) + " - " + cb.getString(i))
                    call MultiboardSetItemValueBJ(.mb, 1, j, I2S(i + 1) + " - " + cb.getString(i))
                else 
                    call MultiboardSetItemValueBJ(.mb, 1, j,"")
                endif
                    if i < 0 then
                        set i = 0
                    endif
                set j = j - 1
                set i = i - 1
            endloop
             call MultiboardSetTitleText(this.mb, User.nameColored[GetPlayerId(p)] + "'s Message Board   -   Displacement: " + I2S(.displacement))
        endmethod
        
        method addString takes string s returns nothing
            local ChatString cs = ChatString.create(s)
            local integer i = 0
            loop
                exitwhen cs.line[i] == null
                call cb.add(cs.line[i])
                set i = i + 1
            endloop
            //call cs.destroy()
        endmethod
        
        method getDisplacement takes nothing returns integer 
            return .displacement
        endmethod
        
        method addDisplacement takes integer amount returns nothing
            set .displacement = .displacement + amount
            if .displacement < 0 or cb.size <= BOARD_ROWS then 
                set .displacement = 0
            elseif  (.displacement + BOARD_ROWS) > cb.size then
                set .displacement = cb.size - BOARD_ROWS
            elseif .displacement > (cb.size - 1)  then
                set .displacement = cb.size
            endif
        endmethod
    endstruct
endlibrary
 
Last edited:
That error message was given in-game, right? (probably through jasshelper if you have debug mode enabled)

Judging by it, I assume that you're running out of space. In the .create() methods of each class, add a BJDebugMsg to display the current number of instances that were made (make one counter for CircularBuffer and one counter for ChatString). Report back with the results.

Behind the scenes, structs are just arrays. Warcraft 3 has an array index limit of 8192, thus structs are limited to having 8192 instances. However, things become a bit complicated when you have array struct members (such as 'capacity' or 'word' in your case). 2-dimensional arrays don't exist in JASS, so Vexorian decided to have the struct's space partitioned to support arrays. Because of that, it requires you to specify a maximum index so that it can partition things correctly.

Note that these arrays aren't monitored perfectly. If you accidentally access something at the index 72 even though your array only supports 60 indices, you'll be infringing upon your other instances' data and weird things can happen. It won't give you an error, but you'll probably get a bunch of bugs. So make sure you add debug messages to make sure you're not accidentally accessing weird indices of your struct arrays.

Back to the array shpiel. Since the struct is partitioned, you actually only have (8192/biggest-struct-member-array-size) instances available to you. For ChatString, your biggest index is 60. Therefore, you have 8192/60 = 136 instances available to you. That still shouldn't cause issues in your case, but it is something to be aware of. But who knows? Sometimes you'll accidentally make more instances than you expected, so this could be the issue.
 
Status
Not open for further replies.
Top