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

Hide unit for only one player?

Status
Not open for further replies.
Level 14
Joined
Aug 8, 2010
Messages
1,022
Hello! I wanna know if i can hide a unit for one player, but unhide it for others. For now, i made only this, but it doesn't work, it only hides the unit for all players...
  • Trigger
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Player Group - Add Player 1 (Red) to group
      • Player Group - Pick every player in (All players) and do (Actions)
        • Loop - Actions
          • Custom script: if IsPlayerInForce(GetLocalPlayer(),udg_group) then
          • Unit - Hide Raider 0003 <gen>
          • Custom script: else
          • Unit - Unhide Raider 0003 <gen>
          • Custom script: endif
Is it even possible?
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
This is to hide a unit from Player 1, but reveal it to other Players (2 ~ 12)
  • Actions
    • Custom script: if GetLocalPlayer() == Player(0) then
    • Unit - Hide Blood Mage 0000 <gen>
    • Custom script: endif
Remember, Player(0) in JASS is Player 1 in GUI.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
This is to hide a unit from Player 1, but reveal it to other Players (2 ~ 12)
  • Actions
    • Custom script: if GetLocalPlayer() == Player(0) then
    • Unit - Hide Blood Mage 0000 <gen>
    • Custom script: endif
Remember, Player(0) in JASS is Player 1 in GUI.

the heroes wouldn't even have to attack or do anything, using ShowUnit in a local block will create a different pathing map for different players, so only crossing them would cause desync.
http://www.hiveworkshop.com/forums/triggers-scripts-269/showing-hiding-unit-specific-player-220716/
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Try this;
  • Melee Initialization
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Set PlayerGroup = (All players matching (((Matching player) is an ally of (Triggering player)) Equal to True))
      • Player Group - Pick every player in PlayerGroup and do (Actions)
        • Loop - Actions
          • Custom script: if GetLocalPlayer() == GetEnumPlayer() then
          • Unit - Hide Blood Mage 0000 <gen>
          • Custom script: endif
      • Custom script: call DestroyForce(udg_PlayerGroup)
This will hide the unit for all ally of Triggering player (including the player himself)

But first, we need to know what does exactly the unit do ?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Try this;
  • Melee Initialization
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Set PlayerGroup = (All players matching (((Matching player) is an ally of (Triggering player)) Equal to True))
      • Player Group - Pick every player in PlayerGroup and do (Actions)
        • Loop - Actions
          • Custom script: if GetLocalPlayer() == GetEnumPlayer() then
          • Unit - Hide Blood Mage 0000 <gen>
          • Custom script: endif
      • Custom script: call DestroyForce(udg_PlayerGroup)
This will hide the unit for all ally of Triggering player (including the player himself)

But first, we need to know what does exactly the unit do ?

Read the post above your first one, and follow the link, it is likely to desync.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
But first, we need to know what does exactly the unit do ?
I'll explain. There is a quest in my map. It's about collecting human heads. When the player collects some heads and goes to the quest giver, a unit "Head on spear" appears. I want this unit to be visible only for the player who bring the heads. The quest will be MPI, each player will do it for his own.

The unit will act only as a decoration.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
JASS:
native GroupEnumUnitsOfType                 takes group whichGroup, string unitname, boolexpr filter returns nothing
native GroupEnumUnitsOfPlayer               takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
native GroupEnumUnitsOfTypeCounted          takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRect                 takes group whichGroup, rect r, boolexpr filter returns nothing
native GroupEnumUnitsInRectCounted          takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRange                takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeOfLoc           takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeCounted         takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRangeOfLocCounted    takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsSelected               takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
not every of those works but what it does is that it takes all the units and puts them to unit group, something like GUI's pick every unit in Group and do actions but that is a little bit different thing
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
This is to hide a unit from Player 1, but reveal it to other Players (2 ~ 12)
  • Actions
    • Custom script: if GetLocalPlayer() == Player(0) then
    • Unit - Hide Blood Mage 0000 <gen>
    • Custom script: endif
Remember, Player(0) in JASS is Player 1 in GUI.
Guess i will do this but with different integer, just as Drunken_Jackal said. I don't know Jass a lot, most of the scripts are copied. I don't know what are those desyncs and most of the functions in general... I understand less that 60% of what you mean in your posts, guys. I try hard to see what happens. :sad: I really appreciate the help you are giving me but i simply can't understand well. Guess it will take me 2 years to learn Jass as good as GUI... Not everyone can know both Jass and GUI.

EDIT : A new solution came in my mind. I will simply hide the unit for all players at map initialization and then unhide it only for the triggering player, without groups. This means that defskull's script is perfect.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Better do my method, set variable outside and inside GetLocalPlayer block.
Then, create the handle (unit) for all Players, that will surely won't cause desync as it creates handle for all Players, but only selected Players get to see the set variable.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
CoLd Bon3 dont worry, you will learn Jass sooner then you thing :D
Ive learned from GUI to Jass in like 2 weeks :)
Desync is event when not every handle(everything expect integer, real, boolean, string, code(you dont need to know this in GUI)) is the same for every player and so if the handle comes to contact with something that is in different state it will automatically kick player from game(dont know if owner of the handle or the one that comes to contact to it :D) with no warn message or anything.
Good example is
JASS:
if GetLocalPlayer() == Player(0) then
    call CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 270)
