• 🏆 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!

[JASS] Learning JASS. Last Question

Status
Not open for further replies.
Level 16
Joined
Mar 3, 2006
Messages
1,564
this global block defines a new variable of type filterfunc and it points to that dummy filter which returns true!

what it does is make you pick units with a proper filter insted of null which will create a leak!

Is the leak can be solved if the filterfunc isn't set to null ?

----------------------------------------------------------------------

JASS:
scope MyFirst initializer Init
 
    private function Init takes nothing returns nothing
        call BJDebugMsg( "|cff32cd32Hello World!!!|r" )
    endfunction
 
endscope

private keyword means that something is only accessible in the scope you are currently coding in.

1) accessible means it will not be executed without the keyword private ?

2) What will happen if I removed private keyword ?
 
Level 8
Joined
Aug 4, 2006
Messages
357
any function that is inside a scope can be executed within that scope, whether it is public or private. so in Dark_Dragon's example, the function "Init" will be executed at map initialization whether it has the private keyword or not. this private keyword just prevents functions outside the scope from calling the Init function.

so, this will not work:
JASS:
scope MyFirst initializer Init
 
    private function Init takes nothing returns nothing
        call BJDebugMsg( "|cff32cd32Hello World!!!|r" )
    endfunction
 
endscope

function test takes nothing returns nothing
    call MyFirst_Init()
endfunction

but this will work (since I made Init public):
JASS:
scope MyFirst initializer Init
 
    public function Init takes nothing returns nothing
        call BJDebugMsg( "|cff32cd32Hello World!!!|r" )
    endfunction
 
endscope

function test takes nothing returns nothing
    call MyFirst_Init()
endfunction

which reminds me: if you want to call a function that is inside a scope, from outside the scope, you need to do "call SCOPENAME_FUNCTIONNAME(...)"

i hope this helped, but if you want more detailed information i suggest you read the JassHelper manual: http://www.wc3c.net/vexorian/jasshelpermanual.html
 
Level 15
Joined
Jul 19, 2007
Messages
618
just as maskedpoptart said about private / public!


about that filterfunc! do not look at globals endglobals block! this block is used to declare variables and they must be null. but look at that init function i have set that Dummy_Filter to an non-leaking function! so when u call it that filter, you will call a proper filter table not null which points to nowhere!

coz if u use null it will leak an boolexpr table (well for u its enough to know how to make it not to leak ;) )

Greets!
~Dark Dragon

EDIT: Omg! ForGroup is as i said at least 2^4 times faster! jass functions are slow but loops are super slow! thats why ForGroup is using c++ coded foreach action! and there u simple have GetEnumUnit which is constant native and you do not need to remove units! since many times you do not want units to be removed!

And yet you left GetEnumUnit() dandling there.
huh? GetEnumUnit returns each unit as it is picked... so i dont understand what is wrong with it...

Eleandor is correct and he is one of best jass-ers!
ofc he knows c++ as well!
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
In JassHelper 0.9.G.0, it says:

JASS:
library A initializer InitA requires B


    function InitA takes nothing returns nothing
       call StoreInteger(B_gamecache , "a_rect" , Rect(-100.0 , 100.0 , -100.0 , 100  ) )
    endfunction

    endlibrary

    library B initializer InitB
    globals
        gamecache B_gamecache
    endglobals

    function InitB takes nothing returns nothing
        set B_gamecache=InitGameCache("B")
    endfunction

    endlibrary

I saved the map and looked at the script and it has the following:

JASS:
globals
//globals from B:
        gamecache B_gamecache
//endglobals from B

//library B:
    
    function InitB takes nothing returns nothing
        set B_gamecache = InitGameCache("B")
    endfunction

//library B ends
//library A:
    function InitA takes nothing returns nothing
        call StoreInteger(B_gamecache , "a_rect" , Rect(- 100.0 , 100.0 , - 100.0 , 100))
    endfunction

//library A ends

And when I removed the initializer keyword I got the same script, now I have to ask what is the function of the initializer keyword if with or w/o it the script is all the same ?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
You didn't get the precise same script.

The function specified after the "initializer" keyword will automatically run when you start a new game in warcraft.

