full PLE mod for BUG

Yes, I should be around most of tomorrow. That's a good first step. It will make plugging in whatever you or I create much easier later.
 
as well as speed testing to see if it actually does anything. Maybe we should run some speed tests at it stands so that we can determine where our biggest wins might be.

Hmm - I am going to the 11:30am screening of Avatar tomorrow so we might have to talk before then (you'll be asleep, won't you?) of around 4pm my time.
 
When I did the timing tests before, I found the largest source of time cost to be the calls to draw the graphics. The time to inspect the units is insignificant. Telling it to draw the same graphic that is already there takes just as long as telling it to draw a new graphic. The underlying UI engine isn't smart enough to detect that nothing has changed--you pay the penalty no matter what.

Thus I need to avoid the calls to draw() when I can. My design is centered around detecting when the graphics must change and only calling draw for that case. It is slightly complicated by the fact that not all graphics are on/off. For example the mission tag is off or one of many icons. It got complicated as I started to work in off vs. not present (no unit in that cell), and I think I over-complicated it.
 
Here is my thinking. Each plot currently has a list of associated units ...
Code:
CyInterface().cacheInterfacePlotUnits(pPlot)
for i in range(CyInterface().getNumCachedInterfacePlotUnits()):
	pLoopUnit = CyInterface().getCachedInterfacePlotUnit(i)
This is totally separate from the unit display. The unit display array (the part of the screen that actually shows you the unit icons) is ...
Code:
if ((iCount == 0) and (CyInterface().getPlotListColumn() > 0)):
	bLeftArrow = True
