Loading...
  OR  Zero-K Name:    Password:   

Central Build Widget

77 posts, 2517 views
Post comment
Filter:    Player:  
Page of 4 (77 records)
sort

9 years ago
This is the widget that gives you a global build queue instead of per-unit, and then automagically assigns workers to nearby jobs. I've decided to work on refactoring it since I'm one of the few people who seems to use it and because it's seriously broken in a couple of ways that annoy me.

The biggest issue right now is that the method for assigning jobs to workers is inconsistent, which causes workers to run around in circles starting random jobs without completing them and sometimes jobs never get finished at all. Technically it's always been inconsistent, but that only became a major issue due to recent changes which allow the widget to reassign workers even if they already have an assigned job or are in the middle of building something. The core code for all of this is much more complicated than it needs to be, and at least according to comments has (n^2+m)*n^2 complexity, where n is the number of eligible workers to be assigned and m is the number of jobs in the queue. I believe that can be reduced to n*m using the model I have in mind.

The recent changes also included a function which favors expensive jobs, however I never saw a necessity for such a feature and I intend to remove it. Also now whenever you queue up a singu or anything in that cost range or greater your workers will all unanimously abandon their jobs, for example building porc at the front line, to go and help on the stupid singu or whatever. It doesn't seem to have any effect with cheaper stuff like DDMs and fusions.

The code also contains several functions that attempt to stop units from suiciding into enemy territory, however some of them may conflict and in practice they cause very stupid behavior. Basically the only one qualified to make those decisions is the player, and to that end I intend to replace all of that code with an area select command for manually removing jobs in bulk.

Currently it does not handle reclaim at all, which sucks. There are problems with this since area reclaim can be 'cast' in places where unsynced code can't know what objects are there. Being able to remove a reclaim job when there's nothing left to reclaim could also be a problem for the same reasons, and I'm not too sure how to handle all of that yet.

I also intend to reoganize the code into even handlers, core logic and helper functions, since currently it's a rat's nest and rather difficult to follow. A few things I suspect are unnecessary and will probably be removed.

So far I've been able to unwind most of what it's doing but the most important part of the code where the worst behavior originates is kind of ambiguous and redundant. Figuring out what's actually necessary and needs to be retained is the first thing I need to work out.
+0 / -0

9 years ago
Well I suppose I'll keep a log here of all the random crap I dig up while working on this thing. A lot of it is voodoo and I've stripped a lot of that out already. Some things will be simplified a lot, and in the end I think this will be a lot easier to read and understand than it is now.

I figured out that the widget now contains a lot of complicated code relating to assisting workers that are already building. There were two reasons for this,
1: In previous iterations items were removed from the build queue as soon as a constructor started working on them, so that in order for another cons to assist it had to either copy the order from the working constructor or use a guard order. Since xponen fixed it so that jobs stay on the queue until completely built this is no longer an issue.

2: Orders given by direct command without shift were never added to the queue, so the only way to assist those jobs was through extra logic. I've modified that code so that now all build jobs are added to the queue whether shift is held or not, although the constructor that was given the direct order will still carry it out immediately as it should.

The new cost/assignment model will also eliminate the need to differentiate between 'primary' and 'assisting' constructors in general.

As a result, the extra handling code will no longer be necessary and I'll be removing that once I get down to rewriting the core job assignment logic. assistType is also obsoleted by this and I've already removed the declarations for it.