In the mapscript, you must scroll down to the "main" function (it can actually be called differently, I don't remember) and you'll see that it looks like this:

JASS:
function main takes nothing returns nothing
...
    call InitA()
    call InitB()
...
endfunction

If you remove the initializers from the library, the main function will no longer call InitA and initB, and thus your libraries will not be initialized when you start the map.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Now things are becoming a little understandable may with a little bit more training one can fully understand ... oh but where are my manners; THANKS ALOT :wink:

-----------------------------------------------------------------------
Another Topic:

How to use library_once and more imortantly why? why would I want to declare library twice if I know that it will ignore the second declaration ?
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
EDIT: Omg! ForGroup is as i said at least 2^4 times faster! jass functions are slow but loops are super slow! thats why ForGroup is using c++ coded foreach action! and there u simple have GetEnumUnit which is constant native and you do not need to remove units! since many times you do not want units to be removed!

2^4? Want to show some evidence?
Anyway, I find it hard to understand how you know that ForGroup() uses a C++ for loop, and knowing C++ has nothing to do with this.
As to GetEnumUnit(), since when do pointers not leak?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I think it's common sense that ForGroup(), since it's a native function, doesn't create a new group and then removes every unit in the group until the group is empty, then deallocates the temporary group. I mean, blizzard must have seriously fucked up if their natives are slower than a loop controlled by a slow-ass virtual machine.

Regardless of that, ForGroup indeed is faster, benchmarks have shown so before. The only good reason why one would prefer a FirstOfGroup loop is the ability to use local variables (you can't pass arguments to ForGroup) or the usage of TSA() which should be avoided anyway.

As to GetEnumUnit(), since when do pointers not leak?
Since when do pointers leak? Only the pointee (if that's a word) potentially leaks. What do you suggest? call RemoveUnit(GetEnumUnit()) ? That removes the unit from the game, and I think that wouldn't be a good idea.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
You don't need to store GetEnumUnit() in a local variable, especially if you only use it once.

The only reason why you need to null local variables is because of the broken reference bug, which actually only occurs on local variables, and does not occur on parameters & function arguments. Therefor, you're only making things more complicated by assigning a local variable any having to null it.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
library_once does work. However, TESH, the program that highlights vjass keywords such as library and library_once does not work perfectly, and it seems that library_once was forgotten by the TESH developers. But it does work if you save the map.

library_once is hardly used. The feature of library_once is that multiple libraries are allowed to have the same name. When 2 libraries with the same name are detected, the 2nd library is simply ignored.

If you only use library, then 2 libraries with the same name will cause a syntax error because that's not allowed.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
You can declare and give values to a global without initializers, you just create a globals block and you set it to something, like this:

JASS:
globals
    integer Int = 12
endglobals

But if you need to set it to another value, for example a function, you need to use an initalizer (if you want it to be set on map init):

JASS:
library Bla initializer SetInt
globals
    integer Int
endglobals

function SetInt takes nothing returns nothing
    local unit u = ...
    set Int = GetUnitUserData(u)
endfunction
endlibrary
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
1) When declaring globals in a library must I use the initializer keyword to make sure that they will run at the top of the script ?

The initializer is there to make a certain function specified within the library automatically execute when the map loads.
Globals have nothing to do with this.

2) Can initializer keyword be used in scopes ?
Yes, it's purpose is the same: making sure a certain function specified within the scope is automatically executed when the map loads.

To give an example: you could have a scope containing the code of a scripted spell. The initializer of the spell would create the required triggers, as well as preload the ability data. The initializer is also often used to initialize globals that can't otherwise be initialized.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
The initializer is also often used to initialize globals that can't otherwise be initialized.

Like what, Array variables is an example for that ?

<<ADDED>>

I don't understand this from JassHelperManual
Note: If you use public on a function called InitTrig, it is handled in an special way, instead of becoming ScopeName_InitTrig it will become InitTrig_ScopeName, so you could have an scope/library in a trigger with the same scope name and use this public function instead of manually making InitTrig_Correctname.
 
Last edited:
Level 21
Joined
Aug 21, 2005
Messages
3,699
Like what, Array variables is an example for that ?

Globals can often not be initialized by functions. For example:
JASS:
globals
    boolexpr b = Filter(function True)
endglobals
When the game starts, b will be null and will NOT be initialized correctly, even though you wrote b = Filter(function True). You must add this in an initializer function.

So globals with or w/o inititializer will move to the top of the script ?
Globals can be declared anywhere and are not limited to libraries or scopes. And yes, globals are all merged to the top of the script.

I don't understand this from JassHelperManual
If you convert a trigger to jass script, you'll probably notice function InitTrig_TriggerName takes nothing returns nothing. This function is automatically generated for each specific trigger and acts exactly the way as a library or scope initializer: the function runs when the map loads. This function usually adds the events, conditions and actions to the trigger.
Now what jasshelper manual is saying is that if you are using scopes and you add "public" in front of this function, it becomes public function InitTrig_TriggerName.
Normally, all public functions in scopes are modified by adding the scope identifier in front of them. For example:
JASS:
scope Blah

public function Blah ...
endfunction

endscope

// becomes

function Blah_Blah ...
endfunction

However, this means that InitTrig_TriggerName is no longer considered a trigger initialization part, because it becomes Blah_InitTrig_TriggerName (and doesn't start with "InitTrig_")
Yet, jasshelper detects this problem and solves it by adding "Blah" behind the "InitTrig", so warcraft will detect that function to be an initializer.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
I need some help with that example:

JASS:
library nestedtest
        scope A
          globals
            private integer N=4
          endglobals
 
          public function display takes nothing returns nothing
            call BJDebugMsg(I2S(N))
          endfunction
        endscope
 
        scope B
            globals
                public integer N=5
            endglobals
 
            public function display takes nothing returns nothing
                call BJDebugMsg(I2S(N))
            endfunction
        endscope
 
        function nestedDoTest takes nothing returns nothing
            call B_display()
            call A_display()
        endfunction
endlibrary
 
    public function outside takes nothing returns nothing
        set nestedtest_B_N= -4
        call nestedDoTest()
        call nestedtest_A_display()
 
    endfunction

Is what I am understanding is right:

1) At scope A inside the globals block, N is a private. Now when setting that variable we need to write nestedtest_A_N = VALUE

2) At scope A, the function diplay() is a public. So outside the scope but inside the library must I call it by A_display() or simply display()
__________________

