Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spectator Panel Redesign #2302

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from

Conversation

CrazyEddieTK
Copy link
Contributor

Work in progress.

@CrazyEddieTK
Copy link
Contributor Author

This is a working demo of a new design for the spectator panels. This is a work-in-progress, presented for early feedback.

Features:

  • Everything (mostly) that's in the current spec panels
  • Single unified panel layout, no separately-enabled individual panels
  • Symmetric layout, with the two sides mirroring each other
  • Economy stats: Total income, extraction / generation, reclaim, OD, and storage bars
  • Unit stats: Total metal value for all units, offense, defense, and generators
  • Unitpics showing:
    • Commanders remaining on the field and their level
    • Top four fielded unittypes as measured by total metal value, and their unit counts
    • Number of mobile constructors
  • Balance bars, showing graphically the relative advantages between sides in:
    • Metal income
    • Metal extraction (as a proxy for territory control)
    • Military (metal value of offense plus defense)
    • Attrition
  • Pretty background pictures:
    • For 1v1 they indicate each player's initial factory
    • For team games they show something relevant based on teamsize

Limitations:

  • No selectable font size options
  • No selectable opacity options
  • No selectable size limit for long vs. short playernames
  • No resbar delta arrows

Notes:

  • The stats display is updated every two seconds so the numbers don't jump around as badly while you're trying to read them
  • The stats are smoothed over a three-second moving average to better show prevailing trends instead of momentary spikes

To Do:

  • Fix energy stats. I copied code from other widgets but I don't understand it, and the results are wrong.
  • Add resbar flashing on e-stall / metal excess / energy waste
  • Layout and skinning tweaks
  • Tooltips for everything
  • Finish collecting background screenshots
  • Interesting graphical effect underneath win counter to designate winner of the previous game
  • Selectable alternate layouts:
    • Small: takes up less space but uses smaller fonts
    • Compact: fits better in small screens but sacrifices some aesthetics
  • Colorblind colors
  • Context menu
  • Fancy skinning (?)
  • General clean-up
  • A gazillion bugfixes

@CrazyEddieTK
Copy link
Contributor Author

1v1, Cloakies vs Hovers:
spng-1v1

3v3:
spng-3v3

Large teams:
spng-largeteams

@CrazyEddieTK
Copy link
Contributor Author

CrazyEddieTK commented Jun 10, 2017

Invitation for feedback: @GoogleFrog @sprunk @Kingraptor @Licho1 @dvr333 @Anarchid @Aquanim and anyone else who cares to comment.

Please note that I'm aware the code is very messy in places and that I already have plans to clean it up. Much of what's there is scaffolding left over from my experiments with layouts. Regardless, suggestions for improvement are welcome.

I have not tested this in live games, only local games and replays.

Copy link
Member

@sprunk sprunk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stats display is updated every two seconds so the numbers don't jump around as badly while you're trying to read them
The stats are smoothed over a three-second moving average to better show prevailing trends instead of momentary spikes

I think I'd prefer 1s:

  • if you're averaging then they might not be jumping around that much?
  • all other displays refresh at 1s so people might assume this one is lagging
  • 2 does not divide 3 so there's a minor skew (only really relevant for spikes but still)

