question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Command Line Interface and API-GUI convergence?

See original GitHub issue

Is your feature request related to a problem? Please describe. Managing large empires is tedious and painful. A lot of stuff, like build order, unit promotions, finding resources or freeing them up, is highly repetitive.

I like a slick UI as much as the next guy. But in an open-sourced program with clean code, it’s frustrating to have to spend several minutes and hundreds of mouse clicks to do something that could be described with a single line of scripting or with a reusable function.

Describe the solution you’d like It would be great to have a CLI that can be used to access all information and perform all actions that are currently available in the UI.

E.G.:

len(Empire.Cities) to count the number of cities to better plan strategic resource use, instead of having to manually count in the Overview screen.

[city for city in Empire.Cities if any("Aluminium" in building.Consumes for building in city.Buildings)] to get a list of all cities that have Spaceship Factories or Hydro Plants, instead of having to click into dozens of cities and scroll through the entire building list for each.

Empire.Cities.map((city) => city.Governor.SetPriority("Food")) to tell all cities to stop assigning scientists and focus on population growth (once governors get implemented).

[city for city in Empire.Cities if city.Tiles.has("Aluminium")] to figure out where your strategic resources are, instead of having to stare at the map for several minutes, checking all city centers separately, and still missing them.

UITools.Messages.ResourceDiscovery("Uranium", target="Mongolia") to manually re-trigger the “You have discovered [X] sources of [Resource]!” notification, but have it target and cycle through resources on visible tiles near a foreign country, instead of having to spend several minutes staring at every tile and then finding out that you’ve still missed some after you’ve already declared and ended a war.

for i, city in enumerate(sorted(Empire.Cities, key=lambda city: -city.Stats.Production.Base)); do if i < Empire.Resources["Coal"]; then city.Production.prepend("Factory"); fi; city.Production.append("NukeSub"*3, "Cruiser"); done to automatically build as many factories in your largest cities as you have coal resources, and queue up three nuclear submarines and one cruiser to be built in all cities.

buildorder = ["Monument", "Granary", ...]; for city in Empire.Cities: if not city.Production: for building in buildorder: try: city.Production.append(building) to have cities follow a custom automatic build order.

UITools.Map.HighlightCoords(tile.Coord for tile in Map.Tiles if "Coal" in tile.Resources) to display some sort of visual overlay for all visible coals resources, instead of again having to scour every tile by eye.

TurnData.GetMovements().map((move) => UITools.Map.DrawArrow(move.From, move.To, move.isAttack ? "Red" : "Blue")) to display some sort of visual overlay that shows how every visible unit on the map moved last turn, with red arrows indicating attacks and blue arrows for regular movements.

Empire.Units.map((unit) => [unit, unit.Tile.GetNearestUnit(["Interception" ])]).filter(([unit, aa]) => !(aa.InRange(unit))).map(([unit, aa]) => UITools.Map.DrawArrow(unit.Tile.Coord, aa.Tile.Coord)) to locate all your own units that aren’t currently covered by any air defences, and draw a visual overlay on the map pointing them to the nearest AA units. (Or plug in the visible unit list of another empire to figure out where you can safely airstrike.)

To automatically promote all melee units to be generalized, and automatically promote all naval ranged units to maintain a 2:1 ratio of land and naval specialization:

PromotionRatios = {
 ("Naval", "Ranged"): {
  ("Bombardment I", "Bombardment II", "Range"): 2,
  ("Targeting I", "Targeting II", "Sentry"): 1
 },
 ("Melee"): {
  ("Shock I", "Drill I", "Cover I", "Cover II"): 1
 }
}

def GetUnitTypeSig(unit):
 sig = []
 for c, t, f in ((unit.Type.isNaval, "Naval", None), (unit.Type.isRanged, "Ranged", "Melee")):
  s = t if c else f
  if c and s:
   sig.append(s)
 return tuple(s)

def CheckUnitMatchesPromotions(unit, promotions):
 return unit.Promotions and all(p in promotions for p in unit.Promotions)

def PromoteUnitTowards(unit, promotions):
 for promo in promotions:
  try:
   unit.Promotions.Select(promo)
  except XPError:
   pass

def AutoPromoteAll():
 unitsets = {sig: [] for sig in PromotionRatios}
 for unit in Empire.Units:
  sig = GetUnitTypeSig(unit)
  if sig in unitsets:
   unitsets[sig].append(unit)
 for sig, units in unitsets.items():
  targetratios = PromotionRatios[sig]
  currentcounts = {promos: len([u for u in units if CheckUnitMatchesPromotions(unit, promos)]) for promos in targetratios}
  for unit in units:
   if unit.Promotions.available:
    selectedpromos = min({promos: currentcounts[promos]/target for promos, target in targetratios.items()}.items(), key=lambda i: i[1])[0]
   PromoteUnitTowards(unit, selectedpromos)
   if CheckUnitMatchesPromotions(unit, selectedpromos):
    currentcounts[selectedpromos] += 1