What is the function of ExecuteFunc or in other word what is the difference between

JASS:
call ExecuteFunc("FUNCTIONNAME")
and
JASS:
call FUNCTIONNAME()
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
1) At scope A inside the globals block, N is a private. Now when setting that variable we need to write nestedtest_A_N = VALUE
Nope. Since it's a private global, it can only be read or modified inside the scope (and can't be reached from outside the scope). And while you're inside the scope, you can just write N = VALUE.

2) At scope A, the function diplay() is a public. So outside the scope but inside the library must I call it by A_display() or simply display()
A_display() will work for sure. I doubt display() will work.
But this kind of stuff you can test yourself too...

What is the function of ExecuteFunc or in other word what is the difference between...
ExecuteFunc allows you to run functions that have not been defined yet at the time of executing it. For example:
JASS:
function A takes nothing returns nothing
    call C() // not allowed since C hasn't been found yet
endfunction

function B takes nothing returns nothing
    call ExecuteFunc("C") // This is allowed
endfunction

function C takes nothing returns nothing
    call DoNothing()
endfunction

function D takes nothing returns nothing
    call C() // this is allowed since C is already defined
endfunction

function Recursive takes nothing returns nothing
    call Recursive() // not allowed
endfunction

function RecursiveGood takes nothing returns nothing
    call ExecuteFunc("RecursiveGood") // allowed
endfunction

There are some problems though: functions executed by ExecuteFunc are not allowed to take parameters nor return anything.
Another problem is that TriggerSleepAction(real) is not allowed in functions that are executed through ExecuteFunc.
 
Level 15
Joined
Jul 19, 2007
Messages
618
2^4? Want to show some evidence?
Anyway, I find it hard to understand how you know that ForGroup() uses a C++ for loop, and knowing C++ has nothing to do with this.
As to GetEnumUnit(), since when do pointers not leak?

pointers? lol! you dont even know what needs to be nulled and why? pointer, the only type which is direct pointer in memory is real, in game its an long integer which is address of float in memory. unit is not a pointer mate! it is struct in VM and class of type unit in c++. k now i know i wasted my time...

however Eleandor ty for explaining things to him +rep!

ofc GhostWolf dont take me wrong i was maybe to impolite, its just that i talk like that with people who know how everything is handled but are wrong! since now i understand that u are not one of them! then you have my apologies.

Greets!
~Dark Dragon
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Let me also note that using ExecuteFunc is discouraged nowadays in the vjass era. If you need to do something similar to this, use:
MyFunction.execute(parameters) or
MyFunction.evaluate(parameters).

They are considered to be better because:
1) It doesn't allow you to execute an inexistant function
e.g. ExecuteFunc("this doesn't exist") is allowed, but causes the game to crash
this doesn't exist.execute() will cause a compile error and is not allowed.
2) both execute and evaluate allow parameters to be passed to the function (ExecuteFunc requires a function that takes nothing returns nothing)
3) .evaluate is slower but also allows TriggerSleepAction to be used.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
JASS:
struct pair
    integer x
    integer y
endstruct

function testpairs takes nothing returns nothing
 local pair A=pair.create()
    set A.x=5
    set A.x=8

    call BJDebugMsg(I2S(A.x)+" : "+I2S(A.y))

    call pair.destroy(A)

endfunction

1) What do struct do ?

2) Is the struct name is pair or A ?

3) I don't understand this line
JASS:
local pair A=pair.create()
 
