• 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.

[JASS] Hmmm. User Data Encapsulator... Suggestions?

Status
Not open for further replies.
Level 18
Joined
Sep 2, 2005
Messages
1,029
Alright.

What I'm trying to do is make a function to encode UserData for units and items, and the same to decode them.

Here are my basic plan outlines.
Read User Data. Convert > String
use 0 as though it were a space. Wherever there is a 0, that means the next digit is the next variable on the unit.
Then Separate them out using sub strings. - This is proving problematic because I can't find any function to detect a specific character, or get it's position in a string.
Use a math formula to compensate for everything being stored in base 9 math (0 doesn't exist) so it goes
1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,21. etc.

IS there a way for me to find the character information im looking for so I can do this?
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Lulz, I made a thingy that can check any digit value of either a unit or a item.
Thanks to BoneBreaker, took us like 30 minutes to notice that the "where" is supposed to be "where - 1" lol.

JASS:
// 'where' is the digit number
function Getdataunit takes unit u, integer where returns integer
    local integer int = S2I(SubString(I2S(GetUnitUserData(u)), where - 1, where))
    return int
endfunction
function Getdataitem takes item it, integer where returns integer
    local integer int = S2I(SubString(I2S(GetItemUserData(it)), where - 1, where))
    return int
endfunction


Example of usage in GUI
  • Actions
    • Custom script: set udg_Integer = Getdataunit( GetTriggerUnit() , 5 )
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • Integer Equal to 3
      • Then - Actions
        • Do something
      • Else - Actions

This trigger will check if the 5th digit in the triggering unit's custom value is equal to 3.
 
Level 9
Joined
Mar 25, 2005
Messages
252
If you limit all stored numbers in between 0 and 8999 and add 1000 to each value when it is stored, that stored value will be in between 1000 and 9999, in other words it will always have a length of 4 characters. This way you don't have to search for 0s in the strings, because you know that the first value starts at character 0, the second at 4, the third at 8 etc..

EDIT: Now that I think of it a bigger problem in your idea seems to be that integers can't be bigger than 2147483647 in wc3, so you can't just use S2I & I2S for conversions, unless you only need to store a few small user datas.
 
Last edited:
Level 18
Joined
Sep 2, 2005
Messages
1,029
I took Ghostwolf's Function and made it a general function to apply to integers, then made a function that uses it to count the Digits (don't know if that one works) and another one to search an integer for a specific number in any digit place, and return which place its in.
JASS:
function GetDigitAtPosition takes integer whatInt, integer where returns integer
    local integer int = S2I(SubString(I2S(whatInt), where - 1, where))
    return int
endfunction
function FindPositionOfNumber takes integer fullInt, integer searchFor returns integer
    local string intString = I2S(fullInt)
    local integer totalDigits = StringLength(intString)
    local integer i = 0
    local integer currentInt
    if (searchFor>9) then
        set searchFor = GetDigitAtPosition(searchFor, 0)
    endif
    loop
        set currentInt = GetDigitAtPosition(fullInt, i) 
        exitwhen currentInt==searchFor
        set i= i+1
        exitwhen i==totalDigits
    endloop
    if (currentInt==searchFor) then
        return i
    endif
        return -1
endfunction

We could go with using set digits, like each value has to be 4 digits, but I think the conversion system will allow us to do more. And I think instead of ignoring 0 i would be easier to 9,8,7, which would make it base 7 math, but the forumula and access functions will take care of all the complex bits of that anyways afterwards. 9 for a space, 8 for a decimal, and 7 for a negative sign.

So now we just need a formula to convert from and to base 7 math. I can do it on paper but I'm not sure how to do it with a formula...
 
Last edited:
Level 18
Joined
Sep 2, 2005
Messages
1,029
Didn't get what you'r trying to make :S

Oh and by the way, there is already a string-length native function
JASS:
native StringLength takes string s returns integer

LOL! I'm coding redundant things now. OK. My Bad. - fixed

What I'm trying to make? I want to take the existing "hold 1 int" variable, and make code to access it in such a way that it will hold a number of reals instead. The reals wouldn't have set lengths beyond not going over the max int size.
 
Level 9
Joined
Mar 25, 2005
Messages
252
Afaik those should do just what you explained.

if you follow the link "BaseConversion" you should find this function:
function BaseConversion takes string input, integer inputBase, integer outputBase returns string

That should be caled like this to convert from 10 base to 7: call BaseConversion(input, 10, 7), assuming that it works and Im not mistaken.
 
Level 18
Joined
Sep 2, 2005
Messages
1,029
JASS:
// 'where' is the digit number
function GetDigitAtPosition takes integer whatInt, integer where returns integer
    local integer int = S2I(SubString(I2S(whatInt), where - 1, where))
    return int
endfunction

function FindPositionOfNumber takes integer fullInt, integer searchFor returns integer
    local string intString = I2S(fullInt)
    local integer totalDigits = StringLength(intString)
    local integer i = 0
    local integer currentInt
    if (searchFor>9) then
        set searchFor = GetDigitAtPosition(searchFor, 0)
    endif
    loop
        set currentInt = GetDigitAtPosition(fullInt, i) 
        exitwhen currentInt==searchFor
        set i= i+1
        exitwhen i==totalDigits
    endloop
    if (currentInt==searchFor) then
        return i
    endif
        return -1
endfunction

