* Minimum macOS version is raised to 10.11.
* App bundles ship 3 versions of the runtime and engine binaries,
and a fat launcher that selects the appropriate runtime/apphost.
* Mono is used for macOS 10.11 - 10.14, or if OPENRA_PREFER_MONO
environment variable has been set.
Set an actor moving along several waypoints whilst the /path-debug command is active, then deselect the actor. Each waypoint will add more information to the debugging overlay until it crashes with "Maximum two records permitted." This resolves the crash by no longer adding new debugging information once the actor is deselected.
An event is added to Map to indicate when the cell projection is changed. This is important as this can mean Map.Contains(CPos) could now return different results for the cell. The HierarchicalPathFinder is made aware of these changes so it can rebuild any out-of-date information. This fixes prevent a crash if a cell that was previously outside the map changes height and becomes inside the map. The local path search will explore the cell as it is inside the map - but if the HPF was unaware if had been updated, it will still consider the cell to be outside the map and unreachable, resulting in a crash.
If a path search is performed by the HierarchicalPathFinder when the source cell is unreachable location, a path is still allowed and starts from one of the cells adjacent to the location. If moving into one of these cells results in the actor moving into an isolated area that cannot reach the target this would previously crash as no abstract path could be found. Now we handle such locations by giving them a unreachable cost so the path search will not attempt to explore them.
Imagine a map split into two by a one tile wide line of impassable cliffs. If an actor is on top of these cliffs it is allowed to path because it can "jump off" the cliff and move into the cell immediately either side of it. However it is important which side it chooses to jump into, as one it has moved off the cliff it loses access to the other side. The previous error came about because the path might try and search on the side that couldn't reach the target location. Now we avoid that being considered.
- Add prefixes to all message keys to provide context
- Use messages with attributes for some UI elements (dropdowns, dialogs, checkboxes, menus)
- Rename some class fields for consistency with translation keys
During a game notification duration should be the same regardless of
game speed. Switch to using wall-clock time defined in milliseconds
instead of game ticks. Also use the opportunity to rename the field
to "Duration" because "RemoveTime" is not so clear.
DeployForGrantedCondition is wrapped around the Move activity, so the AttackMoveActivity thinks that DeployForGrantedCondition is the Move activity.
All it means is that we need to forward the target line request to the Move activity
The Locomotor IsMoving check was allowing us to consider another actor that moving as not a blocker. However for some reason it also considered the actor trying to path being mobile as sufficient for this check to pass which did not make sense. We remove that extra check and inline the method.
This was a regression from 4a609bbee8 which changed the method from IsMovingInMyDirection (which required the lookup of the mobile trait) to just IsMoving. It should have removed the lookup as not required.
This fixes a crash in HPF which was considered the location as blocked when Locomotor considered it unblocked because the logic was not aligned. Removing this check aligns the logic and resolves the crash.
Using the local pathfinder, you could not find a path to an unreachable destination cell, but it was possible to find a path from an unreachable source cell if there was a reachable cells adjacent to it.
The hierarchical pathfinder did not have this behaviour and considering an unreachable source cell to block attempts to find a path.
Now, we unify the pathfinders to use a consistent behaviour, allowing paths from unreachable source cells to be found.
Occupied cells was defined by height yet we didn't update actor map on changing height. This in some scenarios could have caused the aircraft to forget to remove its influence from actor map
The variable `${MOD}` was not enclosed in quotes, but the value contained a space. This caused the argument to be split into two parts.
Using **find** isn't necessary due to globbing.
- Fix an instance where "silo-usage" translation was used without
arguments
- Use the same translation reference for the "Power usage"
- Make the ResourceBarWidget accept a cached transform with the tooltip
text
so it won't have to build the string itself
- Display an infinity symbol when the infinite power cheat is used
- Removes a magic number that is no longer used (>1000000 to check for
unlimited power)
- Use LongBitSetAllocator and not BitSetAllocator. Using the wrong allocator means all string based checks and displays would provide incorrect results.
- Remove LongBitSetAllocator.Mask which wasn't being calculated or Reset correctly. We can use world.AllPlayersMask to provide the same effect at use sites.
When crushables and crates change their Location/TopLeft, their crushability is cached, but when their CenterPosition is changed, their cached crushability is not refreshed. Since their CrushableBy functions depends on IsAtGroundLevel, which depends on the CenterPosition, this means that when the crushability is cached it will depend on the current height of the object. If the height of the object changes, the cache is not refreshed and now contains out of date information.
The Locomotor cache and the HPF both cache this same information, but at different times. HPF caches immediately, but Locomotor caches on demand which means there can be a delay. This means they can have inconsistent, differing views of the crushability information. This eventually surfaces in a "The abstract path should never be searched for an unreachable point." error from HPF when it detects the inconsistency.
The bug is that Locomotor was caching information without refreshing it when required. Fixing this to refresh the cache when the CenterPosition changes is likely to have negative performance impacts. As would removing crushability from the cache. These would both be fixes that address the underlying bug.
The high impacts of a proper fix lead us to a workaround instead. If we set the CenterPosition before setting the Location, then when the Location is set and the caches are refreshed, the new CenterPosition is available when caching the crushability information. This means logic depending on IsAtGroundLevel will get the new information and cache a more up-to-date view of things. This means when changing both the CenterPosition and Location together we now cache correct information. However calls that set only the CenterPosition and not the Location can still result in a bad cache state. Although this is imperfect it is an improvement over current affairs, and has less impact.
Minor adjustment into the D2k
- Add rally point into the Palace
- removed harvester MustBeDestroyed in campaing
- Players can see they carryalls and ornothopers under the fog.
- Increased CameraRemoveDelay on Superweapons so player can see superweapon impact.
When the Land activity is run, the aircraft adds influence to the cell so it cannot be used by other actors. When the TakeOff activity runs, it removes the influence so the cell can be used by other actors.
However, when a Carryall picks up a unit, it is told to Land with a vertical offset - it never reaches ground level. When the TakeOff activity runs, it saw the aircraft was above ground level and bailed out. The means the influence is never removed. The cell is now unusable despite the fact the Carryall has left.
To fix this, TakeOff now checks if influence was applied instead of checking if the aircraft is above ground level. If so, we know the Land activity had decided that influence was required, even if the aircraft has not made it to ground level. When TakeOff runs, it will treat it as a proper take off event even though the aircraft is already above ground level. This means influence will be removed and the cell will become accessible as intended.
In ActorMap, we also fix a design flaw where disposed actors where excluded from queries. This caused cache inconsistencies with clients using ActorMap.CellUpdated event to rely on updates. This event will not get called when the actor was disposed, so the downsteam client may have cached the actors at that location, only for them to "change" when the actor is later disposed. This could cause the Locomotor and HierarchicalPathFInder to have inconsistent views of the actors on the map, causing crashes if the inconsistent state broken some internal invariants. The only reason to exclude disposed actors would be to cover up for the actors not being removed properly from the map, which is fixed now aircraft are handled correctly. If ever an actor isn't removed from the actor map, then the caller needs fixing rather than having the actor map exclude it.
If a path search is attempted from a location outside the map, then PathSearch will filter these out to prevent any crashes. The path search will result in no path. However if the location is within the map but on a custom movement layer that the locomotor cannot use, this currently crashes. To fix this we apply a similar filtering logic to ignore any source locations that cannot be used, and so the path search will result in no path for these as well.
Disallow join button without IP address Input
Closes#20234
Trying to join a server with an empty address crashes the game. This fix disallows pressing join button without ip address field input. Updated to reuse search for joinButton vs 2 separate calls to search.
The BlockingCollection would have `IsAddingCompleted` to true, but `IsComplete` to false, slipping through the cracks and causing an InvalidOperationException ("The collection has been marked as complete with regards to additions.") when trying to add to it.
We now add a check on `(Try)SendData` to only try to add if we can. The collection is still viable for reading until empty/`IsComplete`.
When using the internal AbstractCellForLocalCell method to check if a local cell is reachable, this should return null when the cell is unreachable. If multiple abstract cells were required for that grid, this worked as intended. Only reachable cells are stored in the localCellToAbstractCell mapping. For a grid that required only a single abstract cell, which is the common case, we optimize this to store only the single abstract cell rather than the whole mapping for potentially 100 cells in that grid. However this makes no distinction between the reachable and unreachable cells, so when we check later we get incorrect results. If a cell is unreachable but belongs to the same grid as a single group of reachable cells then we incorrectly report it as reachable. The easiest way to see this incorrect behaviour is when the PathExists is called and can sometimes indicate a path exists when it does not.
To fix this, we now ensure we perform a check to see if the cell is reachable in this single layer case, this allows us to retain the optimization where we don't need to store the whole mapping, but allows us to correctly indicate when cells are unreachable.
Switched the Utility's ExtractTraitDocsCommand output to JSON.
Updated documentation generation to use that and the new Python script to generate the Markdown file, same as the Weapon documentation.
Modifying the list potentially several thousand times is really slow, so notify the child elements that they are being removed and then clear the list in one go.
By tracking updates on the ActorMap the HierarchicalPathFinder can be aware of actors moving around the map. We track a subset of immovable actors that always block. These actors can be treated as impassable obstacles just like terrain. When a path needs to be found the abstract path will guide the search around this subset of immovable actors just like it can guide the search around impassable terrain. For path searches that were previously imperformant because some immovable actors created a bottleneck that needed to be routed around, these will now be performant instead. Path searches with bottlenecks created by items such as trees, walls and buildings should see a performance improvement. Bottlenecks created by other units will not benefit.
We now maintain two sets of HPFs. One is aware of immovable actors and will be used for path searches that request BlockedByActor.Immovable, BlockedByActor.Stationary and BlockedByActor.All to guide that around the immovable obstacles. The other is aware of terrain only and will be used for searches that request BlockedByActor.None, or if an ignoreActor is provided. A new UI dropdown when using the `/hpf` command will allow switching between the visuals of the two sets.
When the UpdateCellBlocking encountered a transit-only cell (the bibs around a building) it would bail from the loop. This would leave the cellCrushablePlayers set to all players. It would update the cell cache and mark that cell as a crushable location.
When CanMoveFreelyInto would later evaluate a cell, it would consider it passable because the crushable check would pass (cellCache.Crushable.Overlaps(actor.Owner.PlayerMask)) rather than because the transit check (otherActor.OccupiesSpace is Building building && building.TransitOnlyCells().Contains(cell)) would pass.
Although this meant the cell was treated as passable in either scenario, it means the cache contained incorrect data. The cell does not contain any crushable actors but the cache would indicate it did. Correcting this means we can rely on the crushability information stored in the cache to be accurate.
When this cheat is used by notifying of shroud changes we invoke the usual logic that would occur if the visibility had been granted by units. Without this change any cached information about the visibility is not refreshed. Without this refresh actors with different visibility may not act correctly.
One aspect this improves is frozen actors. Using the visibility cheat will show up all actors on the map. If the cheat is then disabled than frozen actors will appear in their place. Prior to this change a frozen actor would fail to appear if the cheat had caused it to be revealed. Healthbars and selection boxes are also made consistent for similar reasons.
Since bbf5970bc1 we update frozen actors only when required.
In 8339c6843e a regression was fixed where actors created in line of sight would be invisible.
Here, we fix a related regression where cloaked units that are revealed, and then frozen when you move out of line of sight would lack tooltips.
The fix centers around the setting of the Hidden flag. In the old code this used CanBeViewedByPlayer which checks for visibility modifiers and then uses the default visibility. The bug with this code is that when a visibility modifier was not hiding the actor, then we would report the default visibility state instead. However the frozen visibility state applies here which means if the frozen actor is visible, then we consider the actor to be hidden and therefore tooltips will not appear. In the fixed version we only consider the modifiers. This means a visibility modifier such as Cloak can hide the frozen actor tooltips. But otherwise we do not consider the frozen actor to be hidden. This prevents a frozen actor from hiding its own tooltips in some unintended circular logic. Hidden now becomes just a flag to indicate if the visibility modifiers are overriding things, as intended.
Since bbf5970bc1 we only update frozen actor state on demand rather than every tick. However when the actor was initially created we were failing to set the initial visibility state if the frozen actor was invisible.
With this fix, we now set the visibility states on creation correctly. This fixes an issue where enemy actors created within line of sight would not appear.
During the refactoring to introduce HierarchicalPathFinder, custom costs were no longer applied to source locations. The logic being that if we are already in the source location, then there should be no cost added to it to get there - we are already there!
Path searches support the ability to go from multiple sources to a single target, but the reverse is not supported. Some callers that require a search from a single source to one of multiple targets perform their search in reverse, swapping the source and targets so they can run the search, then reversing the path they are given so things are the correct way around again. For callers that also use a custom cost like the harvester code that do this in order to find free refineries, they might want the custom cost to be applied to the source location. The harvester code uses this to filter out overloaded refineries. It wants to search from a harvester to multiple refineries, and thus reverses this in order to perform the path search. Without the custom cost being applied to the "source" locations, this filtering logic never gets applied.
To fix this, we now apply the custom cost to source locations. If the custom cost provides an invalid path, then the source location is excluded entirely. Although this seems unintuitive on its own, this allows searches done "in reverse" to work again.
When asked to find a path from multiple source locations, the abstract search is used to determine which source locations are viable. Source locations that cannot be reached on the abstract graph are excluded from the local path search. As we know the locations are unreachable, this prevents the local path search from expanding over the entire search space in an attempt to find these unreachable locations, preventing wasted effort.
In order to determine these reachable locations, the abstract search is expanded successively trying to reach each source location each time. However, this failed to account for a property of the ExpandToTarget for which a comment is now added. If the location was found previously, then expanding to try and find it again will fail. If the source locations were close together, it was likely that the initial expansions of the search space would have included them, and thus they would not be found on a later expansion. This would mean these locations would incorrectly be thought unreachable.
To fix this, we check if the location has already been explored (has CellStatus.Closed in the graph). If so we can check the cost to determine if it is reachable.
Previously, actors that were visible would refresh their frozen actor state every tick in preparation for the actor becoming hidden, and the frozen actor appearing as a placeholder instead.
By using ICreatesFrozenActors.OnVisibilityChanged when can avoid refreshing the state constantly, and instead just refresh it the moment the frozen actor needs to appear. This provides a nice performance improvement on the cost on managing frozen actors.
Activated with the '/path-debug' chat command, this displays the explored search space and costs when searching for paths. It supports custom movement layers, bi-directional searches as well as visualizing searches over the abstract graph of the HierarchicalPathFinder. The most recent search among selected units is shown.
Teach HierarchicalPathFinder to keep a cache of domain indices, refreshing them only on demand and when invalidated by terrain changes. This provides an accurate and quick determination for checking if paths exist between given locations.
By exposing PathExistsForLocomotor on the IPathFinder interface, we can remove the DomainIndex trait entirely.
Replaces the existing bi-directional search between points used by the pathfinder with a guided hierarchical search. The old search was a standard A* search with a heuristic of advancing in straight line towards the target. This heuristic performs well if a mostly direct path to the target exists, it performs poorly it the path has to navigate around blockages in the terrain. The hierarchical path finder maintains a simplified, abstract graph. When a path search is performed it uses this abstract graph to inform the heuristic. Instead of moving blindly towards the target, it will instead steer around major obstacles, almost as if it had been provided a map which ensures it can move in roughly the right direction. This allows it to explore less of the area overall, improving performance.
When a path needs to steer around terrain on the map, the hierarchical path finder is able to greatly improve on the previous performance. When a path is able to proceed in a straight line, no performance benefit will be seen. If the path needs to steer around actors on the map instead of terrain (e.g. trees, buildings, units) then the same poor pathfinding performance as before will be observed.
Commands are registered in WorldLoaded event handlers, and IngameChatLogic takes all registered commands and provides tab completion. However IngameChatLogic is also created during WorldLoaded via LoadWidgetAtGameStart. No initialization order is enforced between commands and LoadWidgetAtGameStart, so they can appear in any order.
If a command gets registered before LoadWidgetAtGameStart runs, then it will get tab completion. If it gets registered after then no tab completion is available, even though the command can still be used and appears when using '/help'.
To fix this, we allow the tab completion to check for available commands lazily, meaning it will check for available commands every time the tab key is pressed. This means it will always have the full list of commands available regardless of the initialization order.
Error messages are displayed using the following methods:
* **zenity** parses pango markup and replaces escaped characters
* **kdialog** replaces (some) escaped characters
* **gtk-dialog.py** replaces `\n`
* **printf** interprets format strings and replaces escaped characters
* **echo** just displays the text
The error messages themself contain escaped characters and paths from variables.
This PR unifies the behavior by:
* Use **printf** to format error messages and replace escaped characters
* Setting `--no-markup` for **zenity** to disable pango markup and escaped characters
* Remove `\n` replacement from **gtk-dialog.py**.
* Use plain **echo** instead of **printf**
Use **xargs** to pass results of **find** instead of word splitting. Word splitting fails when filenames contain white spaces (or if no files are found).
To prepare them for documentation generation.
Also added descriptions to SpriteSequence implementations and their properties.
Also made a few code style fixes.
Two different issues were causing a path search to not explore cells in order of the cheapest estimated route first. This meant the search could sometimes miss a cheaper route and return a suboptimal path.
- PriorityQueue had a bug which would cause it to not check some elements when restoring the heap property of its internal data structure. Failing to do this would invalidate the heap property, meaning it would not longer return the items in correct priority order. Additional tests ensure this is covered.
- When a path search encountered the same cell again with a lower cost, it would not update the priority queue with the new cost. This meant the cell was not explored early enough as it was in the queue with its original, higher cost. Exploring other paths might close off surrounding cells, preventing the cell with the lower cost from progressing. Instead we now add a duplicate with the lower cost to ensure it gets explored at the right time. We remove the duplicate with the higher cost in CanExpand by checking for already Closed cells.
Prior to ef44c31a72, Locomotor would be earlier in the trait initialization sequence than SpawnStartingUnits. After this commit, the initialization sequence was perturbed and SpawnStartingUnits would initialize first. When SpawnStartingUnits would query CanEnterCell this would generate a null reference as Locomotor had not yet initialized.
SpawnStartingUnitsInfo is made to initialize NotBefore LocomotorInfo to enforce the required trait ordering.
The following error occurs on a map where the radar activation sound plays:
Exception has occurred: CLR/System.ArgumentException
An exception of type 'System.ArgumentException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Property set method not found.'
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
at OpenRA.FieldLoader.LoadField(Object target, String key, String value) in /home/jason/git/OpenRA/OpenRA.Game/FieldLoader.cs:line 609
at OpenRA.WidgetLoader.LoadWidget(WidgetArgs args, Widget parent, MiniYamlNode node) in /home/jason/git/OpenRA/OpenRA.Game/Widgets/WidgetLoader.cs:line 60
at OpenRA.WidgetLoader.LoadWidget(WidgetArgs args, Widget parent, MiniYamlNode node) in /home/jason/git/OpenRA/OpenRA.Game/Widgets/WidgetLoader.cs:line 67
at OpenRA.WidgetLoader.LoadWidget(WidgetArgs args, Widget parent, MiniYamlNode node) in /home/jason/git/OpenRA/OpenRA.Game/Widgets/WidgetLoader.cs:line 67
at OpenRA.WidgetLoader.LoadWidget(WidgetArgs args, Widget parent, MiniYamlNode node) in /home/jason/git/OpenRA/OpenRA.Game/Widgets/WidgetLoader.cs:line 67
at OpenRA.WidgetLoader.LoadWidget(WidgetArgs args, Widget parent, String w) in /home/jason/git/OpenRA/OpenRA.Game/Widgets/WidgetLoader.cs:line 43
at OpenRA.Game.LoadWidget(World world, String id, Widget parent, WidgetArgs args) in /home/jason/git/OpenRA/OpenRA.Game/Game.cs:line 160
at OpenRA.Mods.Common.Widgets.Logic.LoadIngamePlayerOrObserverUILogic..ctor(Widget widget, World world) in /home/jason/git/OpenRA/OpenRA.Mods.Common/Widgets/Logic/Ingame/LoadIngamePlayerOrObserverUILogic.cs:line 34
Move the domain logic involved into a base class named DensePathGraph. The base class contains all the domain logic necessary to traverse a graph including concepts such as custom movement layer.
PathGraph becomes responsible for proving a backing array for the pathfinding information, and is where the pooling logic lives instead, helping split the two concepts out.
The restores the previous behaviour before FindUnitPathToTargetCell was introduced. This prevents callers such as the harvester code crashing when a harvester tries to route home to a refinery, but there are no refineries.
Prior to ef44c31a72, Locomotor would be earlier in the trait initialization sequence than SpawnMapActors. Locomotor would assume no actors on the map, and register to update blocked cells when new ones were added. When SpawnMapActors created actors, Locomotor was made aware and kept up-to-date.
After this commit, the initialization sequence was perturbed and SpawnMapActors would initialize first. Locomotor would assume no actors on the map and thus be unaware of these starting units, meaning those starting units would not cause blocking, allowing units to pass through them.
There are two possible fixes. SpawnMapActorsInfo can initialize NotBefore<LocomotorInfo>, enforcing that actors are spawned after locomotor is ready. Or we can remove the assumption in Locomotor that the map starts empty, and have it update blocked cells on startup. The latter seems cleaner, so any other traits that may want to spawn actors don't have to be aware sequencing their initialization with the Locomotor trait, instead things would "just work".
The types for Int32 and Boolean are currently replaced with friendly names of int and bool for the docs. Ensure we apply the same handling when these are nullable types, changing the output from Int32? and Boolean? to int? and bool?
Some path searches, using PathSearch, were created directly at the callsite rather than using the pathfinder trait. This means some searches did not not benefit from the performance checks done in the pathfinder trait. It also means the pathfinder trait was not responsible for all pathing done in the game. Fix this with the following changes:
- Create a sensible shape for the IPathFinder interface and promote it to a trait interface, allowing theoretical replacements of the implementation. Ensure none of the concrete classes in OpenRA.Mods.Common.Pathfinder are exposed in the interface to ensure this is possible.
- Update the PathFinder class to implement the interface, and update several callsites manually running pathfinding code to instead call the IPathFinder interface.
- Overall, this allows any implementation of the IPathFinder interface to intercept and control all path searching performed by the game. Previously some searches would not have used it, and no alternate implementations were possible as the existing implementation was hardcoded into the interface shape.
Additionally:
- Move the responsibility of finding paths on completed path searches from pathfinder to path search, which is a more sensible location.
- Clean up the pathfinder pre-search optimizations.
Requires<T> means that trait of type T will be initialized first, and asserts that at least one exists. The new NotBefore<T> means that trait of type T will be initialized first, but allows no traits.
This allows traits to control initialization order for optional dependencies. They want to be initialized second so they can rely on the dependencies having been initialized. But if the dependencies are optional then to not throw if none are present.
We apply this to Locomotor which was previously using AddFrameEndTask to work around trait order initialization. This improves the user experience as the initialization is applied whilst the loading screen is still visible, rather than the game starting and creating jank by performing initialization on the first tick.
This helps improve the safety of code the uses reflection when methods may get renamed, and helps navigating code as the nameof will show up when searching for references to members.
1. If it follow the refinery placing logic, then we can use Facings in PlaceBuildingVariants to help BaseBuilderBotModule "rotates" it to minefield.
2. If it is a normal building, BaseBuilderBotModule will place a random variant actor.
PlayerReference colors in D2k missions only affect chat text and minimap colors because actors use specific palette colors.
So using the colors from the original game's minimap.
- Add a new widget type for input and extend it from other input widgets
- Add a new label type that can be linked to an input widget
- Change the label color when the input's disabled state changes
The `Refinery` trait has a hardcoded usage of `SpriteHarvesterDockSequence`, which requires the harvester to have `WithDockingAnimation`, making it inconvenient-at-best to NOT have a docking/unloading animation.
Actor previously cached targetable locations for static actors as an optimization. As we can no longer reference the IPositionable interface, move this optimization to HitShape instead. Although we lose some of the efficiency of caching the final result on the actor, we gain some by allowing HitShape to cache the results as long as they have not changed. So instead of being limited to static actors, we can extend the caching to currently stationary actor.
Aligns the naming conventions defined in editorconfig (dotnet_naming_style, dotnet_naming_symbols, dotnet_naming_rule) which are reported under the IDE1006 rule with the existing StyleCop rules from the SA13XX range.
This ensures the two rulesets agree when rejecting and accepting naming conventions within the IDE, with a few edges cases where only one ruleset can enforce the convention. IDE1006 allows use to specify a naming convention for type parameters, const locals and protected readonly fields which SA13XX cannot enforce. Some StyleCop SA13XX rules such as SA1309 'Field names should not begin with underscore' are not possible to enforce with the naming rules of IDE1006.
Therefore we enable the IDE1006 as a build time warning to enforce conventions and extend them. We disable SA13XX rules that can now be covered by IDE1006 to avoid double-reporting but leave the remaining SA13XX rules that cover additional cases enabled.
We also re-enable the SA1311 rule convention but enforce it via IDE1006, requiring some violations to be fixed or duplication of existing suppressions. Most violations fixes are trivial renames with the following exception. In ActorInitializer.cs, we prefer to make the fields private instead. ValueActorInit provides a publicly accessible property for access and OwnerInit provides a publicly accessible method. Health.cs is adjusted to access the property base instead when overriding. The reflection calls must be adjusted to target the base class specifically, as searching for a private field from the derived class will fail to locate it on the base class.
Unused suppressions were removed.
- When a path search is being performed the path search will not attempt route to inaccessible cells, so domain index checks to avoid inaccessible cells in the search predicate are redundant and can be removed.
- DomainIndex is a required world trait, so we don't need to use TraitOrDefault and therefore can avoid dealing with the null case.
The existing APIs surfaces for pathfinding are in a wonky shape. We rearrange various responsibilities to better locations and simplify some abstractions that aren't providing value.
- IPathSearch, BasePathSearch and PathSearch are combined into only PathSearch. Its role is now to run a search space over a graph, maintaining the open queue and evaluating the provided heuristic function. The builder-like methods (WithHeuristic, Reverse, FromPoint, etc) are removed in favour of optional parameters in static creation methods. This removes confusion between the builder-aspect and the search function itself. It also becomes responsible for applying the heuristic weight to the heuristic. This fixes an issue where an externally provided heuristic ignored the weighting adjustment, as previously the weight was baked into the default heuristic only.
- Reduce the IGraph interface to the concepts of nodes and edges. Make it non-generic as it is specifically for pathfinding, and rename to IPathGraph accordingly. This is sufficient for a PathSearch to perform a search over any given IGraph. The various customization options are concrete properties of PathGraph only.
- PathFinder does not need to deal with disposal of the search/graph, that is the caller's responsibility.
- Remove CustomBlock from PathGraph as it was unused.
- Remove FindUnitPathToRange as it was unused.
- Use PathFinder.NoPath as the single helper to represent no/empty paths.
- Split control groups management to its own interface
- Add hotkeys for selecting, creating, adding to and combining with control groups
- Add a ControlGroups widget to manage the player interaction
Also added a rule to silence StyleCop complaining about StaticReadonlyFieldsMustBeginWithUpperCaseLetter to match what we already have configured for the IDE.
Having this set to "none" disabled the IDE's option to add braces, whereas "silent" lets it do it on the user's request while still not suggesting it on its own.
Added optional padding to video frames because that's what VideoPlayerWidget expects.
Keeping the option to not use padding for other use-cases like converting frames to PNG.
Removed property backing fields where applicable, introduced C#7 syntax for properties.
Renamed a bunch of interface properties and class private members with more descriptive names.
Did some inconsequential reordering.
- The DEFAULT_PRIVATE_MODIFIER behaviour is now handled by the .editorconfig file via `dotnet_style_require_accessibility_modifiers = omit_if_default:warning`.
Also added `dotnet_diagnostic.IDE0040.severity = warning` there to raise compile-time errors in the CI.
- The field naming conventions seem to already be covered by (some) analyzer rules (checked in both VS and VSCode) - IDE1006/SA1306 and SA1307.
- Fixed a rounding issue in `WavReader.WaveLength()`.
- Fixed `AudReader.SoundLength()` not resetting the stream position.
- Fixed crashes caused by disposed streams because `LengthInSeconds` would try and calculate the length on the fly. It is now precalculated and cached (making it consistent across all 5 current `ISoundFormat` implementations).
- Fixed a crash in `AudReader.LoadSound()`'s `out Func<Stream> result` because that func would try and access the disposed stream's `Length` property. That works for `SegmentStream`, but not for `FileStream`.
- Fixed frameCount/soundLength label positioning in the AssetBrowser window to avoid text clipping .
Splitting them from one array into separate allows us to then reliably pick how each asset should be presented. Also lets us unhardcode some checks like "if file is .vxl ... else is sprite".
Each successive value of BlockedByActor is a superset of the previous value. Having a mixed up order of values in PathSearchOrder is not useful.
In the previous ordering, if a search for Immovable failed to find a path, it would then attempt Stationary. However Stationary is *more* restrictive then Immovable. If Immovable failed, there is no way Stationary could succeed. This means the search for Stationary is wasted effort.
In the fixed ordering, we try Stationary first. In the fixed ordering there are no pointless searches. Every search might succeed where the previous one failed and is therefore useful to try.
The path cache was originally a moderate benefit, but over time a couple of things have conspired against it:
- Only paths with BlockedByActor.None are cached. Originally all paths regardless of blocking were cached but this was deemed unacceptable due to potentially returning outdated paths as actors move about. Paths with BlockedByActor.None are only invalidated if terrain conditions change, which are rarer.
- Move will try and find a path 4 times, trying with a different BlockedByActor check each time. BlockedByActor.None is the last check and only reached if the other searches fail. This is a rare scenario.
Overall, this means the hit rate for the cache is almost non-existent. Given the constraints on path validity it seems unlikely that the hit rate could be improved significantly, therefore it seems reasonable to remove the cache entirely to remove the overhead of cache management.
Fixed code based on feedback
Replaced try/catch block with a null check and exception throw
Fixed code based on feedback
Fixed code based on feedback
Simplified Launch.Map parameter to use map name directly
- Remove functionality for tracking cells considered during the search, as nothing relies on this.
- Rename various parameters in the expand function to closer match naming of fields used in CellInfo, intended to improve clarity.
- Make Status the first field.
- Rename EstimatedTotal to EstimatedTotalCost to make it clearer it has the same unit as the CostSoFar field.
- Rename PreviousPos to PreviousNode as node terminology is a better match for usage.
Firstly, when dealing with maps with height discontinuities, the neighbouring cells we need to search are more that the set we need to search on flat maps. We ensure that as we traverse a map with varying height, we now consider cells "behind" us that may have become accessible due to a height change.
Secondly, when considering connections available via Custom Movement Layers, make sure the target cell on the new layer is actually enterable. Previously this cell would be reported as a valid connection, even if it wasn't actually possible to enter the cell as it was blocked. We also apply the same optimization of ignoring already closed cells.
- Stream lines in as memory rather than needing to realise a string for each line, via a new method in StreamExts.
- Use span to avoid string allocations during parsing until we want to realise the node itself, in MiniYaml.FromLines.
- Change several callsites to use the streaming extension method rather than string method where possible.
This is a follow-up to PR 19379, which aimed to "provide an easy debug option for VSCode developers", but only did so for non-Windows users. VSCode has been building in Release mode for ever and continued to do so on Windows after that PR.
Previously, some paths used a separator and some did not. This broke some de-duplication logic in ExternalMods which tried to enumerate distinct paths but would end up running logic on the same directory more than one as it was provided both with and without a trailing directory separator. By normalizing the path this logic now works.
As there are few custom movement layers, using an array is good for improving lookup speed. Additionally, we can simplify some code by reserving index 0 of the array for the ground layer. Code that needs to maintain a state for the ground layer and every custom movement layer can now maintain a flat array of state using index 0 for the ground layer, and the the ICustomMovementLayer.Index for the custom movement layer. This removes a lot of ternary statements checking for the ground layer special case.
This also removes a workaround that allowed the current mod to be
registered even if it defined a bogus path. Uses of Game.ExternalMods
should therefore always use TryGetValue and correctly handle it
returning false.
- Extract chat line templates and logic so they can be reused across widgets
- Make text notification styling entirely template driven (by removing chat color configuration and making color optional for `TextNotification`)
- Add a new TextNotificationsDisplay widget (based on and replacing ChatDisplayWidget)
- Add timestamp support to text notifications
In CellInfoLayerPool, instead of having to store a layer with the default values, we know we can just clear the pooled layer in order to reset it. This saves on memory, and also makes resetting marginally faster.
In PathSearch, we need to amend a check to ensure a cell info is not Unvisited before we check on its cost.
Unfortunately due to bugs in the analyzers or something else, the IDE0005 doesn't work as expected. The "officially suggested" workaround is to enable XML documentation generation to trigger IDE0005 during compiling. Then we need to add three more rules to silence the warnings that come from the XML documentation generation. We also need to enable code style enforcing on build for all of this to work.
Known issue is that all of this produces a bunch (tens to hundreds) of obscure analyzer warnings on older versions of Visual Studio, but those seem to not be causing issues.
- Rename CostForInvalidCell to PathCostForInvalidPath
- Add MovementCostForUnreachableCell
- Update usages of int.MaxValue and short.Maxvalue to use named constants where relevant.
- Update costs on ICustomMovementLayer to return short, for consistency with costs from Locomotor.
- Rename some methods to distinguish between path/movement cost.
- _http_ `->` _https_ where appropriate
- _wiki.openra.net_ `->` _https://github.com/OpenRA/OpenRA/wiki_
- _bugs.openra.net_ `->` _https://github.com/OpenRA/OpenRA/issues_
- the IRC channel is now on Libera.Chat + make it into a URI
This is in order to be consistent (one link to GitHub wiki already
exists), reflect reality, as well as avoid unnecessary redirects.
We observe that most cells within a map lie within a region where no matter their height, their projection would still remain in map bounds. We can utilise this to perform a fast check for such cells and skipping the expensive checks on their actual height. We only need to check the actual height of a cell if this could cause the projection to go out of bounds.
By making the constructor take non-optional parameters, this highlights some calls sites which were forgetting to set these values. These are now fixed.
Set the path debug to have a marker size of 2 for better visibility.
The ping/pong orders are replaced with a dedicated
(and much smaller) Ping packet that is handled
directly in the client and server Connection wrappers.
This allows clients to respond when the orders are
processed, instead of queuing the pong order to be
sent in the next frame (which added an extra 120ms
of unwanted latency).
The ping frequency has been raised to 1Hz, and pings
are now routed through the server events queue in
preparation for the future dynamic latency system.
The raw ping numbers are no longer sent to clients,
the server instead evaluates a single ConnectionQuality
value that in the future may be based on more than
just the ping times.
* EchoConnection is now a trivial buffer that stores
and repeats orders directly without serialization.
* NetworkConnection no longer subclasses EchoConnection,
and now also caches local orders without serialization.
* Replay recording was moved to NetworkConnection
(it is never used on EchoConnection).
Well, 05eb really, but until we implement campaign progression,
calling it 'c' is the easiest way to differentiate it without breaking
our mission title length/alignment conventions.
* TSVeinsRenderer now shows border cells on the radar
* BuildableTerrainLayer now uses the radar colors defined on the individual tiles
* CliffBackImpassabilityLayer no longer overrides the underlying terrain color.
This is less realistic, but better matches the original
game and is the only practical way to reduce visual issues
caused by long shadows being cast over multiple cells.
The trait documentation specified that the speed
and offset values are px/tick, but they have actually
always been treated as px/render.
Fix the update logic and rescale the map definitions
to account for the fixed behaviour.
Bibs and other effects that should be drawn at ground level
can now simply define ZRamp: 1, Offset: <X>,<Y>,1, avoiding the
need to account for the Y offset or internal sprite offsets.
This explicitly tells KDE to associate the OpenRA window with
the integrated appimage desktop file, allowing it to use the
correct resolution icon for the task switcher.
Forces the chat and performance panels to be re-initialized when a
player transitions to spectators. This ensures that spectators don't
get to see faction themed widgets.
In path finding GetConnections considers connections to already closed cells and calculates the cost for them. The caller afterwards ignores them. These are 15% of all connections.
If progress == Distance, we must not move again on the same tick,
but still 'return true' to avoid losing a tick in the case
when this is the last Move tick followed by a different activity
(or a new queued Move, for example via waypoints).
This was previously decreased to support legacy GPUs
that only supported 8 texture image units and we need
to reserve one of these for the palette texture.
OpenGL 3.X mandates a minimum of 16 (and most most GL2
cards also supported it) so we can now safely increase
this limit.
The previous asynchronous approach did not work particularly well,
leading to large janks when switching to custom maps or opening the
mission browser.
This commit introduces two key changes:
* Rule loading for WorldActorInfo and PlayerActorInfo is made
synchronous, in preparation for the next commit which will
significantly optimize this path.
* The full ruleset loading, which is required for map validation,
is moved to the server-side and managed by a new ServerMapStatusCache.
The previous syntax check is expanded to include the ability to run
lint tests.
As far as I could tell, this was the last place that still
used 'seconds' instead of ticks, apart from
some sound notification intervals (which are better
converted to real [milli]seconds).
Also renamed ScaredyCat.PanicLength to PanicDuration for
consistency and easier finding.
There were 2 issues at work here, both when progress
would overshoot Distance (which is the usual case,
rather than the exception):
- the overshot progress was passed on by MoveFirstHalf, however
OnComplete would make the next MovePart start ticking the
same tick on which the old MovePart reached Distance,
but move by carryoverProgress +(!!!) terrain speed instead of moving
by just the left-over carryoverProgress.
- MoveSecondHalf would not pass any overshot progress to the
next MoveFirstHalf queued by parent Move, leading to
the next MoveFirstHalf performing a full-speed move the same tick
MoveSecondHalf finished its last move.
InnerActivity and UpdateCenterLocation made this
overly complex and hard to read & debug.
This also fixes a bug that would make an outdated
facing being passed during OnComplete (because
InnerActivity was cached before UpdateCenterLocation
could set the correct final facing).
Both writing to perf.log frequently as well as GetTimestamp
aren't free and hurt performance particularly on slower systems
(which can have notably higher output to perf.log, further
amplifying the problem).
Therefore we make simulation perf logging opt-in.
Additionally, logging of the current tick and tick type
(local/net) is removed from debug.log, and some
remnant debug logging for kills and pips is removed
to keep performance-sensitive logging limited to
perf.log.
*Remove internal GameSpeed defaults
Enforce setting values explicitly all the time
Require definition of a DefaultSpeed
*Remove Global.Timestep default
*Remove the hacky Timestep/OrderLatency setting via LobbyInfo
*Fix shellmaps ignoring mod-defined gamespeeds
*Make DateTimeGlobal use the MapOptions gamespeed
A mere int comparison is obviously cheaper than
a comparison between two multiplications,
so pulling this above the checks of other damage states
allows us to bail early for undamaged actors.
Profiling has shown that filtering them out early is cheaper
than applying those percentage modifiers anyway.
Additionally, profiling shows foreach loops to be cheaper
than LINQ here as well.
* ResourceType trait has been removed.
* Simulation-related data is now defined on the
ResourceLayer (which mods can subclass/replace).
* Support non-money resources by moving the resource
values to the PlayerResources trait.
* Allow mods to disable the neighbour density override
and instead always use the map-defined densities.
* Allow mods to define their own resource placement
logic (e.g. allow resources on slopes) by subclassing
(Editor)ResourceLayer.
* Improve ability to subclass/override ResourceRenderer
by exposing more virtual methods.
While they may be only 'visual' in terms of influence/cell grid,
they all do update CenterPosition, which is essentially the
actual world position of the actor.
'Visual' would imply that it only affects the position where the
actor is drawn, which is inaccurate.
Furthermore, using the term 'Visual' here would make
naming future methods/properties related to visual interpolation
unnecessarily complicated, because that's where we might
need a real 'Visual(Only)Position'.
Since it's music it's optional, so the players still won't know anything happened, but if they do open the content manager they will have a chance for an automatic installation.
Alpha can specify a single value for the sequence
or values for each frame in the sequence.
AlphaFade: True can be specified to linearly fade
to transparent over the length of the animation.
Unlike its snow counterpart, the transition between building
and its shadow was jarring, making it look as if there was a
1-pixel gap between them. Fixed that.
Also applied some very subtle polish by replacing some non-
remapable red pixels (nothing worth porting to snow variant, though).
A few small improvements:
* The type `desktop` was renamed to `desktop-appliaction` (a long time ago)
* Add `launchable` to tell how the application can be launched
* Use `https` for homepage link
* Add link to the bugtracker
* Update `oars-1.0` to `oars-1.1`
* Remove all unnecessary `content_attribute` entries with value `none`
The `VERSION` variable doesn't work with a release tarball, because it requires git to be set correctly.
Instead this reads the version from the `VERSION` file.
ClientWithIndex may rarely be null, causing a crash.
In any case we do want to report these changes to the first client, as
somebody else may have changed the settings and left.
Removes it from destroyed fields, trees and rocks in RA and C&C.
This trait isn't free in terms of performance due to all the
INotify* calls, and the mentioned actors should rarely
- if ever - need it. Besides, if a mission ever really needs
this on those actors, the trait can be added back via
map rules.
Fix the Building's SoundOnDamageTransition DamagedSounds with the correct one and add a second sound file to DestroyedSounds for more variation like in the original Tiberian Dawn.
Our SpriteFrameType names refer to the byte channel order rather than
the bit order, meaning that SpriteFrameType.BGRA corresponds to the
standard Color.ToArgb() etc byte order when the (little-endian) integer
is read as 4 individual bytes.
The previous code did not account for the fact that non-indexed Png
uses big-endian storage for its RGBA colours, and that SheetBuilder
had the color channels incorrectly swapped to match and cancel this out.
New SpriteFrameType enums are introduced to distinguish between BGRA
(little-endian) and RGBA (big-endian) formats, and also for 24bit data
without alpha. The channel swizzling / alpha creation is now handled
when copying into the texture atlas, removing the need for non-png
ISpriteLoader implementations to allocate an additional temporary array
and reorder the channels during load.
Do not call SkipDoneActivities method recursively via the
NextActivity property. Rather use the nextActivity member.
Avoiding additional function calls and a recursively
growing stack.
Do not call ChildActivity and NextActivity properties
twice in a row. Once to test for null and after to access
it's value. It will cause the complete list of activities
to be traversed twice looking for non done activities.
Replace Queue method with a version that does not the
NextActivity property causing an extra call to
SkipDoneActivities. Avoid calling Queue recursively.
Similar replace QueueChild with a version that does
not call additional methods.
Note that ActivitiesImplementing returns only non
done activities. The method name does not suggest this.
Please consider making NextActivity a method to cleary indicate it
involves the logic of skipping Done activities. To let
the called know it is 'expensive'.
Please consider renaming the protected property ChildActivity to
FirstChildActivityNotDone to avoid it being used as childActivity.
Please consider maintaining a pointer to the first
non done activity. This avoids the need the each time find it.
- Shared helpers extracted to functions.sh for use by upstream packaging,
Mod SDK, and downstream packaging (via the Makefile targets).
- Assembly management separated from data and combined between engine
and mods to prepare for pending .NET core requirements.
- Streamline Makefile targets.
- Clean up a lot of old technical debt.
- Use SDL2 message boxes instead of Winforms.
- Use a proper project instead of compiling a single file.
- Use assembly attributes instead of modifying strings in the source code.
- Remove generic OpenRA.exe launcher.
- Replace MakeLAA.exe with a python script.
- move Refinery dock/undock notifications to OnStateDock/-Undock
and only call Undock if Dock was also called.
- Add INotifyHarvesterAction support to VoxelHarvesterDockSequence.
...before dock anim could run.
The undock animation would play even if the dock anim
hadn't run (meaning the sequence cancelled before the docking
completed, for example due to refinery death).
Shroud, access ProjectedCellLayer by array index over PPos index.
Performance improvement. Avoid the multiple PPos to array index
conversions in the same method call by calculating the cell
layer index once.
Background:
`Shroud.Tick` and `ProjectedCellLayer.Index(PPos puv)` shows up
in profile reports as one of the most expensive methods
(9% of CPU time).
In `Shroud.Tick` calls `ProjectedCellLayer.Index(PPos puv)` multiple
times for the same or different cell layers of the same dimension.
Improvement:
Benchmark results show an 0.5ms mean improvement in tick
time and 0.3 improvement in render time -
on a replay map of 1.12 min of play at max speed.
Render time:
render222052(bleed) render221934(this commit)
count 8144.000000 8144.000000
mean 11.410075 11.470100
std 5.004876 4.731463
min 3.450700 3.638400
25% 7.409100 7.015900
50% 12.410600 12.435900
75% 13.998100 14.242900
max 149.036200 149.656500
Tick time:
tick_time222043(bleed) tick_time221923(this commit)
count 2366.000000 2366.000000
mean 4.762923 4.275833
std 3.240976 3.206362
min 0.263900 1.653600
25% 4.145375 3.668600
50% 4.779350 4.240050
75% 5.232575 4.611775
max 85.751800 87.387100
Shroud.touchedCount to avoid Tick updates if no cells touched.
Avoids iterating over all map cells of the `touched` cell layer.
Tick time improvement of 40%+ - during at least the first two
minutes of gameplay.
During the first minutes of a game - out of every 1000 ticks
only 10-100 result in the Shroud - of any player - to be touched.
For certains player types (Neutral, Creep) less Shroud updates
are expected throughout a complete game.
Throughout a complete game human/AI players can also have no
Shroud touches during certain Ticks.
Use single piff instead of piffs per impact on
M60s and M1, but in return add visual inaccuracy.
Gave minigunner MG two additional delayed effect warheads
to match sound and fire animation.
All targetlines can now be set to a custom color in yaml or set to be invisible.
All automated behaviours including scripted activities now have no visible target lines.
As proposed in the past in #13577.
Replace TraitContainer.All() that uses the custom AllEnumerator with
TraitContainer.ApplyToAllX() that takes an action as argument.
The AllEnumerator.Current function show up in profiling reports since it is
used each tick multiple times for multiple traits. The function is 'heavy'
because it creates TraitPair<T>'s temporary objects for each actor
trait combination.
In the past about 20k ITick trait pairs were present during an average
multi player game.
Using an Apply function that takes an action avoid the need to create
these temporary objects.
To be able to still use 'DoTimed' somewhat efficiently the measurement
was moved to inside the trait container method.
Results in a 25% performance improvement in accessing all traits of
a certain type.
Apply function could be used for other TraitContainer functions as well
for further improvements.
Test result for calling on a dummy trait on 20k actors a 1000 times:
1315 ms traitcontainer.AllEnumerator (current)
989 ms traitcontainer.Apply (this commit)
UpdateShroud shows up in profile reports as one of the most
active methods (2.3% CPU time, main mono thread).
This commit introduces `anyCellDirty` to indicate that at lease one
of the cells was marked as dirty.
Avoiding the need to traverse all projected cells of the map
to find any dirty cell.
This reduces the number of shroud updates by at least 50% during a
test game. I assume this is related to renders occurring more
often than logic ticks(?).
Also added a configurable deploy cursor and fixed Minelayer target cell validation checks, which should make for a much better experiencing when dragging over an area with blocking terrain, shroud, fog, etc.
The Stream.ReadByte method is implemented by allocating a 1 byte buffer and calling into Read(byte[], int, int). Override ReadByte in derived classes to avoid needing to allocate this small temp buffer.
Also, fix some bugs in the stream implementations. Remove Write capability from MergedStream that didn't make sense. Add guards into SegmentStream to ensure reads and writes belonged to the segment - otherwise a reader or writer could access regions of the base stream that were outside the intended segment.
- Use the count to size the capacity of the list.
- Use a char array as a buffer, so will can build each string directly rather than needing a ToArray call first.
- Clone method will use the node count to create the correct capacity.
- ResolveInherits will use the node count as the suggested initial capacity.
- FromStream will now stream lines, rather than reading the whole file into memory and then splitting into lines.
- Avoid creating new strings in SpriteRenderer.Flush.
- ProductionQueue.CancelUnbuildableItems can exit early if the queue is empty. It can also use a set of names for quicker lookups.
- OpenGL.CheckGLError avoids a Enum.HasFlag call.
- VertexBuffer interface redefined to remove an IntPtr overload for SetData. This removes some unsafe code in TerrainSpriteLayer. This also allows the ThreadedVertexBuffer to use a buffer and post these calls, meaning the SetData call can now be non-blocking.
- ThreadedTexture SetData now checks the incoming array size. As the arrays sent here are usually large (megabytes) this allows us to avoid creating temp arrays in the LOH and skip Array.Copy calls on large arrays. This means the call is now blocking more often, but significantly reduces memory churn and GC Gen2 collections.
These config files often contain many repeated strings which result in different string references in memory. By using a pool, we can detect when the strings are equal and reuse an existing reference as strings are immutable.
The FromLines will now use a pool to de-duplicate strings for a single call. By allowing a pool to be provided as a parameter, we can reuse even more strings. The MapCache defines such a pool so that strings are reused across all maps in the cache for even more savings.
- Distinguish between missing sequences and missing sprites
- Lint default sequences as well as maps
- Improved performance
- Correctly handle null images
Cache armaments on creation, avoid LINQ.
Also merge and put first the DamageThreshold == 0
check in Damaged, because the common default IS 0,
so most of the time the IsTraitDisabled and
IsInWorld checks are redundant.
Instead of looking this up every Draw tick,
cache and update it only when a non-null new
CurrentQueue is set (as the overlays can only change
at that time).
Doesn't really make a difference, since it only matters
for effect warheads and those already could target both
air and ground actors, but GroundActor was still wrong.
Simplified and streamlined code,
based on past feedback and suggestions.
Note: The new methods will move to
Warhead later, once they're used by more
than one warhead.
The conjugate of a quaternion just negates the x/y/z components, so
there is no need to recalculate from scratch and throw away precision
by forcing a quat->euler->quat round trip.
This avoids precision loss when combining rotations.
The equivalent Euler angles are calculated for external use
but the quaternion components are preferred for any further
internal calculations.
This allows TraitInfos to act when the actor preview is placed
in the editor, returning arbitrary data which the editor stores
and gives back if the preview is removed.
The ImpactOrientation needs to be computed from
point of impact to target if the target wasn't hit directly.
Also adapted warhead code to use WarheadArgs consistently,
as well as pass HitShape instead of just HitShapeInfo
(both needed for future and/or downstream features).
Allows to pass the horizontal facing/yaw
and vertical angle/pitch of the carrier
projectile to warheads for further use.
Add ImpactPosition to WarheadArgs
InflictDamage doesn't pass the impact pos
directly, and the very point of WarheadArgs
is to avoid adding more and more arguments
to the warhead methods.
* Rename LeftColor and RightColor to MinColor and MaxColor
These are mapped from LowRadarColor and HighRadarColor in
the original inis, and appear to be used to set the bounding
values for selecting a random colour, NOT for left/right
pixels (which caused noticeably wrong banding).
* Adjust brightness based on terrain height.
MinHeightColorBrightness and MaxHeightColorBrightness
were chosen by trial/error to match the original
map preview rendering.
Also moved the InaccuracyType enum there. This also quietly adds the RangeModifiers to the calculations for all projectiles, while they were only used on Bullet so far, which seemed very wrong.
Also adjusted the inaccuracy values. This should bring inaccuracy in D2k pretty much in line with the original game, with the potential liberty of decreased inaccuracy for the Deviator tank.
Also updated the inaccuracy calculations to account for the new inaccuracy type - either based on distance up to a max defined inaccuracy at max range (old style) or based on distance with each cell (1024 range) increasing the inaccuracy with a set step.
- Add a property for arrows image collection (in drop-downs, scrollbars
and production tabs)
- Add a property for separators image collection (in drop-downs)
- Add hover and disable states to the drop-down separator
- Unify button, textfield and checkbox state suffixes
Inits that are logically singletons (e.g. actor
location or owner) should implement this interface
to avoid runtime inconsistencies.
Duplicate instances are rejected at init-time,
allowing simpler queries when they are used.
If a weapon was aiming at a target position rather
than an actor target, it would always check target types
of the terrain below, ignoring altitude (and therefore ignoring
"InvalidTargets: Air").
A shared ValueActorInit<T> is introduced to reduce duplication
in the most common init cases, and an ActorInitActorReference
allow actors to be referenced by map.yaml name.
While individual trait look-ups may be cheap,
if a large army that is currently standing still gets
its first move-including order, the look-ups of dozens
or even hundreds of actors may happen on the same tick.
Therefore this may help reducing that first-order lag spike,
at least a little bit.
This simplifies #12467.
Using a tree-exclusive amor type is far more efficient
than adding more warheads, which cost performance
due to their huge Spread
This also restores the 100% efficiency vs. trees for
some of the incendiary nuke warheads (which have
reduced efficiency vs. Wood since #13643).
Note: Atomic had two tree-only warheads with a Delay
of 15, I believe the first one to be a copy-paste error
and moved the damage to the regular SpreadDamage
with a Delay of 10.
No more sharing of target types between terrain
and actors (except bridges), removed 'Ground(Actor)'
from WaterActors (was only used by weapons/warheads,
which can just list both ground- and water types.
- only used for auto-targeting
- inconsistent with their fakes (which didn't have this)
- unnecessary, since the 'Ship' target type covers all
surface water actors we want to be auto-targetable by default,
while 'Structure' is enough to add syard/spen in AttackAnything.
- Missiles can now force-fire on water like other weapons
- Superweapons can now target empty water
- made Chemspray null InvalidTargets to avoid yaml-merge issues
- Improved APCGun effect warhead perf by ignoring actors
- removed stale Tiberium weapon mission overrides
1. Optimize & move "ammo" related function from "AirStates.cs" to StateBase.cs
2. Optimize & move "IsRearm" function from "AirStates.cs" to StateBase.cs, name changed to "IsRearming"
(optimized by reaperrr)
- Fix rendering issues
- Track particles in world pixels instead of screen pixels
- Removed un/underused fade in/out support
- Update wind once per tick instead of once per particle
- Make Particle struct readonly
- Removed implicit pip definitions and IPips interface.
New decoration traits have been added to render them.
Pip types are no longer hardcoded in OpenRA.Game.
- Decoration rendering is now managed by SelectionDecorations(Base),
which allows us to remove assumptions about the selection box
geometry from the decoration traits.
- RenderNameTag has been replaced by WithNameTagDecoration, which is
an otherwise normal decoration trait.
- Unify the configuration and reduce duplication between traits.
- Removed hardcoded references to specific selection box renderables.
- Remove legacy cruft.
SendParatroopers and SendParatroopersFrom are now deprecated.
The paratrooper actors themselves can be accessed using the
Trigger.OnPassengerExited trigger.
- Sprite.Bounds now refers to rectangles in the source image.
Use this when copying pixels, etc.
- Sprite.Size now refers to sizes in effective pixel coordinates.
Use this when rendering.
- Sheet.DPIScale has been removed.
- "Density" term is introduced to refer to the number of artwork
pixels per effective pixel.
This ensures that color picks that have multiple issues will
have them all checked at the same time, including ensuring that
the fix for one issue doesn't cause another issue.
Handling of the onError action has been changed from being called
at once to collecting the potential errors in a HashSet to deduplicate
them and then calling onError after a valid color has been found.
(Otherwise you would in the worst case get 256 error messages logged!)
If the picked color and a forbidden color are identical (like
if they both picked the same palette color and in the special case
when a picked color is outside of the allowed range and the method
returns the picked color as the forbidden color),
the vector between them is zero and the maths for adjusting
the color fails by hitting the iteration limit. This changes
the zero vector to the smallest possible vector in order to
avoid the issue.
This can result in some seriously close adjustments in the case of
picking identical palette colors, which might
be undesirable compared to picking a new palette color.
The failsafe in ColorValidator aborts after 255 iterations of
adjusting the color and picks a random color. This message makes it
clearer to the user. Results in two messages being displayed,
first one about adjusting and the about a random color pick.
- Build on Travis-CI macOS VM
- Sign and notarize for distribution
- Create macOS-specific files from generic sources during packaging
- Add volume icon
- Rename osx directory to macos
* 2x and 3x DPI artwork can be specified using
Image2x and Image3x in chrome.yaml.
* Images are rendered using bilinear interpolation.
* For non-integer screen scales, prefer downscaling
the next biggest resolution image over upscaling.
There was a lot of redundancy and unnecessary
complexity in several checks.
This now also prevents infantry from randomly
restarting and potentially switching between stand
sequences if there are no idle sequences.
Old behavior can still be replicated by listing
stand sequences as IdleSequences.
* AbortOnResupply will now cancel queued activities
in addition to the current attack.
* Resupply if no ammo is available during a standard attack.
* Don't resupply (move directly to target) if no ammo is available
during an attack move (C&C3 style).
This commit makes aircraft
- ignore any aircraft-specific orders while disabled
- show blocked move cursor while paused
- set speeds to zero while paused or disabled
Note: This commit only does the minimum changes
to implement PausableConditional, there are no
logic changes yet (like disabling movement on PauseOnCondition).
Waypoint17 is not at the map edge, waypoint7 is.
Also fixes a path, since waypoint20 -> waypoint10 is going back and makes no sense.
Going directly waypoint20 -> waypoint2 works and as compensation I added waypoint21 -> waypoint10 -> waypoint2.
More in line with our property naming conventions.
Additionally, added descs to ProneOffset and
ProneSequencePrefix, since at least the purpose of
the former isn't entirely clear without looking at the code.
These parts were identical duplicates, so I removed them
and made AudReader depend on ImaAdpcmReader instead.
Applied some style fixes while I was at it.
My assumption that the D2 mod would want,
let alone need Mods.D2k was wrong.
Meanwhile, it does need Mods.Cnc for at least
the Pak format as well, so this is a good enough
compromise.
Reducing the count of proprietary formats in Mods.Common.
Note: Moving ShpD2 to Mods.Cnc is intentional. RA/TD
use it for their original mouse shp files, and any D2(k) mod
will normally need Mods.Cnc anyway, while we can avoid
adding a Mods.D2k dependency to RA/TD this way.
While this is strictly speaking a D2 format, any
D2 mod is pretty much guaranteed to use Mods.D2k,
so this should be a good enough place to move it to.
By default WithDamageOverlay uses the actors'
palette, but RA's desert terrain uses the TD desert.pal
which isn't compatible with RA's fire animation shps.
Removes the 'activeMCVs' list since it was not useful.
The real bugfix is not iterating over 'activeMCVs' when issueing new orders
(this was previously needed for already discovered mcvs that stopped)
but over 'newMCVs' instead.
Replace Constants.CellCost and Constants.DiagonalCellCost with a dynamically calculated value based on the lowest cost terrain to traverse. Using a fixed value meant the pathfinder heuristics would be incorrect.
In the four default mods, the minimum cost is in fact 100, not 125. This increase would essentially allow the pathfinder to return suboptimal paths up to 25% longer in the worst case, but it would be quicker to do so.
This is exactly what Weighted A* does - overestimate the heuristic by some factor in order to speed up the search by checking fewer routes. This makes the heuristic inadmissible and it may now return suboptimal paths, but their worst case length is bounded by the weight. A weight of 125% will never produce paths more than 25% longer than the shortest, optimal, path.
We set the default weight to 25% to effectively maintain the existing, suboptimal, behaviour due to the choice of the old constant - in future it may prove a useful tuning knob for performance.
Fix MCV Manager glitch when restrict building area is enabled. It was checking if the location was close enough to the Base center instead of using the MCV Managers min and max ranges. This would cause it to often have no valid locations despite having a huge range.
Add PlaceDefenseTowardsEnemyChance trait to basebuilderbotmodule. This defeaults to 100 which is the current behavior. This change now allows you to set the chance that bots will place defenses evenly around the base like the AI in stock red alert and Tiberian sun did.
To avoid creating copied data in memory (e.g. via MemoryStream), this method can be used to reference offsets on files on disk, reducing memory requirements.
They were unused, their settings were wrong,
and even if fixed they'd make idle ants look
glitchy, because the game switches between
stand sequences randomly.
Any struct which overrides object.Equals(object obj) should implement IEquatable<T> to gain a more efficient Equals(T other) overload. This overload will be used by hashing collections like Dictionary which enables them to check equality without boxing the struct.
- Drop `os` in Eluant config as it's only used on Linux
- Make generic to help BSDs and Solaris
- Update OpenAL-CS and SDL2-CS to get the same
Exception of type `System.DllNotFoundException`: lua51.dll
TypeName=``
at (wrapper managed-to-native) Eluant.LuaApi.lua_newstate(Eluant.LuaRuntime/LuaAllocator,intptr)
at Eluant.LuaRuntime..ctor ()
at Eluant.MemoryConstrainedLuaRuntime..ctor ()
at OpenRA.Scripting.ScriptContext..ctor (OpenRA.World world, OpenRA.Graphics.WorldRenderer worldRenderer, System.Collections.Generic.IEnumerable`1[T] scripts)
at OpenRA.Mods.Common.Scripting.LuaScript.OpenRA.Traits.IWorldLoaded.WorldLoaded (OpenRA.World world, OpenRA.Graphics.WorldRenderer worldRenderer)
at OpenRA.World.LoadComplete (OpenRA.Graphics.WorldRenderer wr)
at OpenRA.Game.StartGame (System.String mapUID, OpenRA.WorldType type)
at OpenRA.Game.LoadShellMap ()
at OpenRA.Mods.Common.LoadScreens.BlankLoadScreen.StartGame (OpenRA.Arguments args)
at OpenRA.Game.InitializeMod (System.String mod, OpenRA.Arguments args)
at OpenRA.Game.Initialize (OpenRA.Arguments args)
at OpenRA.Game.InitializeAndRun (System.String[] args)
at OpenRA.Program.Main (System.String[] args)
On FreeBSD build fails, so check if `msbuild` exists without arguments.
$ gmake
command: wrong number of arguments
OpenRA requires the 'msbuild -verbosity:m -nologo' tool provided by Mono >= 5.4.
gmake: *** [Makefile:154: core] Error 1
# FreeBSD sh
$ command -v echo ls
command: wrong number of arguments
# dash
$ command -v echo ls
echo
# ksh, bash, zsh
$ command -v echo ls
echo
/bin/ls
- **Mod:** [e.g. Red Alert, Tiberian Dawn, Dune2000, ...]
#### Additional Information:
- Steps to reproduce
1. Step
2. Step
3. ...
- Logs
<!-- If you have a log (e.g. debug.log, exception.log), zip and attach it. -->
- OpenRA Replays
<!-- You have to zip it before you can attach it. When does the issue appear [e.g. 10:33]? -->
- Screenshots & Videos
<!-- You should be able to attach screenshots by drag&drop. Videos need to be uploaded to an external platform (e.g. https://www.youtube.com, https://www.dropbox.com) -->
about: Report unexpected behavior or any issues you experienced in OpenRA.
title: ''
labels: Bug
assignees: ''
---
<!-- This is a guideline that shall help you to include information we need to understand and fix the issue you experienced. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
<!-- Important: Help us to avoid duplicates and use the search function to find existing reports for your issue. Please do not submit duplicate reports! Try to help others to find your report by using a precise title. -->
## Issue Summary
<!-- Please provide a a clear and concise description of what the issue is below. -->
DESCRIPTION
## Reproduction
<!-- Please provide information about how the issue can be reproduced below. -->
STEPS TO REPRODUCE THE ISSUE
## Expected behavior
<!-- Please explain what you expected to happen below. -->
EXPECTED BEHAVIOR
## Screenshots / Screen recordings / Replays
<!-- If applicable, attach screenshots, screen recordings or replays to help explain your problem. -->
about: Report a game crash. Check the FAQ first https://github.com/OpenRA/OpenRA/wiki/FAQ#common-issues
title: My game crashed
labels: Crash
assignees: ''
---
<!-- This is a guideline that shall help you to include all the required information we depend on to investigate and fix game-breaking bugs. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
## System Information
<!-- Information about the operating system, engine version, game mod and package source are mandatory for investigating and fixing crashes. -->
- Operating System: OPERATING SYSTEM
- OpenRA Version: ENGINE VERSION
- OpenRA Mod: GAME MOD
- Source: Official download package OR self-compiled OR third-party package
- For self-compiled or third-party packages: Mono version
## Exception log
<!-- Please replace the placeholder below with the content of the exception.log file. The three backticks before and after the placeholder are used for formatting, so don't remove them. If you don't find the log folder consult https://github.com/OpenRA/OpenRA/wiki/FAQ#my-game-just-crashed. -->
```
PASTE LOG HERE
```
## Replay
<!-- If you have a replay file for the game that crashed, and it crashes again when you play it back, it will be a great help for us to fix the issue. Please compress the replay into a zip file and drag it here to include it in the report. -->
## Additional information
<!-- Please tell us below everything that you think is important for us to know about the crash. Specifically, what you were doing in the moment before the crash or ideally steps to reproduce it are very valuable information. -->
about: Describe what you think is missing or could be improved in OpenRA.
title: ''
labels: Idea/Wishlist
assignees: ''
---
<!-- This is a guideline that shall help you to describe your idea for a missing feature or enhancement. Please follow the instructions and replace any placeholders that are written in capital letters. Instructions like this comment will not be visible in your report. -->
<!-- Important: Help us to avoid duplicates and use the search function to find existing requests. Please do not submit duplicate requests! Try to help others to find your request by using a precise title. -->
## Motivation
<!-- Please provide a clear and concise description of the motivation behind the request. If your request is related to a problem or limitation, describe it below. -->
REQUEST MOTIVATION
## Proposed solution
<!-- Please describe your idea and how it is intended to address the motivation of your request. Provide a clear and concise description of the proposed changes. -->
PROPOSED SOLUTION
## Side effects
<!-- Changes often have side effects or unintended consequences. If you expect that your solution has any side effects, please describe them below. -->
EXPECTED SIDE EFFECTS
## Alternatives
<!-- Please outline any alternative solutions you have considered. -->
@@ -13,4 +13,4 @@ You can help speed up the review process by following a few steps:
* Respond to review comments as soon as you reasonably can. Reviewers will usually prioritize Pull Requests that are still fresh in their minds. Make sure to leave a comment when you push new changes, otherwise GitHub does not automatically notify reviewers!
* Leave a polite comment asking for reviews if a week or more has passed without feedback.
If you need any help you can ask in the #openra IRC channel on freenode (most active during European evenings).
If you need any help you can ask on Discord (https://discord.openra.net) or in the #openra IRC channel on Libera (not as active as Discord).
To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with MSBuild or use the Makefile analogue command `make all` scripted in PowerShell syntax.
To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with `dotnet` or use the Makefile analogue command `make all` scripted in PowerShell syntax.
Run the game with `launch-game.cmd`. It can be handed arguments that specify the exact mod one wishes to run, for example, run `launch-game.cmd Game.Mod=ra` to launch Red Alert, `launch-game.cmd Game.Mod=cnc` to start Tiberian dawn or `launch-game.cmd Game.Mod=d2k` to launch Dune 2000.
Linux
=====
Mono, version 5.4 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient.
.NET 6 or Mono (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project.
Use `make dependencies` to map the native libraries to your system and fetch the remaining CLI dependencies to place them at the appropriate places.
The [.NET 6 download page](https://dotnet.microsoft.com/download/dotnet/6.0) provides repositories for various package managers and binary releases for several architectures. If you prefer to use Mono, we suggest adding the [upstream repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version and the `msbuild` toolchain.
To compile OpenRA, run `make all` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod.
To compile OpenRA, run `make` from the command line (or `make RUNTIME=mono` if using Mono). After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod.
Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`.
The default behaviour on the x86_64 architecture is to download several pre-compiled native libraries using the Nuget packaging manager. If you prefer to use system libraries, compile instead using `make TARGETPLATFORM=unix-generic`.
Arch Linux
----------
If you choose to use system libraries, or your system is not x86_64, you will need to install [SDL 2](https://www.libsdl.org/download-2.0.php), [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm), [OpenAL](https://openal-soft.org/), and [liblua 5.1](http://luabinaries.sourceforge.net/download.html) before compiling OpenRA.
It is important to note there is an unofficial [`openra-git`](https://aur.archlinux.org/packages/openra-git) package in the Arch User Repository (AUR) of Arch Linux. If manually compiling is the way you wish to go the build and runtime dependencies can be installed with:
These can be installed using your package manager on various distros:
Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`.
macOS
=====
Before compiling OpenRA you must install the following dependencies:
[.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 unless you are running a very old version of macOS (10.9 through 10.14).
Use `make dependencies` to download pre-compiled native libraries for:
# dotnet clean and msbuild -t:Clean leave files that cause problems when switching between mono/dotnet
# Deleting the intermediate / output directories ensures the build directory is actually clean
clean:
@-$(RM_RF) ./bin ./*/obj
@-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
check:
@echo
@echo "Compiling in Debug mode..."
ifeq($(RUNTIME),mono)
# Enabling EnforceCodeStyleInBuild and GenerateDocumentationFile as a workaround for some code style rules (in particular IDE0005) being bugged and not reporting warnings/errors otherwise.
# Enabling EnforceCodeStyleInBuild and GenerateDocumentationFile as a workaround for some code style rules (in particular IDE0005) being bugged and not reporting warnings/errors otherwise.
@sh -c '. ./packaging/functions.sh; install_linux_shortcuts $(CWD) "$(DESTDIR)" "$(gameinstalldir)" "$(bindir)" "$(datadir)" "$(shell head -n1 VERSION)" cnc d2k ra'
install-linux-appdata:
@$(INSTALL_DIR)"$(DESTDIR)$(datadir)/appdata/"
@sed 's/{MODID}/ra/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Red Alert/g'| sed 's/{SCREENSHOT_RA}/ type="default"/g'| sed 's/{SCREENSHOT_CNC}//g'| sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-ra.appdata.xml
@sed 's/{MODID}/cnc/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Tiberian Dawn/g'| sed 's/{SCREENSHOT_RA}//g'| sed 's/{SCREENSHOT_CNC}/ type="default"/g'| sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-cnc.appdata.xml
@sed 's/{MODID}/d2k/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Dune 2000/g'| sed 's/{SCREENSHOT_RA}//g'| sed 's/{SCREENSHOT_CNC}//g'| sed 's/{SCREENSHOT_D2K}/ type="default"/g'> packaging/linux/openra-d2k.appdata.xml
thrownewInvalidOperationException("An activity was queued before the actor was created. Queue it inside the INotifyCreated.Created callback instead.");
if(CurrentActivity==null)
CurrentActivity=nextActivity;
else
@@ -227,8 +350,7 @@ namespace OpenRA
publicvoidCancelActivity()
{
if(CurrentActivity!=null)
CurrentActivity.Cancel(this);
CurrentActivity?.Cancel(this);
}
publicoverrideintGetHashCode()
@@ -238,8 +360,7 @@ namespace OpenRA
publicoverrideboolEquals(objectobj)
{
varo=objasActor;
returno!=null&&Equals(o);
returnobjisActoro&&Equals(o);
}
publicboolEquals(Actorother)
@@ -280,8 +401,7 @@ namespace OpenRA
{
// If CurrentActivity isn't null, run OnActorDisposeOuter in case some cleanups are needed.
// This should be done before the FrameEndTask to avoid dependency issues.
if(CurrentActivity!=null)
CurrentActivity.OnActorDisposeOuter(this);
CurrentActivity?.OnActorDisposeOuter(this);
// Allow traits/activities to prevent a race condition when they depend on disposing the actor (e.g. Transforms)
thrownewLuaException("Attempted to call CPos.Add(CPos, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name,right.WrappedClrType().Name));
thrownewLuaException("Attempted to call CVec.Add(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name,right.WrappedClrType().Name));
thrownewLuaException("Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name,right.WrappedClrType().Name));
thrownewLuaException($"Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({left.WrappedClrType().Name}, {right.WrappedClrType().Name})");
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.