AutoPromoteAll()

To quickly distribute cruise missiles evenly across cities, submarines, and missile cruisers:

airbases = [...Empire.Cities, ...(Empire.Units.filter((unit) => unit.hasUnique("Can carry [] Missile units")))];

var ismissile = (unit) => unit.hasUnique("Self-destructs when attacking");

num_missiles = Empire.Units.filter(ismissile).length;

maxmissiles = Math.ceil(num_missiles/airbases.length);

for (let base of airbases) {
 while (base.carriedUnits.filter(ismissile).length > maxmissiles) {
  let missile = base.carriedUnits.find(ismissile);
  missile.actions.doRebase([...missile.RebaseOptions].sort((baseoption) => baseoption.Units.filter(ismissile).length)[0]);
 }
}

…You get the idea

Describe alternatives you’ve considered Massive UI-bloat to special-case all possible visualizations and automations.

Arbitrary code execution, and custom UI elements in the modding API, then making bindings and packing a Python interpreter or Javascript engine or something into a mod.

Fork of this project that adds this. Or binary mod for Sid Meier’s Civ V.

Additional context IMHO it would be cool if the internal API and exposed UI had a 1:1 mapping— If the console exposed some version of the same calls as are made by UI elements, and all checks for legal operations were shared between the console and UI, so there wouldn’t be anything cheaty about playing this way. (Being able to add duplicate buildings and previously being able to select incompatible social policies by clicking quickly suggests that definitions of legal actions are currently not separated from UI code?)

Triggering a drop-down with the backtick key, like in a lot of publishers’ games, would be a sensible way to expose it on Desktop I think. Maybe an on-screen button could be hidden by default, and toggleable in the Options menu, for mobile and mouse users.

With a flag to enable a separate set of illegal commands/cheats, I suppose this could also make it easier to test normal features? Cheats.Enable(), Cheats.InstantProduction = 1, Cheats.SpawnAtTile("Lancer"), Empire.ActiveUnit.XP += 100, etc. (Properties like .XP would usually be available as well, but they would be read-only until cheats are turned on.)

If implemented, being able to define one (or multiple) start-up scripts/macros to populate the namespace with user-defined constants/functions would be a no-brainer.

An idiomatic and expressive high-level language would be ideal IMO. Gracefully handling null values and such would be good for mapping idempotent operations (E.G. selling a building, choosing a promotion, setting a focus) to lots of cities/units without having to either wrap in try blocks or run .filter()s. Small quirks for enhancing usability like coercing everything to the same capitalization and having reasonable aliases (“Nuclear Submarine”, “NukeSub”, “NukeSubmarine”, etc.) could be nice too.

Converging the player GUI and a CLI/API may also have other benefits— Being able to easily plug Unciv into a machine learning experiment, for example, or quickly prototype traditional AI behaviours.

Perhaps popular user scripts could be a source of proven candidates for reimplementation as part of the core game.

I know this is a very big ask, may not fit within the scope of this project, may require infeasible architectural changes, or simply might not interest any current developers.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
yairm210commented, Oct 26, 2021

I see no reason why not 😃

1reaction
ajustsomebodycommented, Oct 27, 2021

cheats for unciv would absolutely be great

Read more comments on GitHub >

github_iconTop Results From Across the Web

Comparing Graphical User Interface (GUI) and Command ...
This article will discuss GUI and CLI and compare the two in terms of ease of use, multitasking, remote access, scripting, speed, ...
Read more >
GUIs vs CLIs vs APIs - Cornell Virtual Workshop
When interacting with Jetstream, you can choose between using a Graphical User Interface (GUI), a Command Line Interface (CLI) or an Application Programmer ......
Read more >
Command-Line Interfaces
The Cisco IOS user interface has many different modes: user EXEC, privileged EXEC (enable), global configuration, interface, subinterface, and protocol-specific ...
Read more >
The Return of the CLI: CLIs Being Used by API-Related ...
While that privilege has been regulated to web APIs in recent years, the Command Line Interface is making a resurgence as many companies...
Read more >
Running CONVERGE on Windows
You can edit environment variables in the Control Panel. CONVERGE accepts a number of command line options, which can be invoked with the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found