I'm unsure about background screenshots. I think I'd prefer if this was something simple, for example a render of the factory or its most iconic unit (with llt/hlt/annihilator or whatever for small/medium/large teams). I generally dislike depicting a specific game scenario with parts of an unrelated map etc (even if it's just a beauty shot). More importantly, this allows the picture to have dynamic teamcolors (to look way more coherent).

function GetWinString(name)
local winTable = WG.WinCounter_currentWinTable
if winTable and winTable[name] and winTable[name].wins then
-- TODO - Do something else to mark the winner of the previous game, not this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A laurel wreath perhaps?

return unpack(output_table)
end

local function Format(input, override)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a ToSI function that converts to SI units, use it: https://github.com/ZeroK-RTS/Zero-K/blob/master/LuaRules/Utilities/numberfunctions.lua

-- They were taken from the current spec panels. I've probably translated them
-- incorrectly, but what I have here gives results that seem very wrong.
--
-- For example: Generation 62, Reclaim 0, OD 9 => Income 71.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OD == 9 means that X energy went into overdrive and X+9 came back.

This can happen when one's allies have 100% storage yet many unlinked generators, so even though their entire energy net is directed to OD, some is unable to be spent there. It is then not redirected entirely back to the ally - such extra energy is returned to everyone equally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do everything in terms of allyTeam. AllyTeam overdrive will always be an expenditure. The trick with overdrive is that energy spent on overdrive never touches the Spring resourcing system. Energy is generated by summing over the energy generators, subtracting some for overdrive and then adding that resource to the various teams. The only way to generate energy via Spring is to reclaim or be gifted some energy from an ally (manually, not within the overdrive system).

for i,side in ipairs({'left', 'right'}) do
local smCurr, smStor, smInco, smOvdr, smRecl, smBase, seCurr, seStor, seInco, seOvdr, seRecl, seBase = unpack(smoothedTables['resources_'..side])
t[side].resource_stats.metal.total:SetCaption(Format(smInco, ""))
t[side].resource_stats.metal.labels[1]:SetCaption("E:" .. Format(smBase, ""))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change E to B (for Base) here, and then G to B in energy too, for consistency.

local sorted_udids = {}
for n in pairs(unitStats[i].units) do table.insert(sorted_udids, n) end
if #sorted_udids > 0 then
table.sort(sorted_udids, function (a,b) return unitStats[i].units[a].metal > unitStats[i].units[b].metal end)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to consider: have striders compare before regular units regardless of total metal since arguably they are more interesting.

if #sorted_comm_ids > 0 then
table.sort(sorted_comm_ids, function (a,b) return unitStats[i].comms[a].level > unitStats[i].comms[b].level end)
end
for pic = 1,compic_slots do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extending the unit pic count if the team had less than 3 comms.
Also, perhaps replace com pics with a picture of relevant wreckage as they die.

-- started spectating or the panel was toggled off and on
-- or luaui was reloaded.
--
-- Alas, the attrition counter will still have to start from
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function widget:Update(dt)

-- Start the spec panel in the first userframe. Can't do this during widget:Initialize
-- because the option values aren't set yet by epicmenu and they may be wrong.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Initialize. At some point Epicmenu shows up and updates the options, use OnChange to take this into account. Note that you have to do this anyway as the user can change settings mid-game.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, this should be replaced with Initialize because there is no getting around the fact that options can change.

end

function widget:GameFrame(n)
if panel_is_on then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--------------------------------------------------------------------------------
-- Unit Stats Call-ins and Processor

local function ProcessUnit(unitID, unitDefID, unitTeam, remove)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO add the categorized unit values to the stat collector gadget first, then use that here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting it here means that only spectators will feel the performance impact, and only the spectators using the panels.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version is event-driven, so there's only a small performance hit - just a few local table lookups each time a unit is created or destroyed. On the other hand, if there's no expectation that other widgets would benefit from this information, there's no compelling reason to centralize it in the gadget.

On the gripping hand, putting it in the gadget means that it will be available when a player resigns and begins spectating. Otherwise, the widget will have to iterate through the existing units when first enabled to build the current unit table and then use events for subsequent updates.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to #2258 these stats would be collected by the graph widget anyway.


-- hardcoding these for now, will add colourblind options later
local positiveColourStr = GreenStr
local negativeColourStr = RedStr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a full shader for colourblind now. This still may be useful for colourblind friendly streams that don't want to go all the way.

@GoogleFrog
Copy link
Contributor

Looks fancy. Some feedback:

  • I don't think you need the text "Wins:", just have a large number. Perhaps disable the numbers if they are both zero unless a setting is set. Most games spectated will not be rematches so this would only be relevant for casts and tourneys.
  • The panels take up some of the most important space on the UI. I've been working on making the top of the screen thin and I think the current spectator panels are about the limit of what should be placed in the top center of the screen. The large panels at the top of the screen give a bit of an irregular pillbox effect and reduce the useful game visual area by too much. If you removed the unit icons and bottom two advantage bars it may be thin enough.
  • I've decided that the minimum supported screen size for ZK is 1280x768 and your panels are only just fitting on a 1920 wide screen. The top left and top right thin UI panels that hold the menu and little buttons should be the same size and the menu does not get much smaller than it is now.
  • The list of unit icons contains very little information in the teamgame and probably quickly loses meaning in 1v1. There are often more than 5 unit types in use. Perhaps group them by role and then display image of the type that is most common. This only really works for units with well defined roles like constructors or AA.
  • I made the windows of the basic spectator panel separate so people could have some always enabled and toggle others. For example they may want to always see the economy and only sometimes want to see a force comparison.

@CrazyEddieTK
Copy link
Contributor Author

@sprunk, @GoogleFrog - Thanks for the code review. I'll incorporate your suggestions as I clean up the code. Understanding how the energy stats work will be a challenge; any further pointers would be appreciated.

@GoogleFrog:

Good idea re not enabling the Wins by default, and auto-detecting when there's a rematch.

I'm very sensitive to how much space this layout takes up. I'll be making it thinner, but even so, I think we'll need multiple layouts to support a range of screen sizes. I'm thinking: compact for less than 1080p, standard for 1080p, and large for larger than that. Smaller versions can show less information and have a less interesting design. The presets widget can autodetect the screensize and choose which version to display; users can then override it with an option if they wish.

Standard can drop the unit icons, and probably the clock (I think the advantage bars are the most important part of the spec display). Compact can drop the unit icons and clock, drop the background image, drop the names and the top bar, and arrange the advantage bars horizontally in a thin bar across the bottom, plus make the fontsize smaller.

@sprunk:

I'm unsure about background screenshots. I think I'd prefer if this was something simple, for example a render of the factory or its most iconic unit (with llt/hlt/annihilator or whatever for small/medium/large teams). I generally dislike depicting a specific game scenario with parts of an unrelated map etc (even if it's just a beauty shot). More importantly, this allows the picture to have dynamic teamcolors (to look way more coherent).

That's more-or-less what I was going for, with each bg image showcasing two iconic units from the factory - one small, one large. Only the top quarter of the image is really visible, and the rest just provides a textural background for the rest of the frame to help distinguish the two sides (I intend to have multiple images for each teamsize and choose them so that each side is always different).

But I think I understand what you're suggesting, and I'll try some mockups in that direction and see how it looks.

  • if you're averaging then they might not be jumping around that much?
  • all other displays refresh at 1s so people might assume this one is lagging
  • 2 does not divide 3 so there's a minor skew (only really relevant for spikes but still)

Even with averaging, a one-second refresh makes it hard to read a large display with lots of stats. The three seconds is a rolling average, i.e. it's always the last three seconds averaged no matter when the update happens, so there's no skew.

Thanks for the feedback! I probably won't be able to do any updates for a couple of weeks, but will keep working on it as I'm able.

@dvr333
Copy link
Contributor

dvr333 commented Jun 11, 2017

NB: To check whether there are wins check WG.WinCounter_currentWinTable.hasWins.

I'm going to PR an update to the internal documentation of win_counter.lua to include that info (which needs a rename to api_win_counter.lua)

As for aesthetics, while I feel like you took everything I mentioned wanting in a spectator display and mashed it into one, I agree with Googlefrog that it's really tall and should be more modular. Also, what does "G" and "E" mean? I'm not even looking for an answer so much as the realization that these panels are almost more for the audience than the caster, so there should be as much clarity as possible. The current panels showing "Reclaim" is clear, this one showing "R" is not. (within the assumptions that the audience is English-speaking, but that's a localization question, and my casts are in English anyway)

@sprunk
Copy link
Member

sprunk commented Jun 11, 2017

@CrazyEddieTK

it's always the last three seconds averaged no matter when the update happens, so there's no skew

Let's say update happens on even seconds.

Let's say some stat has a constant 0 value except a one-second spike of value 3X happens at some point.

If the spike is on second 5: the update on second 6 will take seconds 4, 5 and 6 -> (0 + 3X + 0) / 3 -> a value of X is shown for the next 2 seconds and that's it.

If the spike happens on second 6: the update on second 6 takes 4,5,6 -> shows X for the next 2 seconds, then the update at 8 takes 6,7,8 and again shows X for the next 2 seconds (since both these periods include second 6).

In the first case you get shown 2 seconds of X, in the second 4 seconds of X, while in reality there were (the equivalent of) 3 seconds of X.

This is a nitpick but it's also trivial to fix (preferably by making the update period 1s, but if you want to stick to 2s you can make the moving average take 4s).

@dvr333

The current panels showing "Reclaim" is clear, this one showing "R" is not.

Current panels say Re, at least in your own casts: https://www.youtube.com/watch?v=MjoO4G-sMm8&t=0m30s

@dvr333
Copy link
Contributor

dvr333 commented Jun 11, 2017

@sprunk you're right, I'm surprised I didn't notice

@CrazyEddieTK
Copy link
Contributor Author

@sprunk: Thanks, I see now what you're getting at. I don't think it's an issue; the display isn't intended to be an accurate gauge of metal accumulated ("last interval it showed X, this interval it showed X, intervals are two seconds, therefore there's been 4X accumulation"). It's intended to be a reasonable estimate of current rate of income with the spikes smoothed out, so you can tell who's doing well and who's falling behind.

My intuition is that two seconds of averaging would be too spiky, and four seconds would be too laggy (if updates are on even seconds, and a mex was destroyed at t=0.5, the mex's contribution to income would still be partially included in the t=4 update, not disappearing entirely until the t=6 update). But it's easily adjustable in the code; we can do trials and see what people like. We can even make the update and averaging intervals options so people can override the defaults if they really want to. But of course we should make the defaults whatever we think will be best for most people.

@dvr333: Thanks, I'll use that API when I make more fixes.

Perhaps the scheme for alternate layouts will provide both the space savings and modularity that you and GF are looking for. I'll work on it.

Maybe we can find or make icons for generation/extraction, reclaim, and OD. That way they'll at least be equally difficult to understand for everyone. :) Either way, I think having tooltips showing the details and using the spelled-out words will help. People might be briefly confused, but will quickly learn what they mean if they hover over the bar. Icons would make a nicer-looking presentation, too.

@GoogleFrog
Copy link
Contributor

Base generation can be the ibeam with the plus or perhaps the stylized mex. Overdrive can be the ibeam with the energy icon overlayed, this may have been deleted from the repository. Reclaim can be the reclaim cursor.

Perhaps remove the current unit types display and replace it with a collapsible display on the left and right sides of the screen. This display could show many rows of units arranged down each side. This collapsible display could be toggled by clicking on the Unit Value panel and that panel could be its own floating UI component. This would allows the central display to be thinner and fit on smaller screens.

I like the four comparison bars and it is good to stack them vertically but they extend too low. Perhaps stack them in a 2x2 grid with income/extraction as one group and military/attrition as another?

@Anarchid
Copy link
Member

Anarchid commented Aug 1, 2017

The attrition rate calculation here seems to do a duplicate of what Attrition Counter does. Current state of the Endgame Stats widget is that it also collects the information relevant for calculating attrition rate separately and while respecting visibility.

This data is thus now being collected in triplicate. A good idea would be to make both Attrition Counter and Spectator Panel use data provided by Endgame Stats instead of doing their own collection.

That said,
image

P.S i really dig the balance bars for attrition and income ratio stats.

@CrazyEddieTK
Copy link
Contributor Author

One of the open tasks here is to move much of the stats collecting out of the spec panel widget and into the stats collector gadget, as much as it makes sense to do (which may be all of it). I'll do that when I get back to working on this panel (Sprunk has done a lot of that work on the stats gadget already).

@GoogleFrog
Copy link
Contributor

Don't let the unimportantness discourage you too much. The return on investment here seems low (an improvement in the quality of spectating/casts) but it is positive and worth working on at some point. If this is what you want to do then do it. Quite a bit has been improved by people working on projects like this, it all builds up. Ideally the spectator panels would reach a state where they can be enabled by default and automatically toggled on in the appropriate situation. The current panels are not quite at that point, mostly due to placement issues with the floating economy panels.

I've thought a bit about what could be more helpful, since it has come up. You write like a native English speaker and seem to have some common sense regarding PR the most efficient work for you is probably in preparing the text and screenshots for a media pack (I hear it is a good idea to have one). However, if you have preexisting video creation skills then creating an updated trailer is probably the way to go.

@sprunk
Copy link
Member

sprunk commented Oct 18, 2017

The panel seems to have an error:

[f=0011714] [cawidgets.lua] Error: Error in UnitReverseBuilt(): [string "LuaUI\Widgets\gui_chili_specpanel_ng.lua"]:585: attempt to index local 'ud' (a nil value)
[f=0011714] [cawidgets.lua] Error: Removed widget: Chili SpecPanel - Next Gen

ZeroK-RTS/CrashReports#1940

@sprunk
Copy link
Member

sprunk commented Oct 6, 2023

Any recent advances?

@sprunk sprunk marked this pull request as draft October 28, 2023 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants