Install Steam
login
|
language
简体中文 (Simplified Chinese)
繁體中文 (Traditional Chinese)
日本語 (Japanese)
한국어 (Korean)
ไทย (Thai)
Български (Bulgarian)
Čeština (Czech)
Dansk (Danish)
Deutsch (German)
Español - España (Spanish - Spain)
Español - Latinoamérica (Spanish - Latin America)
Ελληνικά (Greek)
Français (French)
Italiano (Italian)
Bahasa Indonesia (Indonesian)
Magyar (Hungarian)
Nederlands (Dutch)
Norsk (Norwegian)
Polski (Polish)
Português (Portuguese - Portugal)
Português - Brasil (Portuguese - Brazil)
Română (Romanian)
Русский (Russian)
Suomi (Finnish)
Svenska (Swedish)
Türkçe (Turkish)
Tiếng Việt (Vietnamese)
Українська (Ukrainian)
Report a translation problem
In programming, short-circuiting a boolean evaluation means that no further checks will be made as soon as the result is obvious. Specifically in our case, when a list of conditions must all be satisfied, as soon as we encounter one condition that's not satisfied, we should not even bother with the following ones.
While there's no official documentation to prove that this behavior actually exists for Paradox's scripting, profiling observations seem to suggest that it does. Most important, because the conditions in `potential` must all be met for the interaction/decision/etc to even appear, and the conditions are not shown to the users, they serve as the best target for this optimization.
Why are we focusing character interactions? Well, the game is populated with hundreds of different characters and nations, and each nations will have different set of actions that can or cannot be done on any character (You can't mind control other countries' monarchs to abdicate, for example). To support this, the frequency for updating the interactions seems very high, such that around a million calls will be made to each character interactions each year. The condition checks themselves are rather low-cost, but the cumulative effect is still appreciable.
How exactly do I take advantage of short-circuiting? I did a one year test profiling session to see how effective each individual condition serves to rule out possibilities. Intuitively, we know that the likelihood for a character to be ruler or heir is much lower than the likelihood of them being a politician. This means that if we put the condition "is ruler or heir" first, there will be fewer cases where the following conditions must be checked. This is also where vanilla code is under-optimized: for example, conditions such as "not in exile" and "not in void" tend to be placed at the beginning, even though we know that pretty much most of the characters will pass these checks.
Some caveats must be noted: 1) I only did a one-year profiling test session for these individual conditions, and it's likely that their costs will continue to evolve as the game progresses 2) We are assuming that each condition is independent from one another, but there's not feasible course of action to assume otherwise 3) Some conditions have very context-dependent costs: checks over the possession of dlc, for example, and some conditions' cost will change significantly, for example whether the character's primary culture has researched nationalism.
With all these in mind, there should still be a small but significant cumulative effect from such a re-ordering, assuming that short-circuiting actually exists (please do otherwise this scripting language becomes a sea of insanity compounded with all those esoteric knowledge that you must master)
The vanilla code is not very optimized in this area, as there are a lot of unnecessary and duplicate checks. First of all, peasants under serfdom is always checked twice: the first time alongside a literacy condition, the second time on its own. By simply checking it upfront and using else_if, we can remove the second check altogether, since reaching the second branch implies that the first branch is not passed
Furthermore, the code does not use if and else_if when checking favored pop types and peasants under serfdom. It's clear that if you belong to the favored pop type you cannot be a peasant under serfdom, thus there are some unnecessary checks.
Finally, each of the favored type's qualification multiplier is listed on its own, even when many of them have the same modifier value. By merging them and using OR, we can short-circuit and prevent unnecessary checks.