I additionally simplified the internal states that units can have. Previously there was idle, busy (direct orders that aren't build orders), drec (direct orders that are build orders), queue (under CB control), and several assist states. I removed the assist states and merged busy and drec so that now there is only idle, queue and drec. In addition to removing a lot of unnecessary crap it should also be easier for users to understand.

I've already removed most of the references to 'avoid enemy unit' related code, will be cleaning the rest of that up shortly.

I need to figure out just how it's handling pathing, but it seems to be doing a lot of unnecessary and possibly incorrect nonsense which could probably be simplified. On the other hand there may be performance related reasons for the extra complexity, which is something I need to verify before I mess with that.

I've also noted that the main assignment code does all the most important/cheap checks only after it does the secondary and more expensive ones. That nonsense is so backwards in inside out that I still don't understand it completely. Also, my version will more likely be n^2*m rather than n*m, but that's still dramatically better than the ~n^4 which it currently is. It might be feasible to increase the assignment rate so that it responds a bit quicker to idle cons.
+0 / -0

9 years ago
After looking over it I removed all code relating to 'check for ally features'. This was supposed to cancel build orders when allied wrecks or 'dragon teeth' (whatever that means) are in the way. This was disabled by default with no interface for enabling it, and, as far as my experience goes that kind of thing is not a major issue in real games anyway. I'm documenting it so that it's at least known that the change was made.

I should also mention that I'm cleaning up and removing a lot of ancient, commented-out code after making sure that it isn't needed. I probably won't be leaving any commented out code from these changes either, since I'm gutting it pretty heavily and that would leave a mountain of unreadable crap that nobody understands anyway. I'll probably leave a note about that in the code so that people will know to just pull an older version if they want to see all of that.

It's already looking a lot better after a bit of cleanup and reorganization.
+0 / -0
9 years ago
Dragon teeth is an obstacle from Total (or Balanced) Annihilation. OP way to restrict movement of large groups of units at cost of few bitz of metal. Not sure if disabling check for blocked path is the best idea, as in some other games this caused loop in pathfinding (repetitive seeking of way to unreachable taget) with serious performance drop, tho cant say if it may be problem here.
+1 / -0

9 years ago
That particular code had no effect on pathing, it just stopped units from reclaiming allied wreckage if it happened to be in the way of construction. That would have actually caused problems had it been enabled anyway.

I did figure out how pathing is calculated. It turns out it's calculated redundantly in 3 different places, and at least once globally for updating myQueueUnreachable over all units. I found out the global calculations are only used in a few peripheral functions that aren't actually necessary. It also turns out that the GetWorkFor function calculates the pathing in every iteration anyway, but I'll probably just clean up the IsTargetReachable function and use that instead. One of the functions for calculating pathing looks to be entirely redundant and not entirely functional.

I also found out that the globally declared blockageType is currently only used by the EnemyAtBuildSiteCleanOrder function, which is being removed. The CleanOrders function declares its own local blockageType, which I'll keep instead.

There seems to be a whole lot of dead or nearly dead code floating around in this widget. I may choke on the dust.
+0 / -0


9 years ago
I'm having great fun reading your dissection/exploration diaries here :P

What's your Github username?
+0 / -0
EErankAdminAnarchid lol, my github is mtroyka.

Which reminds me, I also need xponen to help me comment his changes regarding continuous reassignment and keeping items on the build queue until they're completely finished. I haven't tried to pick that apart in much detail, mainly because that code actually works well enough as is, but I wasn't able to figure out how those parts work by skimming it either. The current comments are no longer correct which is not something I want to leave.
+0 / -0
hello USrankaeonios !

Its great that you are interested in CBAI, but also worrisome when you said most of its components was redundant.

As a defence I will help elucidate the working component.

quote:
I also need xponen to help me comment his changes regarding continuous reassignment and keeping items on the build queue until they're completely finished

First, focus on myQueue[hash], this is a remake of Spring's build-queues, it list the coordinates and type of build. Remove its content will remove the available job for constructors and also the UI green box.

To make job re-assignable, keep its entry undeleted. The entry will be scanned by GetWorkFor() when assigning job, and emptied by widget:UnitFinished() when build finishes and occasionally by CleanOrders() when obstruction is detected. ( note: new patch that fix CleanOrders() in ZK-test )

10 worker are collected at one time by FindEligibleWorker() to be assigned for jobs. (it is limited to 10 due to performance concern)

The job assignment loop isn't redundant, each loop find something necessary:
1st iteration, find the closest job for all 10 worker (GetWorkFor())
then, it find worker nearest to its job and assign it to that job ( GiveWorkToUnits())
2nd, it repeat them with next 9 worker...
3rd, repeat for next 8 worker..
then, 4th -> next 7, 5th -> next 6, ect...

When 1 worker got new job it changes the environment for other worker, so next iteration need to rescan the queues (eg: whether to assist job or create new one).

quote:
The biggest issue right now is that the method for assigning jobs to workers is inconsistent, which causes workers to run around in circles starting random jobs without completing them and sometimes jobs never get finished at all.

Useful feedback, thanks, this is a bug.

A code labelled "--Collect busy worker for reassignment--" (latest version from ZK Github) control the re-assignment. Its currently very simple and by removing "queueType.buildQueue" from "matchAssistOrBuildQueueType", you will at least make 1 worker stay on its job.

Improving this code will give smarter reassignment.

p/s: I didn't see this bug because I usually keep queue short

quote:
The recent changes also included a function which favors expensive jobs, however I never saw a necessity for such a feature and I intend to remove it. Also now whenever you queue up a singu or anything in that cost range or greater your workers will all unanimously abandon their jobs, for example building porc at the front line, to go and help on the stupid singu or whatever.

This is reassignment bug, not Singu! Don't remove the code. More worker to Singu is a correct choice. If worker didn't abandon porc due to re-assignment then everything work perfectly.

quote:
The code also contains several functions that attempt to stop units from suiciding into enemy territory, however some of them may conflict and in practice they cause very stupid behavior. Basically the only one qualified to make those decisions is the player,

Another feedback, thanks, it need improvement.
You should use Direct command to build in enemy territory, else if you use Queue it obey CBAI rules (such as de-prioritize your Queue or remove it).

quote:
Currently it does not handle reclaim at all, which sucks.

It don't need reclaim because it's not meant to be independent of player.

I had widget that control reclaim without conflict with CBAI. Why CBAI is awesome? because it never conflict with other AIs and user. With dedicated widget I can get more advance behaviour.

quote:
1: In previous iterations items were removed from the build queue as soon as a constructor started working on them, so that in order for another cons to assist it had to either copy the order from the working constructor or use a guard order. Since xponen fixed it so that jobs stay on the queue until completely built this is no longer an issue.

Certain worker had limited buildOptions, such as Athena. So GUARDing is never obsolete.

quote:
2: Orders given by direct command without shift were never added to the queue, so the only way to assist those jobs was through extra logic. I've modified that code so that now all build jobs are added to the queue whether shift is held or not, although the constructor that was given the direct order will still carry it out immediately as it should.

Direct command is already stored in myQueue[hash] (this is contrast to the claim). Its hash start with "queueType.buildNew", while hash for Queue start with "queueType.buildQueue".

quote:
The new cost/assignment model will also eliminate the need to differentiate between 'primary' and 'assisting' constructors in general.

Removing "assistBuild" tag will loose the core idea/concept of unit interaction, which is "one builder--many helpers".

The tag could be used to code for more behaviour or for UI.

quote:
This was supposed to cancel build orders when allied wrecks or 'dragon teeth' (whatever that means) are in the way. This was disabled by default with no interface for enabling it, and, as far as my experience goes that kind of thing is not a major issue in real games anyway.

CBAI is proud to maintain portability with any Spring mod. In old days, tweaking widget directly is normal.

quote:
I did figure out how pathing is calculated. It turns out it's calculated redundantly in 3 different places, and at least once globally for updating myQueueUnreachable over all units. I found out the global calculations are only used in a few peripheral functions that aren't actually necessary. It also turns out that the GetWorkFor function calculates the pathing in every iteration anyway, but I'll probably just clean up the IsTargetReachable function and use that instead. One of the functions for calculating pathing looks to be entirely redundant and not entirely functional.

CBAI don't use pathfinding for job assignment but use 2D distance for cost reason.

Periodic pathfinding check for inaccessible build site (eg: sea <-> inland <-> wall barrier) and de-prioritize them.

It's stored in "myQueueUnreachable[unitID][hash]" as integer 0(clear),1(enemy!),2(blocked)
+0 / -1
9 years ago
Now this is how development subforums should look! Without spam of neonstorm threads but filled with actual technical development thought.
+1 / -0

9 years ago
quote:
First, focus on myQueue[hash], this is a remake of Spring's build-queues, it list the coordinates and type of build. Remove its content will remove the available job for constructors and also the UI green box.

To make job re-assignable, keep its entry undeleted. The entry will be scanned by GetWorkFor() when assigning job, and emptied by widget:UnitFinished() when build finishes and occasionally by CleanOrders() when obstruction is detected. ( note: new patch that fix CleanOrders() in ZK-test )

10 worker are collected at one time by FindEligibleWorker() to be assigned for jobs. (it is limited to 10 due to performance concern)


That much I knew. myQueue I didn't really change significantly. widget:UnitFinished() I figured was responsible for keeping items on the queue properly until finished, and I didn't change that either.

quote:
The job assignment loop isn't redundant, each loop find something necessary:
1st iteration, find the closest job for all 10 worker (GetWorkFor())
then, it find worker nearest to its job and assign it to that job ( GiveWorkToUnits())
2nd, it repeat them with next 9 worker...
3rd, repeat for next 8 worker..
then, 4th -> next 7, 5th -> next 6, ect...


The problem is that the second iteration, ie 'find the worker nearest to its job' is very expensive and redundant. We basically have to find work for each constructor twice instead of once, and although it might lead to constructors being assigned to slightly closer jobs that problem is NP-Complete and also much more accurate than what is actually needed for good behavior. The double-assignment is also probably the main reason why constructors are being assigned in circles.

My version will be more like 'find the lowest-cost job for each worker, assign immediately- end'.

quote:
When 1 worker got new job it changes the environment for other worker, so next iteration need to rescan the queues (eg: whether to assist job or create new one).


That's because the cost model for the first assignment pass doesn't account for that properly. The second pass is an over-optimal and overly expensive solution, that also doesn't seem to produce correct results.

quote:
10 worker are collected at one time by FindEligibleWorker() to be assigned for jobs. (it is limited to 10 due to performance concern)...

A code labelled "--Collect busy worker for reassignment--" (latest version from ZK Github) control the re-assignment. Its currently very simple and by removing "queueType.buildQueue" from "matchAssistOrBuildQueueType", you will at least make 1 worker stay on its job.

Improving this code will give smarter reassignment.


I did not see that code, so it's possible that I pulled incorrectly from git. :| Technically FindEligibleWorker is already responsible for that, so the changes should have been made to that function instead.

I should note however that the solution you proposed can't work. If a worker is assigned to a job that's very far away and marked as the primary constructor, then it won't be properly reassigned should a new job get queued up nearer than the job it's already been assigned to. That was one of the major improvements that the previous change made.

quote:
This is reassignment bug, not Singu! Don't remove the code. More worker to Singu is a correct choice. If worker didn't abandon porc due to re-assignment then everything work perfectly.


The problem is that you're trying to compare metal cost and distance in the same cost function. It might be possible to do that, but not simple. I also noticed that you try to account for the total fraction of workers assigned to the expensive job, which is kind of irrelevant.

The main problem though is that it's trivial and takes no time in game to manually tell workers to assist on something, but it's literally impossible to tell them to start some other job on the queue that hasn't been started yet, even if that job is much more important towards not losing the game (for example an LLT next to your singu to stop scythes and things). The 'correct' decision is to obey the player, always, without exception. Taking away the player's ability to make important decisions like that is never a good idea.

It would be fairly trivial to add that back in with the new cost model anyway, but actually making it work in a way that's useful would require coming up with a better system for accounting for metal cost.

quote:
Another feedback, thanks, it need improvement.
You should use Direct command to build in enemy territory, else if you use Queue it obey CBAI rules (such as de-prioritize your Queue or remove it).


That, on the other hand, is a huge freaking pain that I do not ever want to have to do again in game, which is why I removed it. A single undefended enemy mex has no business cancelling my perfectly good queue, when all my workers needed to do was ignore the mex and build the LLT next to it like I told them to and then it'd be my mex instead of my enemy's.

None of the methods for determining what jobs are 'unsafe' is valid from what I checked out. There's no way to tell whether 'enemy units' are actually capable of attacking or not, or whether a worker got killed by a few raiders or whether it walked into an enemy porc line, nor is there a way to tell when a 'dangerous' zone has become safe, except when the player takes actions to clear it out themselves.

Removing jobs with a single area select would be much easier than having to manually tell workers to individually start each job in a place just because CB decided it was 'unsafe'. That's a lot of wasted time that could have been spent managing combat units instead, and I've seen people lose for less than that.

quote:
Certain worker had limited buildOptions, such as Athena. So GUARDing is never obsolete.

Direct command is already stored in myQueue[hash] (this is contrast to the claim). Its hash start with "queueType.buildNew", while hash for Queue start with "queueType.buildQueue".

Removing "assistBuild" tag will loose the core idea/concept of unit interaction, which is "one builder--many helpers".

The tag could be used to code for more behaviour or for UI.


Athena is a special case, and the only special case that I'm aware of. I'm not so sure that it's a big enough issue to merit all of that extra complexity though, since in general people use athenas for special purposes rather than as normal constructors. Athenas are mostly used for ressurecting things and building units behind enemy lines, neither of which are things that CB can handle correctly anyway.

Getting rid of the leader/assistant distinction is what will allow it to both ensure that jobs that have been started will always retain at least one constructor, while at the same time allowing constructors to be reassigned if closer jobs become available.

It's also a lot simpler than the way it works now, so I'd prefer a more concrete example of just what you could accomplish that would actually be useful that also employs the leader/assistant distinction. None of the features that I've been thinking of adding require it, nor is it required to maintain the widget's core functionality, although I will have to rewrite that entirely in order to make it work.

quote:
CBAI don't use pathfinding for job assignment but use 2D distance for cost reason.

Periodic pathfinding check for inaccessible build site (eg: sea <-> inland <-> wall barrier) and de-prioritize them.

It's stored in "myQueueUnreachable[unitID][hash]" as integer 0(clear),1(enemy!),2(blocked)


myQueueUnreachable is never referenced by GiveWorkToUnits or GetWorkFor, and is only trivially referenced by CleanOrders but never actually used for anything.

I looked it over again and you're right, GetWorkFor and GiveWorkToUnits only use a simplified 2D distance, although they cut it in half for flying workers for no good reason. Actually I don't see anywhere where pathing is applied correctly for job assignment, since correct pathing is per-unit-per-location.

Keeping a queue of unreachable jobs is dumb anyway, if anything you would need a per-worker queue of reachable jobs, so that only those jobs would be considered by GetWorkFor. I'll have to figure that out when I get to it, I guess.
+1 / -0
quote:
It don't need reclaim because it's not meant to be independent of player.

I had widget that control reclaim without conflict with CBAI. Why CBAI is awesome? because it never conflict with other AIs and user. With dedicated widget I can get more advance behaviour.


There are a couple of problems with this. First of all CBA first and foremost distributes workers to jobs, and for that reclaim/repair/ressurect are no different from building jobs. You still have to give the orders for that to get on the queue at all one way or the other. Having to direct order workers means finding nearby workers manually, which for expensive jobs is fine but for reclaim is much more tedious. It's also inefficient if the reclaim job is far away from your workers, in which case you probably should just wait until they get around to that area again, or wait for new workers that may be closer. CBA already does that for other jobs, so it wouldn't add any extra effort. CBA can also prevent reclaim jobs from ever being performed if they're added with shift. EDIT: ie it does this currently, which is bad, but would not if it handled reclaim correctly.

CBA also does not work well with other widgets that try to control constructors. The auto reclaim/repair/assist widget for example spams random fight orders and will prevent CBA from assigning them jobs. Letting CBA handle user-added reclaim commands would not have the same issues.


I figured out how FindEligibleWorker() works and what you did to get it to reassign queue-controlled workers. I simplified that slightly and removed some dead commented-out code to clean it up. I couldn't find the comment you referred to, but I'll add some for future reference.
+0 / -0
Could you use CBAI_2 as name instead of merge to CBAI? because rewrite is better for you. You could add experimental stuff without compromise!

I want to fix the CBAI's Reassignment bug and stupidity-with-enemy bug by adding cost bonus for nanoframe under construction & prevent remove of Queue in player's vision.
+0 / -0

9 years ago
Yeah, forking sounds good. EErankAdminAnarchid suggested "Global Build Command" as an alternative name. :P

I finally got it mostly rewritten including the core code, but I haven't gotten that working yet and it needs additional debugging.

Here's the version I produced for anyone interested: http://pastebin.com/X9gLELKb

Currently I'm stuck on a mystery crash that says it tried to access a nil index. What irritates me is that the line throwing the error is only trying to get the moveID, which I copypasted directly from one of the old pathing functions and even used the same variable names.

On the other hand from the short time when it was working for me it looked like most of the perhipheral code is still working in good order. What also baffles me is that the changes I made to FindEligibleWorkers() seem to be working as intended even though it strongly resembles voodoo. :P The changes to queue types also seem to be working fine, although that's not too surprising.

Another note, I believe that the GiveWorkToUnits function was responsible for moving units onto the "wasgivenwork" (or whatever it was called) queue so that it properly cycles through all units instead of just the same 10 over and over. I still need to double check and possibly reimplement that, but it shouldn't be difficult.

One thing you might notice is that the new version is much, much simpler than the old version was. It should now be possible to easily add custom user-configurable cost models. I also intend to add, at minimum, an optional constructor seperator since that should only be a few lines anyway, and an area select for removing jobs.

Adding reclaim/repair/ressurect should be easy in theory, but since the widget draws its ghosts by looking up the building models that leaves the question of how to properly draw ghosts for those commands. Adding them in without changing the drawing code just sounds like a bad idea to me, although I guess I could try that anyway.
+0 / -0
a patched CleanOrder() http://pastebin.com/vWALKF6Y to fix it don't remove Queue that overlap over building. You need to re-cleanup this patch.

Airplane don't have moveID and "access a nil index" meant your index is NIL.

"Global Build Command" sound cool by the way...


+0 / -0
quote:
Adding reclaim/repair/ressurect should be easy in theory, but since the widget draws its ghosts by looking up the building models that leaves the question of how to properly draw ghosts for those commands. Adding them in without changing the drawing code just sounds like a bad idea to me, although I guess I could try that anyway.


USrankaeonios, good news!
I found old widget that demo "AREA COMMAND" that require no complex coding:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua

Command added:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua#L197-L220

Command read:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua#L88-L90

HOPEFULLY YOU READ THIS BEFORE YOU TRIED THE HARD WAY!
+0 / -0

9 years ago
I'm looking forward to this new CBAI USrankaeonios, but think twice before blindly giving in to the Global Build Command.
+0 / -0
quote:
a patched CleanOrder() http://pastebin.com/vWALKF6Y to fix it don't remove Queue that overlap over building. You need to re-cleanup this patch.


Ah thanks, I accidentally deleted the myQueue[key] = nil lines, probably before I understood what they actually did. I also incorporated your changes for keeping started buildings on the queue. I'll need to test that later to make sure it's working properly.

quote:
Airplane don't have moveID and "access a nil index" meant your index is NIL.


I still don't understand this. AFAIK 'nil' is a valid (although not necessarily sane) value in lua, so moveID = nil should be valid. The error isn't even occurring from the usage of moveID, but rather just from assigning it using UnitDefs[udid].moveDef.id. I already implemented a check for "if (moveID)" in isTargetReachable so that shouldn't cause any problems either, but I haven't been able to get far enough to test that yet.

Also I didn't have any air units at the time of testing, unless recom/jumps count. I still don't see any significant differences with the old widget's pathing code either.

EDIT: Strike com also causes this error, so it's a problem with the way I'm trying to access the movedef in general, even though there's literally zero difference with the old widget. :| wtf???

quote:
good news!
I found old widget that demo "AREA COMMAND" that require no complex coding:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua

Command added:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua#L197-L220

Command read:
https://github.com/ZeroK-RTS/Zero-K/blob/4c65c1246586c509f1654584867e378cf0f7ea64/LuaUI/Widgets/cmd_area_mex.lua#L88-L90

HOPEFULLY YOU READ THIS BEFORE YOU TRIED THE HARD WAY!


Ah that does help. No I haven't started working on implementing that part yet since I want to get the core code actually working properly before I start adding other things.

quote:
I'm looking forward to this new CBAI USrankDudeaeonios, but think twice before blindly giving in to the Global Build Command.


I don't get it. :P
+0 / -0

9 years ago
lol ok, it turns out I was pulling the index from unitsToWork instead of the unitID, which caused spGetUnitDefID to return nil, which then broke a bunch of other stuff. I also cleaned up some other errors so I guess we'll see if it works. :P
+0 / -0
USrankaeonios , I want you to know that your feedback about CBAI is really awesome, I appreciate it very much!!

But I accidentally give you buggy patch ops!
You see in http://pastebin.com/vWALKF6Y there's a code that look like the following:
quote:

myQueue[key] = nil --remove queue
isOverlap = true --return true

StopAnyLeader(key)
StopAnyAssistant(key)
break;

pls move the line containing "myQueue[key] = nil" to after the line that contain "StopAny***(key)" , to fix NIL error when cancelling command.

Thankyou very much!
+0 / -0

9 years ago
Oh, I caught that when I was integrating the changes then promptly forgot about it. :P

Another thing I found was that idle workers are not added to reassignedUnits when given jobs, which causes them to get assigned jobs two cycles in a row. It might also cause the widget to get "stuck" on the same 10 idle workers if it can't find reachable jobs for them for pathing reasons, although that would be a fairly rare occurrance.
+0 / -0
Page of 4 (77 records)