function BaseConversion takes string input, integer inputBase, integer outputBase returns string
    local string charMap = "0123456789abcdefghijklmnopqrstuvwxyz"
    local string s
    local string result = ""
    local integer val = 0
    local integer i
    local integer p = 0
    local integer pow = 1
    local string sign = ""
    if ( inputBase < 2 or inputBase > StringLength(charMap) or outputBase < 2 or outputBase > StringLength(charMap) ) then
        // Bases are invalid or out of bounds
        return "Invalid bases given"
    endif
    if ( SubString(input, 0, 1) == "-" ) then
        set sign = "-"
        set input = SubString(input, 1, StringLength(input))
    endif
    set i = StringLength(input)
    // Get the integer value of input
    set input = StringCase(input, false)
    loop
        exitwhen i <= 0
        set s = SubString(input, i-1, i)
        set p = 0
        loop
            if ( p >= inputBase ) then
                // Input cannot match base
                return "Input does not match base!"
            endif
            if ( s == SubString(charMap, p, p+1) ) then
                set val = val + pow*p
                set pow = pow * inputBase
                exitwhen true
            endif
            set p = p + 1
        endloop
        set i = i - 1
    endloop
    loop
        set p = ModuloInteger(val, outputBase)
        set result = SubString(charMap, p, p+1) + result
        set val = val / outputBase
        exitwhen val <= 0
    endloop
    return sign + result
endfunction

// Returns -1 if find was not found anywhere
function StringFind takes string find, string subject, integer offset returns integer
    local integer len = StringLength(find)
    local integer pos = offset
    local string s
    local string str

    if ( offset < 1 ) then
        set pos = 1
    endif
    if ( find == "" ) then
        return -1
    endif

    loop
        set s = SubString(subject, pos, pos+len-1)
        if ( s == find ) then
            return pos
        endif
        if ( SubString(subject, pos, pos) == "" ) then
            return -1
        endif
        set pos = pos + 1
    endloop
    return -1
endfunction

function StringReplace takes string find, string replace, string subject returns string
    local integer pos = 1
    local integer i
    local string result = ""
    local integer len = StringLength(find)

    loop
        set i = StringFind(find, subject, pos)
        if ( i > -1 ) then
            if ( i > pos ) then
                set result = result + SubString(subject, pos, i-1) + replace
            else
                set result = result + replace 
            endif
            set pos = i + len
        else
            set result = result + SubString(subject, pos, 999999)
            return result
        endif
    endloop
    return subject
endfunction

function GetDataChunk takes integer fullInt returns real
    local integer endAt = FindPositionOfNumber(fullInt,9)
    local string workWith = SubString(I2S(fullInt), 0, endAt)
    set workWith = StringReplace("8",".",workWith)
    set workWith = StringReplace("7","-",workWith)
    set workWith = BaseConversion(workWith, 7, 10)
    return S2R(workWith)
endfunction

Current Progress. Now I just need a function to encode the data, since I can decode it. :) Does everyone at least understand what I'm trying to accomplish here now?
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
Hm how detailed are Reals? Would be very comlicated, but you could use DiscipleOfLife's idea with reals... 0,xxxxyyyyzzzz and so on.

Reals can hold less data effectively than integers, due to the overhead of floating points. You could get them to store the same, but it would be harder, and you certainly can't get any more than the 32 bits you can with ints (actually 31 bits if it is unsigned...not sure).

A more simple method would be to assign unit user data to a struct, and then use that struct.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ugh

Reading this thread is giving me a massive headache

I'm a little lost, but what your trying to do, is expand the custom value function that WE already provided, and use not just real values, but multiple values.....correct me if I'm wrong


If you wanna get multiple values just use arrays

If you want reals... :O ... Now I get what all the base changes are for....><


Perhaps it would be better to use fractions rather than decimals? Might be able to fit more data
 
Level 18
Joined
Sep 2, 2005
Messages
1,029
that's the basic Idea. instead of using 1 int, use multiple reals. and store it all in each units userdata, so I don't need to know in advance how many I need, nor do I need to track the creatures directly. whenever a creature is accessed by any script, all of his user data slots would be easily viewable.

I don't need this for a while (maybe a week or 2) but if other people are actually interested in it I could try to work on it faster.

I think it's something that might be useful for a whole bunch of things.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
As Captain Griffen said, structs are so much more convenient that this is rather wasteful.

Syntax should be fine, but it is rather early in the morning and this is unparsed, so don't be surprised if there is an error someplace. (And the local unit u = instances (ie with no value) are intentional, just saying "insert something here")

[jass=Example]struct UnitData
static method create takes unit attach returns UnitData
local UnitData dat = UnitData.allocate()
call SetUnitUserData(attach,dat)
return dat
endmethod
real exampleReal //an example something in the struct
string exampleStr //example something else
integer exampleInt //more and more... you get the idea
player examplePlyr = Player(2) //Hey look! This variable will default to teal!
//you can add more stuff here if you want
endstruct

function SomeFunctionThatIsReadingAndWritingToAUnit takes nothing returns nothing
local unit u = //someone?
local UnitData dat = GetUnitUserData(u)
set dat.exampleReal = 5.2
set dat.exampleStr = "Zomg structs r0x0r"
call BJDebugMsg(dat.exampleStr + " + " + R2S(dat.exampleReal))
//and so on
set u = null
endfunction

function ThisIsAFunctionAllUnitsAreRunThroughSomehow takes nothing returns nothing
local unit u = //current instance unit
call UnitData.create(u)
set u = null
endfunction[/code]
 
Status
Not open for further replies.
Top