Spring.SelectUnitMap, Spring.SelectUnitArray
Moderator: Moderators
Spring.SelectUnitMap, Spring.SelectUnitArray
In regards to synced LuaRules... not being able to select a Unit in Sync is a pain. There are a lot of situations where you want to replace / destroy Units, I've been finding, and it's annoying if you lose the selection during that transition, and writing code to get around that just leads to more waste. Just a UI issue, mind ye, but it's one that affects final polish, imo.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
1. It makes no sense to select things in synced.
2. It's a couple lines to do it in unsynced.
2. It's a couple lines to do it in unsynced.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
We check for commands issued there, seems silly to not be able to check for a Selected state there, too, imo.
And it's not a two-liner, because I need to send an event to unsync from sync- an event that occurs in sync causes this to need to happen.
Therefore, I found I needed to send, then clear, an array. Sending over a single UnitID is not really a good way to do this, given that more than one such event may (possibly) be happening that frame.
And, if you don't clear it after executing, then it stays selected, forever
That's a lot of extra bother and very inefficient, to boot, sending an array to unsync, unpacking it, then using it in DrawWorld or whatever, imo. Moreover, it requires a constant IF/THEN running in DrawWorld. Is there a way for Sync to just call a Function on the Unsync side, instead? That'd save a lot of the waste.
If I'm just doing it wrong, meh, let me know. This works, but it feels very... clunky.
And it's not a two-liner, because I need to send an event to unsync from sync- an event that occurs in sync causes this to need to happen.
Therefore, I found I needed to send, then clear, an array. Sending over a single UnitID is not really a good way to do this, given that more than one such event may (possibly) be happening that frame.
And, if you don't clear it after executing, then it stays selected, forever

If I'm just doing it wrong, meh, let me know. This works, but it feels very... clunky.
Last edited by Argh on 24 Mar 2008, 08:24, edited 1 time in total.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
My head hurts.Argh wrote:We check for commands issued there, seems silly to not be able to check for a Selected state there, too, imo.
Yes there is, but I don't remember the name, and I'm going to bed. Possibly sendtounsynced, unless I'm missing something.Argh wrote:Is there a way for Sync to just call a Function on the Unsync side, instead?
Last edited by lurker on 24 Mar 2008, 08:28, edited 1 time in total.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
function gadget:AllowCommand(u, ud, team, cmd, param, opts) is a sync command 
Basically, I'm taking a UI action by a player (they hit a button) then it causes stuff to happen, that must occur in sync... then at the end, I want to select a very specific UnitID. I just thought it was terribly wasteful, to have to go through all this trouble, when AllowCommand is sync'd...
Ah... ok! I'll go look that up... then at least I'd do this exactly ONCE, instead of having an evil, evil IF/THEN running constantly...

