From: Jan E. <ch...@in...> - 2001-07-30 08:25:32
|
I looked more thoroughly at the problem you got, Mike, fixed a few bugs in fire.py but managed to get the same error as you got. I'm not exactly sure where it comes from, and what can be done to remedy it. The problem basically is that somehow two DoneCmd:s end up being sent to the clients. The first one clears away the plan as it's supposed to do, but the second DoneCmd tries to clear away the same plan, but fails. It fails as there are no plans for the unit anymore. The problem here is to determine why two DoneCmd:s end up being sent. After reading the debug output thoroughly I found that somehow Fire.execute() got called twice for the same unit/target. It should never be called more than once with the current code: get in, calculate, send a MoveCmd if needed and terminate with a DoneCmd. However, it got called one more time, the next time updateEngine() was called in mainLoop() in server_main_loop.py. This should not happen, and I think it's a timing problem in checkTime() in the same file. Apparently the server changes the current turn *before* it has a chance to execute the first DoneCmd, thus never removing it from the unit's plans, and ends up executing it once more. For the server this is no problem, as the plans still exists and can be executed, but this of course leads to another DoneCmd being sent out. Here be dragons. Solution: Better timing handling. I propose that the execute() method be made to return a valud indicating wether the plan is done, instead of relying on DoneCmd removing it on the server side too. The change would be in the method executeUnitPlans() in server/engine.py: # loop over all units we have for unit in scenario.units.values (): # does the unit have any plans? plan = unit.getActivePlan () # do we have a plan that is valid and that was not executed # previously this turn? if plan and plan.getLastExecuted () != turn: # yep, all ok, execute the plan if plan.execute ( self.outgoing ): # plan is done now, remove it unit.getPlans ().remove ( plan ) else: # not yet done, set new last execution time to make sure it # will not be called again this turn plan.setLastExecuted ( turn ) The DoneCmd is of course created and sent as before, as the clients need it. It should however not be executed on the server side, as the plan is already removed. So the method applyServer() on DoneCmd could just be made empty, and more the code the removes the plan to applyClient() and applyAI(). What do you think? It's really unbeliveably hard to make a good server engine that works well. I'd like to still believe the system we have is not fundamentally broken by design. It may be a little crippled and flawed, but I still would like to believe in it... ----------------------------------------------------------------------------- Real children don't go hoppity-skip unless they are on drugs. -- Susan Sto Helit, in Hogfather (Terry Pratchett) |