endif
Creates a unit which only Red players computer knows about, if the unit attacks blues player unit the player red will have information of the unit attacking but the player blue will have no idea what is happening as he dont know there is any unit supposed to attack him.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
CoLd Bon3 dont worry, you will learn Jass sooner then you thing :D
Ive learned from GUI to Jass in like 2 weeks :)
Desync is event when not every handle(everything expect integer, real, boolean, string, code(you dont need to know this in GUI)) is the same for every player and so if the handle comes to contact with something that is in different state it will automatically kick player from game(dont know if owner of the handle or the one that comes to contact to it :D) with no warn message or anything.
Good example is
JASS:
if GetLocalPlayer() == Player(0) then
    call CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 270)
endif
Creates a unit which only Red players computer knows about, if the unit attacks blues player unit the player red will have information of the unit attacking but the player blue will have no idea what is happening as he dont know there is any unit supposed to attack him.
Aaaah, i see. Yesterday i had a desync then... i wandered what happened. Thanks. It's something like the endless trigger, when for example the trigger runs when a hero acquires an item and then this same trigger adds an item to the hero (the trigger runs again and again because the action in it causes the event). So this infinite loop causes the game crash and is something like a desync, right?

So i can use defskull's code because those units are shown only to some players, yes, but they only stand there as a decoration. They can't move, attack, cast, they can't do anything, they can't desync.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Desync and game crash is 2 different things >.>"
Desync will cause a game to crash, while game crash is... a phenomenon.

Desync is when you're creating a handle for you, but not for others (desync = server split).
What is on your screen is not on your friend's screen because you create separate handle for you and not for your friend(s).

This will create a split server (the game now handles 2 server, 1 with units created 1 with no units created)

When this unit (Server A) interact with another unit (Server B), this would cause a desync.

By means of interact can be anything such as Attack, Cast spell to the unit, etc.

On the other hand, "infinite loop" is not desync-case.

It is the user's fault for creating such code.

Let's say you have starting integer value 1.
And you will enter a loop and this loop will end at integer value 10.

If you do this;
i = i - 1

How can the value will reach 10 if it keeps decreasing ?
It should be;
i = i + 1

This is what we call infinite loop.

Or an action stacks to one another, such as if you an Event that when unit takes damage, damage the unit.
You see where this is going ?

When the Event fires (from taking damage), the Event's action is to damage the unit (so it will damage the unit and when unit is damaged, it runs the Event again because the Event is "any unit takes damage" and this will cause infinite loop)
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
eventually the i will get to 10, when it reaches -2147483648(I think thats the number but no calc so may be wrong) it will get next value as 2147483647 and go lower
Im not sure but I think that if loop loops too many times it will crash the thread because one thread can do only limited amount of "calls"
I tried to loop 100000 times onInit and it stopped :D

if one player is desynced it is as well fault of coder, he has to ensure that wont happen
 
The problem with hiding a unit for a local player is not in the way you do it - regardless of the method, the unhidden unit will be able to move, fight, and recieve orders, while the hidden one will not. Other units will also be able to target the unhidde unit aswell as collide with it, and theese things are guaranteed to result in a server split.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Just as he said, that unit is for decorations only, meaning that it's fine if the unit doesn't get Attack/Move/Controlled.

To remove Attack from the unit;
Combat - Attacks Enabled: None

To remove Move from the unit;
Movement - Speed Base: 0

To remove control-able from the unit;
Add "Locust" ability to the unit

Now it's done, the unit won't be able to interact with other units if we disable these 3 attributes.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Sure, but again you have other things to care, for example some GroupEnum functions could enum the visible unit, and it won't be if it's hidden.
I have never tested if open a new thread in a local block desync or not, but it's very possible.

You could go for the hide solution, but it really requires to know exactly what it involves, and it's not the case here, i mean CoLd Bon3 is not enough knowledgable, so here i would just go for the safest solution if it's possible ofc.

EDIT :

And btw if it's only a "decoration" why not just use an effect ?
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
If you're so scared about desync (split server - caused by creation of handle for Player A but not for Player B), well use the method I mentioned for quite few times on this forum.

  • Actions
    • Set UnitType = No unit-type
    • Custom script: if GetLocalPlayer() == GetTriggerPlayer() then
    • Set UnitType = Decoration
    • Custom script: endif
    • Unit - Create 1 UnitType for (Triggering player) at TempLoc facing Default building facing degrees
Make it a loop of 12 times, each unit is set by Unit[Array], for example Unit[1] is for Player 1.

When the event comes, just do this;
  • Unit - Unhide Unit[(Player number of (Triggering player))]
 