Basically, I'm taking a UI action by a player (they hit a button) then it causes stuff to happen, that must occur in sync... then at the end, I want to select a very specific UnitID. I just thought it was terribly wasteful, to have to go through all this trouble, when AllowCommand is sync'd...
Ah... ok! I'll go look that up... then at least I'd do this exactly ONCE, instead of having an evil, evil IF/THEN running constantly...
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
But that's not checking for commands being issued, that's looking at commands that have already gone through the net loop. If you want commands being issued in the same sense as looking at selection status, look to commandnotify. Just think about it for a minute. How are 10 different computers going to know if one person has a particular unit selected?Argh wrote:function gadget:AllowCommand(u, ud, team, cmd, param, opts) is a sync command
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
Are you TRYING to parody yourself?Argh wrote:having an evil, evil IF/THEN running constantly...
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
Ah, commandnotify... hmm. I think that I'll just use SendToUnSynced, it's annoying, but meh, whatever.
And no, KDR, it's not parody. I hate wasting cycles on stuff like that in DrawWorld, hence my questions about how to avoid that. Whenever possible, I'm tying down DrawWorld stuff to the clock, to frames- whatever I can, to slow it down and prevent it from running more than it should.
Do you know how many times an empty IF/THEN will try to run, if it's in DrawWorld? Hello... not frame-limited... bad. Which is why I don't want it to work that way. Yeah, every DrawWorld call is going to have a timing call... guess what? An ideal Spring game using Lua would have exactly ONE DrawWorld, for everything. Then it's just an empty loop with only one layer, when it's not running. Not a nested loop.
Check CPU usage against it. Then try this with 10 of them. Then 100. You'll see what I'm saying. It's not crippling, but it's not free, either. Add in a few spikes of major activity, and it really starts to make a difference. I dunno why basic optimization stuff like this offends you, I think it's just good coding practice. I just wish I had the time and mental stamina required to keep every bit of code I do perfectly clean, frankly.
And no, KDR, it's not parody. I hate wasting cycles on stuff like that in DrawWorld, hence my questions about how to avoid that. Whenever possible, I'm tying down DrawWorld stuff to the clock, to frames- whatever I can, to slow it down and prevent it from running more than it should.
Do you know how many times an empty IF/THEN will try to run, if it's in DrawWorld? Hello... not frame-limited... bad. Which is why I don't want it to work that way. Yeah, every DrawWorld call is going to have a timing call... guess what? An ideal Spring game using Lua would have exactly ONE DrawWorld, for everything. Then it's just an empty loop with only one layer, when it's not running. Not a nested loop.
Code: Select all
function gadget:DrawWorld()
local a,b = 1,2
if a == b then return end
end
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
Try 100 with some other instruction, I'm pretty sure that's mostly handling overhead. The creation/destruction of variables probably takes more time than if/then.
You could also try gadget:Update(), no idea how often that's called.
Remember, every terminating loop will run a conditional branch statement for every iteration. So better never use loops if you're scared of conditional branches.
You could also try gadget:Update(), no idea how often that's called.
Remember, every terminating loop will run a conditional branch statement for every iteration. So better never use loops if you're scared of conditional branches.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
There's only so much you can avoid, of course. It's not like you can program much without loops
And you're right, the variable seek / creation is probably a lot of the suck, in that example. Probably not a really good test case. But meh, the main thing is that this is just a relatively rare event, so why have something waiting forever to handle it, when it only occurs infrequently? That's what was making me think I was really doing it wrong- I was like, "surely, you don't have to run anything like this through an endless loop, that makes no sense"...
I'm trying to write as few things that go through an unsync loop as I can, in LUA. I've been a little frustrated that a few things like this cannot be called directly, but I see Lurker's point, I guess this just cannot be avoided, as it's basically a UI query, not a Command, and Spring doesn't want to send it over the net. That makes sense, tbh I just didn't think it through, as I'm rather tired at the moment. Time for bed...