Level 15
Joined
Jul 19, 2007
Messages
618
The other way round, .execute is slower but allows TSA to be used.

And yes, .evaluate and .execute are vJass features.

yes but its important to say that .execute does not cause current trigger to wait for example:

JASS:
function somefunc takes nothing returns nothing
    call TriggerSleepAction(2.0)
endfunction

call somefunc.execute()

now current trigger will not sleep while if .execute was not called it will wait in the trigger...

and until Deaod told about .evaluate and .execute that u swap them :D
i thought wtf i was wrong? coz i was 100% sure that .evaluate is faster and cant use sleeps! but now i get it that Eleandor replaced them :D so now its all clear!

JASS:
struct pair
    integer x
    integer y
endstruct

function testpairs takes nothing returns nothing
 local pair A=pair.create()
    set A.x=5
    set A.x=8

    call BJDebugMsg(I2S(A.x)+" : "+I2S(A.y))

    call pair.destroy(A)

endfunction

1) What do struct do ?

2) Is the struct name is pair or A ?

3) I don't understand this line
JASS:
local pair A=pair.create()

structs are used to declare an new type / object in vjass!
that line pair.create() allocates an memory for this two integers x and y
and then as u can see u access members by writing var_name.member
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
A struct defines a new datatype. Normally you're limitted to the datatypes such as integer, real, boolean, string, unit etc.
structs allow you to define new datatypes composed of the already known datatypes.

just like you write down
local integer A = 5
local unit U = CreateUnit(...)

you can write down
local pair P = pair.create()
call P.destroy()

Think of a "unit" variable. A unit basically is nothing more than a variable that encapsulates a real for hit points, a real for X coordinate, a real for Y coordinate, a string for name, etcetera.
Similarly, structs are new variable types defined by you. A struct is comparable to an array, except that an array requires your variables to be of the same type. Structs allow mixed types.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
The result variable is a type with 2 integers, not one integer.

It's the same way a location variable works: it's just 2 real variables, one for the X coordinate and one for the Y coordinate.

Structs are probably the most wanted feature in vJass simply because it allows you to create new types with mixed contents. For example:
JASS:
struct CharmData
    unit u
    player p
endstruct
This links a unit with a player. In this specific example the idea is to create a temporary Charm spell, where a unit becomes charmed (changes player) for 30 seconds. After those 30 seconds it would have to become owned by the previous player again. Thus, we need to store the previous owner somewhere.

The spell would look like:
JASS:
struct CharmData
    unit u
    player p
endstruct

function CharmEnd takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local CharmData d = GetTimerData(t) // Retrieve the attached data to the timer
    call SetUnitOwner(d.u, d.p, true) // Change owner back into original owner
    call ReleaseTimer(t) // Destroy the timer
    call d.destroy() // Destroy the CharmData
endfunction

function CharmStart takes unit u, player p returns nothing
    // This uses TimerUtils
    local CharmData d = CharmData.create() // create new CharmData
    local timer t = NewTimer() // If you use TimerUtils, this is the alternative to CreateTimer()
    set d.u = u
    set d.p = GetOwningPlayer(u)
    call SetUnitOwner(u, p, true)
    call SetTimerData(t, d) // Attach the charmdata to the timer
    call TimerStart(t, 30.0, false, function CharmEnd) // Start the timer, to elapse in 30 seconds
endfunction

// When the spell is cast:
call CharmStart(GetSpellTargetUnit(), GetOwningPlayer(GetTriggerUnit()))
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
OK, this is what I understand:

When you say
JASS:
struct CharmData
     unit u
     player p
endstruct

CharmData is now the new type variable not the variable itself; the variable is d of type CharmData.

And if you need to change that variable d you need to change its components since it no longer a single-value variable.

But in the line
JASS:
local CharmData d = GetTimerData(t) // Retrieve the attached data to the timer
I don't understand how could I set d with this function, isn't the d suposed to store data of unit and player ?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
CharmData is not the variable but variable type or like a variable type, d is the variable of type CharmData, well that's how I understand it.
Yup, that's basically it.

The GetTimerData(t) was just an example using TimerUtils. With the TimerUtils vJass system made by Vexorian you can attach a value to a timer. In this example, I have attacked the CharmData variable to the timer but I could have also just attached a meaningless integer.
 
Level 3
Joined
Aug 9, 2008
Messages
60
See it as this, lets take charm data as an example... Each struct you create, the struct index gains a number, what that index is, is a spot in two arrays, one global player array, and one global unit array. The reason you can attach structs to units, is because all you assign them is the number of the arrays to use, you don't create new types of variables.
 
Status
Not open for further replies.
Top