elif ((iCount == (gc.getMAX_PLOT_LIST_ROWS() * self.numPlotListButtons() - 1)) and ...
... CyInterface().getPlotListColumn() columns wide and gc.getMAX_PLOT_LIST_ROWS() rows high.

Current Method
  • loop over all unit display elements
    1. hide graphical elements
  • loop over all units in the plot
    1. calculate where in the unit display array the pLoopUnit should be displayed (the x and y) - this will vary on lots of things ... column / row format selected, PLE style (#1 unit is shown on top left most unit display element) / vanilla BtS style (#1 unit is shown on bottom left most unit display element), etc, etc
    2. determine the characteristics of the unit (type, selected, promo available, moves left, GG, etc, etc)
    3. display said characteristics
Final Method
  • loop over all units in the plot
    1. calculate where in the unit display array the pLoopUnit should be displayed (the x and y) - this will vary on lots of things ... column / row format selected, PLE style (#1 unit is shown on top left most unit display element) / vanilla BtS style (#1 unit is shown on bottom left most unit display element), etc, etc
    2. determine the characteristics of the unit (type, selected, promo available, moves left, GG, etc, etc)
    3. compare said characteristics to current unit display element settings
    4. adjust if required (show, hide, change)
  • loop over all unit display elements
    1. hide graphical elements if not associated with unit

Now, changing from current to future in 1 fell swoop might be asking for trouble. As such, I would like to bite it off in chunks and head towards this position to start with ...

Interim Method
  • loop over all units in the plot
    1. calculate where in the unit display array the pLoopUnit should be displayed (the x and y) - this will vary on lots of things ... column / row format selected, PLE style (#1 unit is shown on top left most unit display element) / vanilla BtS style (#1 unit is shown on bottom left most unit display element), etc, etc
    2. determine the characteristics of the unit (type, selected, promo available, moves left, GG, etc, etc)
    3. compare said characteristics to current unit display element settings
    4. adjust if required (show, hide, change)
    5. display said characteristics
  • loop over all unit display elements
    1. hide graphical elements if not associated with unit
 
Question for our uses - do you use the PLE filters? If so, what do you do with them?
 
I've started to pull the 1000s of line of code for PLE out of MainInterface into its own file. I haven't got it completely working yet but it is mostly there. Some of the functions in the PLE file are used for the other unit plot methods so they will need to be extracted to some other more generic file at a later stage.
 
EF and I discussed the plot lists and neither of us could figure out what what these two suckers did ...
Code:
CyInterface().getPlotListColumn()
CyInterface().getPlotListOffset()
Well, after some testing and playing with units, I can say that CyInterface().getPlotListOffset() is the number of plot list 'slots' from the top left to the active unit. Vanilla PlotLists number the slots from the top left to the bottom right. When they display the units, the head unit is displayed on the top left (up the screen enough to get them all on one page, multiple rows if required). So CyInterface().getPlotListOffset() tells the draw routine how many empty holes to leave before drawing the first unit.

CyInterface().getPlotListColumn() only comes into play when you have too many units (need to scroll them back and forth). I haven't fully tested this (don't have time to WB in 281 units) but I would assume that it shows the unit number in the top right less 1. So, if I have 280 units, the head unit is displayed in the top left slot. If I add a unit, then the little right / left arrows are enabled. I can then scroll the units left and right. If I move the head unit off the 'page', then I am guessing that CyInterface().getPlotListColumn() will become '1' (ie the head unit is 1 column offset).
 
I've been thinking about this overnight and have the following to share ...

The vanilla BtS unit plot list ties the unit to the on screen location. Each unit plot has a widget number associated with it (k) and the DLL converts clicking / hover action over the widget location to the unit number in the group on that plot. With the PLE unit display methods (grouping, filtering, different layouts) that linkage between on screen location and location in the plot group is totally broken. Thus the author of PLE had to write tons of their own code to redo what the system did for him.

That is not what we want to do with the BUG version. Instead, we are going to decouple the on screen location and the location in the plot group. To do this, we need the individual screen unit place holders to be able to have different widget numbers (k).

The vanilla method sets up the on screen unit place holders ...
Code:
for iIndex in range(self.MaxCells):
	szBupCell = self._getCellWidget(iIndex)
	iX = self._getX(self._getCol(iIndex))
	iY = self._getY(self._getRow(iIndex))

	screen.addCheckBoxGFCAt(self.sBupPanel, szBupCell, sTexture, sHiLiteTexture, iX, iY, 32, 32, WidgetTypes.WIDGET_PLOT_LIST, iIndex, -1, ButtonStyles.BUTTON_STYLE_LABEL, True)
(my value k discussed above is iIndex in the above code)

... and then just changes the display picture based on what unit it should represent ...

Code:
iIndex = CyInterface().getPlotListOffset()
for pBupUnit in self.BupUnits:
	szBupCell = self._getCellWidget(iIndex)
	self.screen.changeImageButton(szBupCell, gc.getUnitInfo(pBupUnit.pUnit.getUnitType()).getButton())
	self.screen.show(szBupCell)
	iIndex += 1

Instead of doing this, we'll need to make note of the unit's place in the plot group and recreate the CheckBoxGFC every time we update the unit plot list so that we can reset the 'k' value to that value. Then we can just use the DLLs method of tying the on screen representation of the unit to the unit in the plot group.
 
Removing and adding the checkbox would put it in front of all the adornments (status dot, health and movement bars, upgrade arrow, and mission tag). And you can't move an item behind another item--only to the front of back completely. But the promotion frame must be behind the checkbox, so you'd have to push that back as well.

For each unit, you must do this:

  1. Delete checkbox
  2. Create checkbox
  3. Move checkbox to back
  4. Move promotion frame to back
Note that when we get the smart redraw code working, removing/replacing the checkboxes will defeat some of the performance gains.

That may only be necessary when you filter/scroll--not when selecting units, right? Maybe that would be okay, but it seems not worth it. Is having that extra code that horrible? I doubt that it is part of the performance problems with PLE.
 
The above only applies when you filter or have a non horizontal layout. We should use code that works for vanilla layout and the above for when you are being PLE tricky. The new code isn't just select, it is also info pain, upgrade, etc.
 
The other option is that we add the 'k' value as a decoration (btw - that is what the author of PLE called all the eye candy that you can add to the unit icon) and if it changes, then we do a complete re-draw - probably of the whole plot list, not just that unit plot.

I see the following as my development order ...
  • add eye candy to BugPanel
  • fold in code to minimize re-draw
  • add PLE functionality to BugPanel
 
all of this work is to speed up displaying plots that have lots of units. Do we have any time tests on the current system? How would I go about setting something like that up?\

I was thinking of using the BUG timer code and then just hitting '>' 10 times.
 
That's exactly what I did originally, except I clicked. > works better probably since you don't have to move the mouse (lazy bum). BugUtil.Timer is the way to go.
 
care to refresh my memory about all of the .Timer commands?
 
got it ... results with about 130ish (edit: actually 165!) units ...

18:10:30 DEBUG: Timer - draw plot list took 624 ms
18:10:34 DEBUG: Timer - draw plot list took 698 ms
18:10:35 DEBUG: Timer - draw plot list took 708 ms
18:10:37 DEBUG: Timer - draw plot list took 691 ms
18:10:38 DEBUG: Timer - draw plot list took 700 ms
18:10:40 DEBUG: Timer - draw plot list took 704 ms
18:10:41 DEBUG: Timer - draw plot list took 711 ms
18:10:43 DEBUG: Timer - draw plot list took 708 ms

So - about 700 ms - totally noticeable.
 
just for fun, I commented out the code that actually does the drawing ... got these results:

21:24:09 DEBUG: Timer - draw plot list took 12 ms
21:24:11 DEBUG: Timer - draw plot list took 13 ms
21:24:12 DEBUG: Timer - draw plot list took 13 ms
21:24:12 DEBUG: Timer - draw plot list took 12 ms

So if people are willing to play with NO unit plot icons, we can get this game to sing!
 
I now have some functional code that does all that Vanilla BtS does. Here is the timing with the 165 units that I have been using for testing ...

22:11:34 DEBUG: Timer - draw plot list took 743 ms <--- this is the first time that I selected the plot
22:11:58 DEBUG: Timer - draw plot list took 4 ms <--- all I did from here was hit '>' as per the test above
22:11:58 DEBUG: Timer - draw plot list took 4 ms
22:11:59 DEBUG: Timer - draw plot list took 4 ms
22:11:59 DEBUG: Timer - draw plot list took 4 ms
22:12:00 DEBUG: Timer - draw plot list took 4 ms
22:12:00 DEBUG: Timer - draw plot list took 4 ms
22:12:01 DEBUG: Timer - draw plot list took 4 ms

Hmm - even better than I got when I wasn't displaying anything - how cool is that!
 
Gotta say, that's pretty sweet! :goodjob: Have you done some thorough testing with things like promoting units, upgrading, attacking, issuing orders, grouping, ungrouping, selecting units, etc?
 
Gotta say, that's pretty sweet! :goodjob: Have you done some thorough testing with things like promoting units, upgrading, attacking, issuing orders, grouping, ungrouping, selecting units, etc?
No, no, no, a little, yes and yes. I think I got that right. Its not ready for prime time yet ... still need to allow for the situation where there are too many units on the plot (those little arrow things), for when the city screen is up (only 1 row) and also need to include non-player units.

If only we had some people who were interested in helping to test this.
 
Top Bottom