And btw if it's only a "decoration" why not just use an effect ?

This.

And consider the fact that built-in mechanics such as aquisition range might work through a process similar to that of the GroupEnum functions, where hidden units are ignored. Even if the unit is invulnerable it might still be brought up in the aquisition evaluation for some players. Those things may be enough to cause a desync. Even if i should be wrong on this, i can still think of lots of cases where it would make a difference.

EDIT: defskull, i hope you realize that code of yours is guaranteed to desync. You are still stuck with creating a unit for some players but not for others. When the unit is created, an id is allocated for it. If it is not created for some players, this id will still be free and some other unit will recieve it. This is not the same as with effects.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Effect as in, Special Effects ?

Well the reason he made it Unit is because it wants the "Unit Model" to not play its death animation if the SFX is destroyed ?

Using Units as SFX will cause it to play death animation when it is destroyed, whereas he wants the unit to get hidden AFTER THAT, kills the unit (you won't see the death animation).

There's too much possibilities here.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Again, again and again you don't need to create or destroy an handle in a local block to make a desync.
There are other cases.
I'm not afraid of anything here, just trying to give the best solution according to the user.

But if it's enough just use an effect, that's the simplest and the best solution.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
But if it's enough just use an effect, that's the simplest and the best solution.
Yeah if and only if, the SFX does not has "death" animation, would look weird to see SFX playing death animation (unit's death animation).

What unit (model) are you using to represent the decoration anyway ?
Would like to know this.

But I guess SFX is the best solution by far.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
The model is called "Head on Spear <Base>" it has no animations and i think that using it as an effect, instead of a unit, will not cause a desync because effects can not interact with the other server, right? It's only a visual effect. I have already created special effects for some players only and i had no issues so far.

Btw, is "local player" = "one of all the players"?
 
You cannot compare local variables with local players.

A local variable is just a temporary variable local to the function it exists within. When the function ends, so does the variable (although some needs to be nulled).

Local player would rather refer to the client of a certain player, so

JASS:
if GetLocalPlayer() == Player(0) then ...

would mean that if this computer (which is running the game) is the computer of player 1, then it will execute whatever code is in the if statement. Now, one thing which is important to realize in game programming, is that you are never playing together in the same game. Your computer is only sending away the most relevant information about where units are positioned in your game, and the server registers it and sends back information to all the other players so that their client can mimic your game. The system is completely dependant on the information in all clients being the same, otherwise it derails.
Special effects, and other visual things are kinds of information that the game does not find important enough to synchronize.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
local variable and global variable works for any players
the difference is, global variables can be used in any function, in any trigger
local variables on the other hand can only work within the function they are in.
Example:
JASS:
//this is vJass addition to the trigger editor, if you dont have JNGP you cant do this
globals
    unit u = null
endglobals

function AA takes nothing returns nothing
    set u = gg_unit_Hmkg_0001 // mountain king, only works if he is first unit placed on the map
endfunction

function AB takes nothing returns nothing
    call KillUnit(u)
endfunction
will work properly. However doing
JASS:
function AA takes nothing returns nothing
    set locint = 1
endfunction

function AB takes nothing returns nothing
    local integer locint = 0
endfunction
will pop up error, undeclared variable locint
Basically you can only use locals within that instance but they are far more used then globals because if you do this
JASS:
globals
    integer int = 0
endglobals

function AA takes nothing returns nothing
    set int = int + 1
    call BJDebugMsg(I2S(int))
    call TriggerSleepAction(1.0) //Wait 1.00 seconds in GUI
    set int = int + 1
    call BJDebugMsg(I2S(int))
endfunction

//the below INITa is just to make this work

function INITa takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 0.5, true)
    call TriggerAddAction(t, function AA)
    set t = null
endfunction
what this does is on init it creates Timer - Every 0.5 seconds and registers it to the function and that function runs every 0.5 seconds(hope you understand so far)
now what this does, is set the integer to +1 every time it runs and additionally after 1 second. But this is not MUI, thats why you need in GUI unit indexing to make spells MUI.
On the other hand, locals are not only within the function but is like array, you can have how many globals with same name working at the same time, they are bound to the thread meaning that when you run it it initializes those values and then takes values of current thread
The example above will display 1, 2, 3, 4, 5, 6, 7... or something but what if you want to end on 2 everytime. You do
JASS:
function AA takes nothing returns nothing
    local integer i = 0
    set i = i+1
    call BJDebugMsg(I2S(i))
    call TriggerSleepAction(1.0)
    set i = i+1
    call BJDebugMsg(I2S(i))
endfunction

//and the second function or anything else
this will however display 1, 2, 1, 2, 1, 2, 1, 2, or something like that
However remember that if you have global with name i(if you do it trough the Variable Editor it will automatically have prefix udg_variableName) and you have local with i then if you do set i = i + 1 you will work with the local not global
Hope you understand, if not let me know Ill try to describe it slower :D
 
Status
Not open for further replies.
Top