I'm trying to write as few things that go through an unsync loop as I can, in LUA. I've been a little frustrated that a few things like this cannot be called directly, but I see Lurker's point, I guess this just cannot be avoided, as it's basically a UI query, not a Command, and Spring doesn't want to send it over the net. That makes sense, tbh I just didn't think it through, as I'm rather tired at the moment. Time for bed...
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
Ok, got that problem solved. The best way to do it is through RecvFromUnsynced, I found. Here's a simple sample of how to select / re-select a Unit in the UI after completing a sync command that, for whatever reason, needs to break the UI focus. Public Domain.
Please feel free to correct any incorrect statements, I think I got the technical terms right, and the code certainly works. This is very simple, and runs only if something has been received from Sync on a given frame, I think, otherwise it's just an empty loop in unsync and doesn't check that IF/THEN within it, which is what I was trying to avoid here.
What would you use this for? Well, there are a lot of situations where you need to re-select things, because you've broken the UI focus for some reason. Or you could have code that needs to select, say, the 6 nearest friendly Units, then select them for some reason, such as a fake-transport script.
In my case, I'm using something like this (albeit with some fancy elements I'm not showing here) to do "transformer" code with. This was the last little wrinkle- I wanted the UI to behave "normally" insofar as the player is concerned, and retain the UI focus (in this case, what Units are selected) throughout the operation.
Since "transformer" code usually involves destroying a Unit (there is another way of dealing with this, through LuaMoveCtrl, but I'm not entirely happy with that yet), it's impossible to maintain UI focus on the original UnitID. Therefore a method of selecting the Unit that has been newly-created was necessary, so that users will not lose focus, and have to click on the Unit again (remember, in users' minds, this is one Unit, not a Unit we just killed that's been replaced with a completely new one- we don't want to break that illusion).
Code: Select all
if (gadgetHandler:IsSyncedCode()) then
---------------------------------------START SYNCED
function DoSomeStuff(u, ud, team)
--Do Some Game Logic, ending with the value "y", which is a UnitID we want to select
SendToUnsynced("SelectMe", y) --This is sending a Table to RecvFromSynced on this frame, consisting of {Tablename,"SelectMe",y}
end
---------------------------------------END SYNCED
else
---------------------------------------UNSYNCED
function gadget:RecvFromSynced(name,unitID)
if (name == 'SelectMe') then
-- We're the value of the first argument, "name" against our value, "SelectMe", that we sent to Unsync earlier.
Spring.SelectUnitArray({unitID},true)
-- The second argument, the value of "y" in the previous section, is a unitID, so we're looking for that unitID now.
end
end
---------------------------------------END PROGRAM
end
What would you use this for? Well, there are a lot of situations where you need to re-select things, because you've broken the UI focus for some reason. Or you could have code that needs to select, say, the 6 nearest friendly Units, then select them for some reason, such as a fake-transport script.
In my case, I'm using something like this (albeit with some fancy elements I'm not showing here) to do "transformer" code with. This was the last little wrinkle- I wanted the UI to behave "normally" insofar as the player is concerned, and retain the UI focus (in this case, what Units are selected) throughout the operation.
Since "transformer" code usually involves destroying a Unit (there is another way of dealing with this, through LuaMoveCtrl, but I'm not entirely happy with that yet), it's impossible to maintain UI focus on the original UnitID. Therefore a method of selecting the Unit that has been newly-created was necessary, so that users will not lose focus, and have to click on the Unit again (remember, in users' minds, this is one Unit, not a Unit we just killed that's been replaced with a completely new one- we don't want to break that illusion).
Last edited by Argh on 24 Mar 2008, 22:57, edited 1 time in total.
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
first, you don't send a table in synced code (the arg table is created on function call cause of "..." in the function header -> and is slower than direct definition of all arguments).Argh wrote:Code: Select all
if (gadgetHandler:IsSyncedCode()) then ---------------------------------------START SYNCED function DoSomeStuff(u, ud, team) --Do Some Game Logic, ending with the value "y", which is a UnitID we want to select SendToUnsynced("SelectMe", y) --This is sending a Table to RecvFromSynced on this frame, consisting of {Tablename,"SelectMe",y} end ---------------------------------------END SYNCED else ---------------------------------------UNSYNCED function RecvFromSynced(...) if (arg[2] == 'SelectMe') then -- We're checking the second value of the array here, to look for the string value 'SelectMe'. The first value, the table's name (a hex number), can be disregarded. Spring.SelectUnitArray({arg[3]},true) -- The third value of the array we've sent is the value of "y", so we're looking for that value. The ",true" indicates that we want to add this selection to any current selection- if false, then any Units that were selected at that time are unselected, in favor of the new selection- probably worse behavior, from a user's perspective. end end ---------------------------------------END PROGRAM end
second, arg[0] is not the tablename, it is a real table and you only get the reference (a hex code) if you send it through print/Spring.Echo! also arg[0] is the self object, cos you didn't wrote "function gadget:RecvFromSynced(...)".
PS: check the ca morph gadget for an swap-selection example
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
Oh, so that's what that does. Good to know that. Why would you ever want to use "..." then?first, you don't send a table in synced code (the arg table is created on function call cause of "..." in the function header -> and is slower than direct definition of all arguments).
Ok, so to clean that up, it should read:
Code: Select all
function gadget:RecvFromSynced(name,y)
if (name == 'SelectMe') then
Spring.SelectUnitArray({y},true)
end
end
Re: Spring.SelectUnitMap, Spring.SelectUnitArray
"..." are various arguments of mixed type.