Compare commits

...

1425 Commits

Author SHA1 Message Date
teinarss
857da21b0f Add support for dotnet core for Windows 2020-12-23 18:41:27 +01:00
teinarss
73bba97aaa Update MasterServerPinger to modern approach 2020-12-22 20:57:40 +01:00
abcdefg30
d6e9cdab5b Add the 9th Dark Tournament map as "Oil Spill" 2020-12-21 21:08:39 +01:00
Paul Chote
1a177bc2de Remove unused variables from Map.SavePreview. 2020-12-19 13:07:01 +01:00
Paul Chote
e0b3e631fe Remove obsolete null checks. 2020-12-19 13:07:01 +01:00
Paul Chote
2518a353af Add lint test for invalid map tiles. 2020-12-19 13:07:01 +01:00
Paul Chote
989800efff Fix missing tiles in upstream maps. 2020-12-19 13:07:01 +01:00
Paul Chote
c02846e2cb Replace invalid tiles on map load. 2020-12-19 13:07:01 +01:00
Matthias Mailänder
09db4a0e25 Enable debug mode by default. 2020-12-15 23:06:05 +01:00
Trevor Nichols
a85da9d86c Implement loader for MegV3 file format 2020-12-15 11:11:05 +01:00
Paul Chote
920d00bbae Use nearest-neighbour scaling in --debug-chrome-regions utility command. 2020-12-14 22:38:25 +01:00
Ivaylo Draganov
62475279ee Remove unneeded chrome yaml declarations 2020-12-14 20:52:38 +01:00
Matthias Mailänder
d8e979d283 Remove dead code. 2020-12-14 20:38:50 +01:00
Paul Chote
299b8880dd Fix api output directory. 2020-12-14 18:33:35 +01:00
Paul Chote
61027e4067 Fix docs.openra.net repository reference. 2020-12-14 18:33:35 +01:00
Paul Chote
a7249c10dc Fix docs.openra.net documentation workflow. 2020-12-13 15:35:31 +01:00
Paul Chote
611d12ac78 Migrate CI and packaging from Travis CI to GitHub Actions. 2020-12-12 20:17:29 +00:00
abcdefg30
ef9f26a60d Fix MissionObjectives not properly ending the game 2020-12-12 14:59:49 +01:00
abcdefg30
aeaffc0a8e Properly restrict the spectator view in mission maps 2020-12-12 14:59:49 +01:00
Paul Chote
e3084e230e Switch mirror for nsis3 package. 2020-12-12 14:54:50 +01:00
Paul Chote
4c01c772f8 Fix incorrect animation playing when moving infantry stop to attack. 2020-12-12 14:40:13 +01:00
Paul Chote
ed94f7680a Revert "Fix WithInfantryBody wrongly overwriting attack animations"
This reverts commit 1a63cc4a41.
2020-12-12 14:40:13 +01:00
yuantse
408d66cdaf Add Allies 09a 2020-12-12 13:18:08 +01:00
Smittytron
c4a0f2f169 Add Counterstrike mission Sarin Gas 3: Controlled Burn 2020-12-12 13:15:18 +01:00
Paul Chote
26b28d26da Prevent Civilians from wandering onto Tiberium. 2020-12-12 12:54:46 +01:00
Paul Chote
8ded6dafd4 Add AvoidTerrainTypes to ScaredyCat. 2020-12-12 12:54:46 +01:00
Paul Chote
57a94ad667 Add AvoidTerrainTypes to Wanders. 2020-12-12 12:54:46 +01:00
Paul Chote
53933a4d8f Fix restart black screen race condition. 2020-12-11 22:57:57 +01:00
Paul Chote
6606d7dd93 Add DisplayFaction details to the replay metadata. 2020-12-11 18:05:44 +01:00
Paul Chote
7a256dcafa Fix rally point target line exit display. 2020-12-11 17:25:30 +01:00
abcdefg30
7899c52b6d Add an update rule 2020-12-11 17:13:02 +01:00
abcdefg30
919c670502 Update the rules of the default mods 2020-12-11 17:13:02 +01:00
abcdefg30
aac3174efc Rename Stances to Relationships in the yaml api 2020-12-11 17:13:02 +01:00
Paul Chote
a8d3d5c79a Fix Neutral crushing checks. 2020-12-08 20:17:11 +01:00
Paul Chote
7c852d90fb Ignore aircraft when searching for enemy targets. 2020-12-07 23:39:22 +01:00
Paul Chote
269ce9c406 Exclude carryalls from AI squads. 2020-12-07 23:39:22 +01:00
Paul Chote
53d98ec255 Abort squad states that are not able to move. 2020-12-07 23:39:22 +01:00
Paul Chote
7a7cd21578 Fix TD SAM Site facings being reset when damaged while closed. 2020-12-07 01:44:04 +01:00
abcdefg30
2b363e4e1c Fix WithInfantryBody wrongly overwriting attack animations 2020-12-07 00:29:16 +01:00
Paul Chote
b1560ae69c Overhaul packaging scripts and helpers:
- 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.
2020-12-06 17:16:47 +01:00
Paul Chote
f3ebe07540 Fix WithDeliveryAnimation overriding sell animation. 2020-12-06 09:49:40 +01:00
Orb
6cac587753 ST Death Explosion Change Commit 2020-12-06 09:47:22 +01:00
Paul Chote
09e6cc4add Enable dark mode support on macOS. 2020-12-05 17:09:32 +00:00
Paul Chote
5a2f91be1c Fix building bibs not blocking placement. 2020-12-05 17:06:04 +00:00
Paul Chote
25071b813e Prevent concrete from spawning underneath already placed building bibs.
This is the equivalent to reverting 83b61ab.
2020-12-05 17:06:04 +00:00
Paul Chote
d61bd675c4 Revert "Remove BuildingInfluence from ResourceLayer."
This reverts commit 1634f3b70e.
2020-12-05 17:06:04 +00:00
Paul Chote
582e2774ac Revert "Remove BuildingInfluence from building adjacency check."
This reverts commit 33a1ca5965.
2020-12-05 17:06:04 +00:00
Paul Chote
5a52ce5330 Revert "Remove BuildingInfluence trait."
This reverts commit 34bf143328.
2020-12-05 17:06:04 +00:00
abcdefg30
31c9b4fc80 Revert renderable buffer sorting improvements 2020-12-05 17:03:03 +00:00
abcdefg30
4953ce314b Make Attack turn during its own tick 2020-12-05 16:41:30 +00:00
Paul Chote
86519bfda5 Expose Player.HomeLocation to the Lua API. 2020-12-05 14:14:56 +01:00
teinarss
2c9a36b9a3 Update float3 to readonly and use in modifier for parameters. 2020-12-02 20:37:50 +01:00
Paul Chote
d3847d49ed Fix windows package filenames. 2020-12-02 19:41:24 +01:00
Paul Chote
57f40a0b20 Remove obsolete variable definition. 2020-12-02 19:41:24 +01:00
Paul Chote
fa05f4e4b0 Generate Unicode-aware Windows installers. 2020-12-02 19:41:24 +01:00
Paul Chote
754f41ecd1 Remove redundant python check from Linux package creation. 2020-12-02 19:41:24 +01:00
Paul Chote
4b6e1c2198 Add a utility wrapper script for non-Windows. 2020-12-02 16:57:51 +01:00
teinarss
e6db2c98d0 Make WRot readonly and use in parameter modifier 2020-12-01 22:54:39 +00:00
Paul Chote
942f1e2d9e Fix infantry ignoring the default subcell when produced.
They were being created with the correct subcell, but was rejecting it
as invalid because it was already occupied (by the unit itself).
2020-12-01 22:39:11 +01:00
Paul Chote
da5c94858f Evaluate exit distance from the exit cell instead of the spawn position. 2020-12-01 22:35:43 +01:00
Paul Chote
77ffc20a5f Convert Attack*.FacingTolerance to WAngle. 2020-11-30 16:39:48 +01:00
abcdefg30
d75fed3a00 Replace chan with c10 in actors spawned from selling RA tech buildings 2020-11-30 01:07:36 +01:00
Matthias Mailänder
2aba054fe8 Move it to the right folder. 2020-11-29 18:27:59 +01:00
Paul Chote
3b1f4ba07f Fix production exit desync. 2020-11-28 17:49:36 +01:00
Paul Chote
d35768e0f9 Rework Windows launchers:
- 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.
2020-11-27 20:32:02 +01:00
Paul Chote
07a10069db Introduce new OpenRA.exe entrypoint and change OpenRA.Game to a library. 2020-11-27 20:32:02 +01:00
Paul Chote
20fe59e844 Output compiled binaries to ./bin. 2020-11-24 17:53:48 +01:00
Paul Chote
6ad5b9ebc4 Allow the game root directory to be moved away from the binaries. 2020-11-24 17:53:48 +01:00
Paul Chote
dd0b08d54a Replace ^ and . in platform paths with ^SupportDir and ^EngineDir. 2020-11-24 17:53:48 +01:00
Paul Chote
1cc1f93fb0 Rename Platform.GameDir to Platform.EngineDir. 2020-11-24 17:53:48 +01:00
Paul Chote
72f1f06ebc Remove Platform.UnresolvePath. 2020-11-22 16:42:46 +01:00
Paul Chote
151cea96e9 Remove Platform.IsPathRelativeToSupportDirectory. 2020-11-22 16:42:46 +01:00
Paul Chote
888915b53b Use Platform.GameDir explicitly in hardcoded paths. 2020-11-22 16:42:46 +01:00
Paul Chote
de7a84e8ed Don't use Platform.ResolvePath when constructing hardcoded paths. 2020-11-22 16:42:46 +01:00
Paul Chote
1dd5b113c7 Fix asset browser and map editor paths for SDK-based mods. 2020-11-22 16:42:46 +01:00
Paul Chote
e9ad38667e Expose TransformsInto* targetline colors to yaml. 2020-11-21 14:52:54 +01:00
abcdefg30
05e8026713 Remove or use unused variables in TransformsIntoAircraft 2020-11-20 23:12:44 +01:00
abcdefg30
5b75649888 Fix TransformsIntoAircraft transforming on all orders 2020-11-20 23:12:44 +01:00
Matthias Mailänder
c22392eb1e Enable itch app auto updates on Windows. 2020-11-17 19:46:28 +01:00
dnqbob
7c2a51df38 Make OrderGenerator flexible on mouse input for modder 2020-11-17 19:18:04 +01:00
reaperrr
05cb9b1fbf Fix dock sequence dock/undock notifications
- move Refinery dock/undock notifications to OnStateDock/-Undock
and only call Undock if Dock was also called.
- Add INotifyHarvesterAction support to VoxelHarvesterDockSequence.
2020-11-15 16:56:28 +01:00
reaperrr
6bba35c330 Fix TS harvesters getting stuck in unload graphics
when refinery is destroyed while unloading.
2020-11-15 16:56:28 +01:00
reaperrr
90d9ee1f5c Fix harv dock sequence issuing drag despite cancellation 2020-11-15 16:56:28 +01:00
reaperrr
385f01247b Fix harvs dragging to refinery even if it died while turning 2020-11-15 16:56:28 +01:00
reaperrr
996029ee38 Fix undock anim playing even if docking was cancelled
...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).
2020-11-15 16:56:28 +01:00
reaperrr
87929b3d91 Fix dock animation continuing after refinery died
OnStateDock would always be triggered, even if the
refinery was killed before the harvester would finish
docking.
2020-11-15 16:56:28 +01:00
abcdefg30
e7e50cc101 Remove WorldUtils.AreMutualAllies 2020-11-15 16:37:51 +01:00
abcdefg30
d6c0926856 Remove LaysTerrain 2020-11-15 16:33:32 +01:00
abcdefg30
99ec119ffd Move LaysTerrain functionality to D2kBuilding 2020-11-15 16:33:32 +01:00
abcdefg30
6b2920cc91 Introduce D2kBuilding 2020-11-15 16:33:32 +01:00
abcdefg30
05f933f007 Add an update rule for the DamagedByTerrain refactor 2020-11-15 16:33:32 +01:00
abcdefg30
80aeb5ada6 Refactor DamagedByTerrain 2020-11-15 16:33:32 +01:00
abcdefg30
83ea65d4ff Require IOccupySpace for DamagedByTerrain 2020-11-15 16:33:32 +01:00
Paul Chote
46b3b01b89 Fix WithVoxelBarrel orientation calculations. 2020-11-15 13:51:12 +00:00
Orb
973f679939 TD Veterancy Adjustment Commit 2020-11-15 09:46:54 +01:00
abcdefg30
6de1b7b915 Always mark defeated/victorious players as spectating 2020-11-15 09:45:16 +01:00
Orb
e7ce739fec TD Fix Repair Times Commit 2020-11-15 09:42:21 +01:00
abcdefg30
bf14a4ce80 Remove an unused variable from LoadComplete 2020-11-15 09:38:02 +01:00
abcdefg30
8840a690c6 Fix maps without spawn points no longer working 2020-11-15 09:38:02 +01:00
abcdefg30
77e85e7c58 Change DisabledSpawnPoints from List to HashSet 2020-11-15 09:38:02 +01:00
Pavol Molnar
6943cf5ad5 fixed tooltip, issue 18301 2020-11-15 09:36:56 +01:00
Vapre
17996dfdfc Shroud, access ProjectedCellLayer by array index. Shroud.touchedCount to avoid Tick updates.
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.
2020-11-14 18:33:49 +00:00
reaperrr
7f32776701 Fix some RA effect warheads ignoring water actors 2020-11-14 16:06:21 +01:00
reaperrr
fce109a46d Fix piff anims of Sniper and SilencedPPK weapons 2020-11-14 16:06:21 +01:00
reaperrr
748292324a Update RA/TD light guns cosmetic effects
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.
2020-11-14 16:06:21 +01:00
reaperrr
efe0de2ecb Move around TD Pistol yaml
Feels more organized if located below the inherited
^LightMG, like all other inheritors.
2020-11-14 16:06:21 +01:00
reaperrr
cac9940736 Support 'inaccuracy' on effect warhead
Purely cosmetic, allows to 'fake' slight inaccuracy without
affecting game balance on weapons like light machine guns.
2020-11-14 16:06:21 +01:00
abcdefg30
559b143265 Use FlyForward for strafing 2020-11-14 12:50:02 +00:00
abcdefg30
a66305e282 Fix the constructor order of FlyForward 2020-11-14 12:50:02 +00:00
abcdefg30
b3aa61ee8e Make fields readonly where possible 2020-11-14 12:50:02 +00:00
abcdefg30
80436a3195 Add a distance based constructor to FlyForward 2020-11-14 12:50:02 +00:00
abcdefg30
5127a6813d Rename FlyTimed to FlyForward 2020-11-14 12:50:02 +00:00
tovl
84eb3c54ef Expose targetline colors to yaml.
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.
2020-11-14 12:04:19 +00:00
abcdefg30
ea3c7a3c34 Remove the Stances dictionary 2020-11-14 11:04:41 +00:00
abcdefg30
718cf37146 Misc code improvements 2020-11-14 11:04:41 +00:00
abcdefg30
10f645bf77 Replace usage of the Stances dict by a method call 2020-11-14 11:04:41 +00:00
abcdefg30
eda9966d27 Rename Stance to PlayerRelationship 2020-11-14 11:04:41 +00:00
abc013
672172d1f1 Add missing PlayNotification calls to SelectTarget. 2020-11-12 19:52:06 +00:00
abcdefg30
a366e37014 Fix angles in the Descriptions of TDGunboat 2020-11-10 20:32:08 +01:00
Trevor Nichols
d66e0bb22e Right click lobby spawns to disable or remove players. 2020-11-07 19:33:28 +01:00
teinarss
13581c030d Use in parameter for Target 2020-11-06 22:02:24 +01:00
teinarss
13a8b6bda2 Make Target readonly 2020-11-06 22:02:24 +01:00
Paul Chote
3aaaa95618 Apply range modifiers to Missile RangeLimit. 2020-11-05 19:15:13 +01:00
abcdefg30
e3929d7ded Fix reservable crashing when unreserving and attack moving 2020-11-05 13:22:22 +01:00
teinarss
2c62f747d9 Fix style in issue template config 2020-11-04 23:26:04 +01:00
teinarss
e08818cca1 Update issue template with links to FAQ 2020-11-04 23:26:04 +01:00
Matthias Mailänder
b4670345dd Don't crash when the bullet bounces outside of the map. 2020-11-04 10:59:55 +01:00
abcdefg30
0320dcdef9 Revise the RA map pool 2020-11-02 21:32:25 +00:00
Mustafa Alperen Seki
8b12cce250 Disable neutral Oil Derricks in TD and RA. 2020-11-02 21:27:37 +00:00
Mustafa Alperen Seki
6bb7ab0f97 Add GrantConditionOnCombatantOwner. 2020-11-02 21:27:37 +00:00
Matthias Mailänder
b32346d65f Add a range marker to the nuke targeter. 2020-11-02 10:13:29 +00:00
darkademic
8f9c212921 Make AI randomly select from map squares with above average attractiveness when using support powers. 2020-11-01 21:20:00 +00:00
Orb
df39d4fcc4 TD Map Pool 2020 Commit 2020-11-01 19:21:23 +00:00
RoosterDragon
4daa5193b6 Use tie breaks for sort order in WorldRenderer.GenerateRenderables 2020-11-01 19:00:20 +00:00
abc013
13596c1474 Add offset to Explodes. 2020-10-31 17:48:21 +01:00
abc013
bb71b59e18 Improve explosion determination. 2020-10-31 14:55:13 +01:00
abc013
f2797c711c Add InvalidBounceTerrain parameter to Projectile. 2020-10-31 14:55:13 +01:00
Paul Chote
6b6b1e56e6 Resolve random players and spawn points in server replays. 2020-10-31 14:31:44 +01:00
abcdefg30
7b75a78e38 Fix free-of-charge repairing still costing credits 2020-10-30 15:12:47 +01:00
Taryn Hill
2cea4b26e8 vscode debugging: build before launching 2020-10-30 13:58:05 +01:00
dnqbob
48f4a98c6a Fix AI air squad misbehaving in TS maps
Change Cpos to Mpos by Pchote
2020-10-30 09:20:01 +01:00
Paul Chote
9ddc9073c2 Revert "Determine stance for spectators based on shroud selection"
This reverts commit e459fde031.
2020-10-30 08:36:23 +01:00
abcdefg30
774f2e0852 Fix Production.cs not properly using INotifyCreated 2020-10-29 21:42:03 +00:00
abcdefg30
f5a963ac47 Production now uses nearest exit to rally point. 2020-10-29 21:42:03 +00:00
Vapre
38f1f1e5c2 Replace TraitContainer.AllEnumerator with ApplyToAll.
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)
2020-10-29 21:21:12 +00:00
Mustafa Alperen Seki
4cdbf74256 Add Align: to SupportPowerTimerWidget. 2020-10-29 19:46:51 +01:00
Andrew Odintsov
bd0738c5c4 Determine stance for spectators based on shroud selection 2020-10-26 23:39:42 +00:00
Paul Chote
72c82cb080 Remove BuildingInfluence trait. 2020-10-26 16:51:12 +01:00
Paul Chote
b9dd59cd63 Remove BuildingInfluence from building adjacency check. 2020-10-26 16:51:12 +01:00
Paul Chote
79019b06ca Remove BuildingInfluence from Plug placement. 2020-10-26 16:51:12 +01:00
Paul Chote
90b25be1b6 Remove BuildingInfluence from ResourceLayer. 2020-10-26 16:51:12 +01:00
Paul Chote
e4faa6b0f0 Remove BuildingInfluence from Aircraft. 2020-10-26 16:51:12 +01:00
Paul Chote
1a3dfdc67f Remove BuildingInfluence from LaysTerrain. 2020-10-26 16:51:12 +01:00
Paul Chote
8d2156fb30 Remove BuildingInfluence from BuildableTerrainLayer. 2020-10-26 16:51:12 +01:00
Paul Chote
5e032edd28 Remove redundant BuildingInfluence checks.
Buildings are already excluded by the ActorMap checks.
2020-10-26 16:51:12 +01:00
Vapre
63d597e4ad ShroudRenderer UpdateShroud only when at least one cell is dirty.
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(?).
2020-10-25 23:01:19 +01:00
Pavel Penev
4135045ca4 Added valid TerrainTypes to the Minelayer trait
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.
2020-10-24 12:20:15 +02:00
abcdefg30
538623c835 Add a lint check for player counts 2020-10-24 10:09:22 +02:00
abcdefg30
3674583053 Throw an exception at load when a map has more than 64 players 2020-10-24 10:09:22 +02:00
Paul Chote
daa8c74c37 Improve Replaceable logic:
- Remove BuildingInfluence checks
- Support multiple Replaceable/Replacement traits on the same actors
- Fix description typos
2020-10-22 22:15:43 +02:00
Mustafa Alperen Seki
8aeec24c9b Add DamageTypes to Demolition 2020-10-21 18:41:16 +02:00
RoosterDragon
54c4a05062 Classes derived from Stream override ReadByte.
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.
2020-10-20 22:53:32 +02:00
RoosterDragon
466de89e17 PackageEntry.HashFilename avoids stream reads .
Operate directly on the array to avoid overhead of stream reads.
2020-10-20 22:53:32 +02:00
RoosterDragon
6eaf51d450 CursorManager avoids use of BitConverter.
Avoid allocating a small temp array via BitConverter.GetBytes, and instead use bitwise ops to isolate the components of the color.
2020-10-20 22:53:32 +02:00
RoosterDragon
7c8dc5d5f4 XccGlobalDatabase allocation improvements
- 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.
2020-10-20 22:53:32 +02:00
RoosterDragon
4f34d3edb3 Improvements in MiniYaml allocation
- 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.
2020-10-20 22:53:32 +02:00
RoosterDragon
0efdbc762d Avoid ReadBytes calls in some StreamExts methods.
Read individual bytes to avoid allocating small temp arrays.
2020-10-20 22:53:32 +02:00
Matthias Mailänder
5e42c03afc Replace more \n characters with write lines. 2020-10-19 22:37:01 +01:00
Matthias Mailänder
58726160a9 Reduce the indention level to show the table of contents. 2020-10-19 22:37:01 +01:00
Matthias Mailänder
8cd9215756 Add an additional new line before the unordered list. 2020-10-19 22:37:01 +01:00
Orb
0e33640b14 Code Polish TD Commit 2020-10-19 13:33:25 +02:00
reaperrr
a1c8cbab0b Enable recoil anim on RA/TD Gun Turrets 2020-10-18 20:39:22 +02:00
reaperrr
50b484df56 Fix RA/TD defense turrets facing issues
By using WithSpriteTurret instead of
WithEmbeddedTurretSpriteBody.
2020-10-18 20:39:22 +02:00
reaperrr
99facd2797 Fix default facing of RA/TD Gun Turrets
Compare with make anim and original, 224 was
one facing too far.
2020-10-18 20:39:22 +02:00
Paul Chote
f79e1cacf0 Fix and document FMV scanline rendering. 2020-10-18 20:15:11 +02:00
Paul Chote
82069db724 Fix FMV aspect ratio. 2020-10-18 20:15:11 +02:00
Paul Chote
5a7dc385a3 Remove obsolete LocomotorInfo caching. 2020-10-18 18:19:56 +02:00
darkademic
49e7a33db0 Fixed WithRangeCircle when Visibility is set to Always. 2020-10-18 18:06:22 +02:00
Paul Chote
90b26681eb Remove trait queries from Actor ctor. 2020-10-18 18:00:17 +02:00
Matthias Mailänder
14fc0254c6 Make all range circles fully configurable. 2020-10-18 15:08:17 +01:00
Matthias Mailänder
214aa64ce3 Fix Analyzer warning: V3128 field is used before initialized 2020-10-18 14:53:35 +01:00
abcdefg30
a7bb217887 Make the calculation of DesiredLocalFacing more readable 2020-10-18 14:48:05 +01:00
abcdefg30
10cb8090ec Remove the second arrow on the preview of gdi08a 2020-10-18 14:33:52 +01:00
abcdefg30
1fdecb4e9d Fix briefing text and video of nod04a 2020-10-18 14:33:52 +01:00
abcdefg30
575596c9ad Fix map previews and order in TD 2020-10-18 14:33:52 +01:00
RoosterDragon
e11c8436bd Misc changes to reduce allocation:
- 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.
2020-10-17 23:48:48 +02:00
RoosterDragon
c23efea402 Comments to justify GC.Collect calls, compact LOH during load. 2020-10-17 23:48:48 +02:00
RoosterDragon
8d3cec5bea When a render method has nothing to render, eagerly return.
By eagerly returning an empty enumerable in these cases, this avoids allocating an enumerable for the whole render method if nothing will be drawn.
2020-10-17 23:48:48 +02:00
RoosterDragon
87389d3051 Reuse a list in FrozenActor.RefreshState 2020-10-17 23:48:48 +02:00
RoosterDragon
71e3ca4493 Sort renderables in-place in WorldRenderer.GenerateRenderables 2020-10-17 23:48:48 +02:00
RoosterDragon
2adee1e374 Use HasMovementType to avoid Enum.HasFlag allocations. 2020-10-17 23:48:48 +02:00
RoosterDragon
094ccf76b0 Prefer Min/MaxBy overloads to OrderBy().First() patterns 2020-10-17 23:48:48 +02:00
RoosterDragon
bb116034c7 Avoid or reduce LINQ allocations required in various areas. 2020-10-17 23:48:48 +02:00
Paul Chote
da53d5b776 Fix a divide by zero crash in Move. 2020-10-17 22:31:35 +02:00
abcdefg30
75fe0e524f Fix units not attack moving to waypoints after resupply/takeoff 2020-10-17 19:48:54 +01:00
Matthias Mailänder
0ded0355c1 Allow mod code to set rally point indicators. 2020-10-16 18:14:33 +01:00
Matthias Mailänder
4da14cee0a Disable UPnP on local games. 2020-10-16 18:14:33 +01:00
Orb
90c8e112e2 Stealth C17 Checkbox 2020-10-16 18:09:43 +01:00
Orb
d49bf81d95 TD Balance 2020 3 Commit 2020-10-16 17:52:41 +01:00
abcdefg30
abbe16b6ec Remove default parameters 2020-10-15 10:53:06 +02:00
abcdefg30
274bf06eae Fix evacuated civilians not staying at the GDI base 2020-10-15 10:53:06 +02:00
abcdefg30
dcf7b6b3f6 Add an alternative escape route to the south 2020-10-15 10:53:06 +02:00
abcdefg30
4173e40a9d Use actor names instead of searching for actors with a type 2020-10-15 10:53:06 +02:00
abcdefg30
1abd272862 Fix actor naming since those are not Nod soldiers 2020-10-15 10:53:06 +02:00
abcdefg30
946bf7b9fa Let civilians flee away from - not towards - the player in Nod04b 2020-10-15 10:53:06 +02:00
Matthias Mailänder
0d64fa549b Fix the command bar selecting dead units
and crashing while doing a trait lookup on them.
2020-10-14 19:58:24 +02:00
abcdefg30
8a7020b4ef Ignore the length requirement of sync orders we want to drop 2020-10-14 19:53:49 +02:00
abcdefg30
1bc19e788c Drop and log sync orders with mismatching length 2020-10-14 19:53:49 +02:00
abcdefg30
c17110dac5 Make OrderManager fields readonly where possible 2020-10-14 19:53:49 +02:00
abcdefg30
d07b34e67e Style fixups in ReplayConnection.cs 2020-10-14 19:53:49 +02:00
abcdefg30
accecee018 Fix savegames not saving sync packets correctly 2020-10-14 19:53:49 +02:00
abcdefg30
1861174d38 Add a Order.SyncHashOrderLength const 2020-10-14 19:53:49 +02:00
Curtis Shmyr
8d5ed65feb Remove effective owner check when choosing armament 2020-10-14 19:52:34 +02:00
Paul Chote
a375f0e58a Rewrite spawn point assignment logic. 2020-10-13 20:41:39 +02:00
RoosterDragon
b2b639434c ThreadedGraphicsContext improvements.
- 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.
2020-10-13 15:54:53 +02:00
Curtis Shmyr
5eadd26f66 Set lobby bool display values to start uppercase 2020-10-12 22:05:35 +02:00
Curtis Shmyr
c0cbca26ea Use lobby option display values when clients join 2020-10-12 22:05:35 +02:00
RoosterDragon
8fb65fd9bf Use string pooling in MiniYaml to de-duplicate strings in memory.
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.
2020-10-12 21:57:08 +02:00
RoosterDragon
9072d645fd Use TrimExcess to shrink lists used by MiniYaml after loading 2020-10-12 21:57:08 +02:00
Paul Chote
597b8b1caa Hide legacy GL support behind a feature flag. 2020-10-12 12:24:22 +02:00
Paul Chote
2c0d512727 Package and default to GLES via ANGLE on windows. 2020-10-12 12:24:22 +02:00
Paul Chote
87c5cc96ad Add an "Automatic" GL profile. 2020-10-12 12:24:22 +02:00
Paul Chote
fc844cfa6d Print the GL_RENDERER string to stdout on engine start. 2020-10-12 12:24:22 +02:00
Paul Chote
1ab1c30e39 Remove glGetTexImage/glBindFragDataLocation on GLES.
These functions are not available in GLES3.
2020-10-12 12:24:22 +02:00
reaperrr
f2a1a497c7 Fix Pillbox damage
These were overlooked during the RA target type
refactor.
2020-10-12 11:56:55 +02:00
Paul Chote
1ddbe50b3f Add inline node inclusion support to mod.yaml. 2020-10-11 01:42:59 +02:00
Paul Chote
dd7b8b24af Use tileset ID in sequences instead of the TileSet object. 2020-10-11 01:23:15 +02:00
abcdefg30
6dcb701d1d Fix a crash in AIUtils 2020-10-10 17:54:55 +02:00
reaperrr
f67b7ad837 Cache IResolveOrder traits on Actor
Avoids looking up all of them each time
an actor is given an order.
2020-10-10 13:59:40 +01:00
reaperrr
a4a409f39b Pass world directly to UnitOrders.ResolveOrder
Avoids order.Subject.World look-ups.

Also removes validOrders parameter,
we can get that directly from World now.
2020-10-10 13:59:40 +01:00
reaperrr
904a5f60d1 Cache IOrderValidator traits on World 2020-10-10 13:59:40 +01:00
dnqbob
ca8341d432 Avoid WaterCheck crash in base builder 2020-10-10 11:44:43 +02:00
Clément Bœsch
815bbc6ee8 Save disconnect frame in the GameInformation
This information is useful to infer a winner in case the winstate is
unknown.
2020-10-10 01:17:39 +02:00
Clément Bœsch
ca8870a5cf Server: handle wins/losses using Sync hash
Signed-off-by: Paul Chote <pchote@users.noreply.github.com>
2020-10-10 01:17:39 +02:00
Clément Bœsch
e5da58e2b4 Server: add basic replay recording
Signed-off-by: Paul Chote <pchote@users.noreply.github.com>
2020-10-10 01:17:39 +02:00
Paul Chote
dd18829def Traits: add ICreatePlayersInfo
Signed-off-by: Clément Bœsch <u@pkh.me>
2020-10-10 01:17:39 +02:00
Paul Chote
41814a881d Player: move player name resolve in a dedicated function
Signed-off-by: Paul Chote <pchote@users.noreply.github.com>
2020-10-10 01:17:39 +02:00
Clément Bœsch
d708f46d50 Orders: make SyncHash packet size check more accurate 2020-10-10 01:17:39 +02:00
Clément Bœsch
11f57b2b26 Protocol: add defeat state bitfields to Sync packets
Signed-off-by: Paul Chote <pchote@users.noreply.github.com>
2020-10-10 01:17:39 +02:00
Paul Chote
60df247416 Streamline SpawnOccupant management. 2020-10-09 12:19:19 +02:00
Trevor Nichols
6f32196f89 Support List<> for FieldSaver/FieldLoader 2020-10-07 22:04:10 +02:00
abcdefg30
d647aab7fe Fix d2k conyards granting an unconsumed "auto-concrete" condition 2020-10-06 23:25:12 +01:00
Mustafa Alperen Seki
be88c33399 Add a lobby option to disable Concrete in D2k. 2020-10-06 13:29:33 +02:00
Mustafa Alperen Seki
7372da150a Make LaysTerrain Conditional. 2020-10-06 13:29:33 +02:00
Mustafa Alperen Seki
3ec3eac160 Don't StartOnThreshold if the trait is disabled. 2020-10-06 13:29:33 +02:00
reaperrr
0990caefd7 Fix turreted defenses always realigning
This looks weird, doesn't match the originals
and makes map-defined custom facings useless.
2020-10-06 12:53:11 +02:00
Paul Chote
fc1786e243 Fix turrets immediately realigning on actor creation. 2020-10-05 15:13:48 +02:00
Matthias Mailänder
7e61199458 Fix a link in the Lua documentation. 2020-10-05 10:11:30 +02:00
Paul Chote
0672553a07 Lock Server.LobbyInfo to prevent races with callback threads. 2020-10-04 20:31:07 +02:00
reaperrr
8d1f72c104 Fix for SquadManagerBotModule
Aircraft and ships are immediately assigned a squad,
so adding them to `unitsHangingAroundTheBase` is bogus.
2020-10-04 00:31:35 +01:00
reaperrr
6337067032 Clean up property names + defaults of smudge smoke 2020-10-02 23:46:48 +02:00
reaperrr
7395a3ed2d Use cached world instead of query in SmudgeLayer 2020-10-02 23:46:48 +02:00
abcdefg30
e4e1878a4b Remove an used TerrainTemplateInfo constructor 2020-10-02 12:09:42 +02:00
abcdefg30
cc8908d7eb Make ProductionParadrop and ProductionAirdrop refund undelivered actors 2020-10-02 11:51:48 +02:00
abcdefg30
0dac4520ad Add a 'refundableValue' parameter to 'Produce' 2020-10-02 11:51:48 +02:00
Paul Chote
cc2e369475 Fix corrupted final frame in VQA playback. 2020-10-02 11:37:00 +02:00
tovl
92189e4b50 Let docking angle be determined by the host building. 2020-10-02 11:28:14 +02:00
abcdefg30
2e8c85ff0b Add support for querying the Passengers of an actor via Lua 2020-10-02 11:24:52 +02:00
abcdefg30
798aff1140 Fix ValidStances of RevealsMap not working 2020-10-02 11:17:03 +02:00
Niklas Holma
8596ce00cc Add a text field next to the map editor actor initializer sliders. 2020-09-28 15:46:19 +02:00
Matthias Mailänder
b5613acad8 Don't put absolute paths of developer machines in there. 2020-09-28 12:47:27 +02:00
Matthias Mailänder
7e992d44c8 Fix a crash when refineries share a cell. 2020-09-28 12:45:20 +02:00
Matthias Mailänder
7a7393b9f0 cachedWidth is never assigned. 2020-09-27 22:56:41 +01:00
Matthias Mailänder
f13e6fb76d Fix Analyzer warning V3008 variable is assigned values twice. 2020-09-27 22:56:41 +01:00
Mustafa Alperen Seki
3e83346915 Add DamageTypes to SoundOnDamageTransition. 2020-09-27 21:22:52 +01:00
Mustafa Alperen Seki
761d3583c4 Add DeathTypes to ShakeOnDeath. 2020-09-27 21:22:52 +01:00
abcdefg30
1a4b773fda Replace 'is' by 'as' and a null check in ScriptMemberWrapper 2020-09-27 22:17:20 +02:00
Matthias Mailänder
930f8ab207 Reset lobby ready state when options change server side. 2020-09-27 15:06:48 +02:00
Matthias Mailänder
2e438f1da9 Remove superfluous null checks. 2020-09-27 00:11:25 +01:00
abcdefg30
4627387ae3 Document the 'CancelActivity' field 2020-09-26 23:20:00 +01:00
abcdefg30
fd69bce609 Use CancelActivity instead of hackily using ResolveOrder 2020-09-26 23:20:00 +01:00
abcdefg30
391d9030cb Move update rules into their correct subfolder 2020-09-26 23:20:00 +01:00
abcdefg30
1ad9a4b65d Move shared color definitions to common metrics 2020-09-26 23:05:28 +01:00
abcdefg30
c6cc2405d3 Move shared sound definitions to common metrics 2020-09-26 23:05:28 +01:00
Matthias Mailänder
0e39cc7829 Tooltip is a conditional trait.
Fix Analyzer warning: V3146 Possible null dereference.
2020-09-26 22:59:39 +01:00
Matthias Mailänder
8d7e5f4663 Fix Analyzer warning: V3022 Expression is always true. 2020-09-26 22:59:39 +01:00
Paul Chote
e320bbfc87 Add disclaimer in readme. 2020-09-26 13:40:20 +02:00
Paul Chote
2e104046d4 Remove music downloads. 2020-09-26 13:40:20 +02:00
reaperrr
9cf38c1784 Increase Pillbox muzzle anim length
Length of muzzle anim now roughly matches the length
of the sound and impact animations.
2020-09-20 20:34:44 +02:00
Paul Chote
1aca6da1ea Hide "Furthest" battlefield camera option if the mod disables it. 2020-09-20 20:28:28 +02:00
abcdefg30
ce4d263b52 Fix AttackMove getting unarmed units stuck 2020-09-20 12:02:20 +02:00
abcdefg30
53c02eb2b9 Fix a crash in the Move activity 2020-09-18 20:12:42 +02:00
abcdefg30
82a2148300 Fix grouped orders not being validated correctly 2020-09-15 10:16:50 +02:00
Paul Chote
b72a58b917 Add missing ActorReferences to yaml dictionaries. 2020-09-15 09:27:50 +02:00
Paul Chote
7f7bce50dc Add dictionary support for ActorReference. 2020-09-15 09:27:50 +02:00
Paul Chote
290e214638 Remove unexpected RenderSprite.FactionImage fallback. 2020-09-12 17:52:46 +02:00
Paul Chote
ad4d6eaec9 Improve --check-missing-sprites error handling. 2020-09-12 17:52:46 +02:00
Paul Chote
cd9bf53e1a Use nameof() to reference image fields. 2020-09-12 17:52:46 +02:00
Paul Chote
ac8b312140 Generalize --check-sequence-sprites to --check-missing-sprites. 2020-09-12 17:52:46 +02:00
Paul Chote
3e849568ff Improve exception message for bogus tileset definitions. 2020-09-12 17:52:46 +02:00
Paul Chote
5d6961619d Fix WithIdleOverlayInfo Image override. 2020-09-12 17:52:46 +02:00
Paul Chote
94180f6a0a Add SequenceReference support for dictionaries. 2020-09-12 17:52:46 +02:00
Paul Chote
7803686aec Rewrite sequence linting / missing file handling.
- Distinguish between missing sequences and missing sprites
- Lint default sequences as well as maps
- Improved performance
- Correctly handle null images
2020-09-12 17:52:46 +02:00
Paul Chote
b8e60ca8ec Fix SequenceReference definitions. 2020-09-12 17:52:46 +02:00
Paul Chote
b985edbc29 Add ModData to ILintRulesPass.Run. 2020-09-12 17:52:46 +02:00
Paul Chote
ffdb3f86d7 Move mod-specific lint attributes to Mods.Common. 2020-09-12 17:52:46 +02:00
Paul Chote
c9b2a34561 Save SubCellInit as an integer. 2020-09-12 17:17:26 +02:00
Paul Chote
e5dc0309f1 Support OPENRA_DISPLAY_SCALE environment variable on Windows. 2020-09-12 00:37:20 +02:00
abcdefg30
57a3ad8ae2 Replace 'inner' with 'move' inside AttackMoveActivity 2020-09-12 00:30:33 +02:00
abcdefg30
ad3722e19f Add support for circumventing the target scan limit in AttackMove 2020-09-12 00:30:33 +02:00
abcdefg30
a12d127fd6 Rework the internals of AttackMoveActivity
Avoids creating and throwing away inner activities unnecessarily
2020-09-12 00:30:33 +02:00
abcdefg30
e80ebfae35 Use readonly where possible in AttackMoveActivity 2020-09-12 00:30:33 +02:00
abcdefg30
4669d6b378 Work around a sound issue when loading saves 2020-09-12 00:18:25 +02:00
abcdefg30
9f093da61e Unhardcode the leeway range of AttackFollow 2020-09-11 23:55:57 +02:00
abcdefg30
c0d31688c4 Exclude walls from the assets value 2020-09-11 23:44:30 +02:00
abcdefg30
86698e7822 Exclude C17, A10 and carryall.reinforce from the assets value 2020-09-11 23:44:30 +02:00
abcdefg30
3fc5859f08 Add 'AddToAssetsValue' to 'UpdatesPlayerStatistics' 2020-09-11 23:44:30 +02:00
tovl
f9bb663f6b Allow thieves to capture landed aircraft in RA mod. 2020-09-10 18:18:09 +02:00
tovl
5e8121bd0b Properly cancel EnterActor when target capturable trait is disabled. 2020-09-10 18:18:09 +02:00
Paul Chote
9cd6df2929 Replace DecorationPosition with mod-defined string ids. 2020-09-09 23:16:05 +02:00
Matthias Mailänder
b16cbeacb6 Sort contents before merging to unify UIDs across filesystems. 2020-09-07 17:25:24 +02:00
Matthias Mailänder
4d46464bc6 Fix an invalid target crash
target.CenterPosition is referenced in warhead orientation later
2020-09-06 12:21:15 +01:00
Matthias Mailänder
7746dc55f0 Remove the table of content
which is auto-generated by mkdocs.
2020-09-06 11:44:23 +01:00
Matthias Mailänder
5d9e8b56c5 Use fewer hard-coded HTML tags to improve mkdocs rendering. 2020-09-06 11:44:23 +01:00
Matthias Mailänder
d1c06365a8 Move automatic API documentation to docs.openra.net 2020-09-06 11:44:23 +01:00
Matthias Mailänder
b56ddc1a08 Check global scripts for Lua errors. 2020-09-05 21:13:47 +01:00
Orb
ae8c8e781f TD Balance Summer 2020 2 2020-09-05 21:02:59 +01:00
reaperrr
1344b1f2e3 Remove system order checks from PlayerStatistics
ResolveOrder for actors isn't even used
for these.
2020-09-05 17:22:04 +01:00
reaperrr
36df25dcb4 GivesExperience performance optimization
Move some look-ups to creation to reduce contribution
to actor death cost.
2020-09-05 17:16:00 +01:00
reaperrr
84246d287d Merge two ifs into one in SpawnActorOnDeath 2020-09-05 17:16:00 +01:00
reaperrr
6d0fbfa21f Explodes performance optimization
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.
2020-09-05 17:16:00 +01:00
abcdefg30
034c6824de Fix MiG missiles damaging airborne actors 2020-09-05 18:06:30 +02:00
reaperrr
c8afa4a2a8 Remove defenderStats look-up from UpdatePlayerStatistics
playerStats is updated on owner change,
so it should always be identical to the removed defenderStats.
2020-09-05 11:12:38 +02:00
abcdefg30
1a77f7320b Fix a crash when updating the DiscordPresence party size 2020-09-05 10:36:35 +02:00
abcdefg30
183ece1360 Remove the unused SetPlayers method 2020-09-05 10:36:35 +02:00
abcdefg30
035cc3da99 Turn DiscordService's 'GetService' into property 2020-09-05 10:36:35 +02:00
ABrandau
c01c39954a Update Harpy Rotor 2020-09-01 18:57:43 +02:00
Matthias Mailänder
c48eb572e3 Remove MuzzleSplitFacings and expose MuzzleSequence to testing. 2020-09-01 18:53:43 +02:00
Paul Chote
b03ab1212f Remove install-core target. 2020-09-01 18:48:54 +02:00
Paul Chote
8a9b5e7e01 Split a separate "compat" macOS package that uses the system mono. 2020-09-01 18:48:54 +02:00
Paul Chote
9b90e4f25a Remove Coverity references. 2020-09-01 18:48:54 +02:00
Paul Chote
8a4401bdcb Fix Appveyor GeoIP download. 2020-09-01 18:48:54 +02:00
Paul Chote
d52e90cf23 Improve .travis.yml compatibility for non-OpenRA deploys. 2020-09-01 18:48:54 +02:00
Paul Chote
14ef0a7740 Remove markdown/html pages from windows install. 2020-09-01 18:48:54 +02:00
Paul Chote
c1f79b348a Generate platform-specific artwork from common source files. 2020-09-01 18:48:54 +02:00
Paul Chote
62166a50d9 Move itch upload script. 2020-09-01 18:48:54 +02:00
Brent Gardner
283b330403 Workaround for GLES 2.0 hardware 2020-09-01 18:00:51 +02:00
teinarss
2cf6b74295 Refactoring on GetEventBounds in Widget 2020-09-01 17:56:12 +02:00
abcdefg30
1a9f707d18 Remove the last reference to DedicatedLoop 2020-08-30 18:12:48 +02:00
Aigamo
06a1c88e86 Replace 0x7FFFFFFF with int.MaxValue 2020-08-29 12:37:20 +01:00
ycanardeau
f358b566b1 Replace NetFrameNumber >= 1 with GameStarted 2020-08-29 12:37:20 +01:00
reaperrr
15fc27d142 Use cached selected in SelectionDecorationsBase 2020-08-28 12:24:07 +02:00
reaperrr
ad20597d74 Cache hue picker sprite in HueSliderWidget 2020-08-27 21:17:37 +02:00
reaperrr
6d409a7c97 Cache indicator sprite in ResourceBarWidget at initialization 2020-08-27 21:17:37 +02:00
reaperrr
36d5ae5421 Cache SupportPowersWidget offsets at initialization
As well as overlay font.
2020-08-27 21:17:37 +02:00
tovl
db9744ea7f Let TS aircraft turn slower when circling. 2020-08-27 21:15:38 +02:00
tovl
5e62fe86fc Add IdleSpeed to aircraft trait. 2020-08-27 21:15:38 +02:00
Paul Chote
6cfa27c33b Replace per-color font caches with tinted rendering. 2020-08-24 18:38:08 +02:00
Taryn Hill
a405969199 docs: link to docs.openra.net instead of wiki.openra.net in readme for generated trait docs 2020-08-23 11:20:02 +02:00
Paul Praet
9a6f3b4c05 Reset Ready status of players in Lobby when options change
Addresses #11274
2020-08-23 00:05:55 +03:00
Matthias Mailänder
7be059a79b Download our cached version after they blocked Travis CI... 2020-08-22 13:06:08 +02:00
reaperrr
29b55de042 Cache rectangles and font in ProductionTabsWidget 2020-08-21 18:06:18 +02:00
reaperrr
235fb19aa8 Cache overlay traits in ProductionPaletteWidget
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).
2020-08-21 18:06:18 +02:00
reaperrr
c0f54fa4fc Cache offsets in ProductionPaletteWidget
At least those that never change.
2020-08-21 18:06:18 +02:00
reaperrr
cdc216aca0 Fix airborne husk target types
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.
2020-08-20 20:46:58 +02:00
reaperrr
4505053618 Simplify CreateEffectWarhead code
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.
2020-08-20 20:46:58 +02:00
abcdefg30
e0d53126d6 Remove the Light Tank husk 2020-08-20 19:17:39 +02:00
abcdefg30
12ff1dd14c Add RAGL balance changes 2020-08-20 19:17:39 +02:00
abcdefg30
50db3152f6 Fix the windows uninstaller name 2020-08-20 17:33:48 +02:00
teinarss
9c4fd0e3d3 Use Null-Propagation Operator 2020-08-19 18:11:07 +01:00
teinarss
8d27d22100 Use discard syntax 2020-08-19 18:11:07 +01:00
teinarss
27f1a7ab27 Use out var syntax 2020-08-19 18:11:07 +01:00
teinarss
d52e4793fe Refactor classes to structs 2020-08-19 11:54:29 +02:00
teinarss
544ac6cb33 Fix crash after entering manage content 2020-08-19 11:40:43 +02:00
Paul Chote
06fbc1a6cf Hide TraitInfo.InstanceName from FieldLoader. 2020-08-17 20:13:32 +02:00
abcdefg30
edab10e6a6 Make the Phase Transport uncloak during repair by mechanics 2020-08-16 21:01:16 +02:00
abcdefg30
dd99fc93e4 Uncloak during resupply when "UncloakOn: Dock" is defined 2020-08-16 21:01:16 +02:00
abcdefg30
dbe824d4e5 Correct "offseted" to "offset" 2020-08-16 15:02:56 +02:00
Paul Chote
6e73d7f5c2 Tidy MapEditorLogic ctor. 2020-08-16 14:17:45 +02:00
Paul Chote
960056d300 Fix mod switcher icon handling. 2020-08-16 14:17:45 +02:00
Paul Chote
3efac3287e Fix Session.Deserialize error handling. 2020-08-16 14:17:45 +02:00
Paul Chote
c4b4a8c8a5 Fix incorrect ramp fill in Map.Resize. 2020-08-16 14:17:45 +02:00
Paul Chote
b833f033bf Remove redundant check from LabelWithHighlightWidget. 2020-08-16 14:17:45 +02:00
Paul Chote
ad75e2be89 Remove redundant check from SupportPowerInstance. 2020-08-16 14:17:45 +02:00
Orb
7ee4fbeb0d New Money Settings 2020-08-15 21:02:01 +01:00
Paul Chote
9886f0ca9a Fix Harvester crash when multiple resource renderers are used. 2020-08-15 18:43:40 +02:00
Paul Chote
46cf56d6ff Remove editor-specific resource rendering.
Mods must manually move their *ResourceRenderer definitions from
World onto BaseWorld to restore resource rendering in the editor.
2020-08-15 18:43:40 +02:00
Matthias Mailänder
e7af295b5e Allow news per mod. 2020-08-15 16:21:21 +01:00
Matthias Mailänder
9d179d9a1a Initialize the font only once and make it configurable. 2020-08-15 16:13:21 +01:00
Matthias Mailänder
15010f9567 Fix production palette ignoring yaml font overrides. 2020-08-15 16:13:21 +01:00
Oliver Brakmann
a7f4f6c1cf Use LeaveMapAtClosestEdge for scripted MiGs on Intervention 2020-08-15 13:38:57 +01:00
Oliver Brakmann
3eeb677f14 Add LeaveMapAtClosestEdge idle behaviour for Aircraft 2020-08-15 13:38:57 +01:00
Paul Chote
ef69a3de66 Use nameof() in PaletteReference. 2020-08-15 13:41:45 +02:00
abcdefg30
0aa5e07252 Send the 'minefieldStart' along with a 'PlaceMinefield' order 2020-08-15 11:34:00 +01:00
abcdefg30
07d58337f1 Let order generators account for selection changes 2020-08-15 11:34:00 +01:00
abcdefg30
b5e3f25418 Fix CashTrickler crashing without IOccupiesSpace 2020-08-15 11:21:39 +01:00
teinarss
19b02875c7 Use Tuple syntax 2020-08-15 10:37:10 +01:00
Taryn Hill
8a74f6ea18 change whitespace-only lines to empty lines in Lua scripts 2020-08-14 15:08:14 +02:00
abcdefg30
a847f3eafa Fix actors not yet in the world improperly updating power state 2020-08-14 11:46:38 +02:00
Curtis Shmyr
a751f074e7 Added actor parameter to Lua UnloadPassenger 2020-08-10 10:38:35 +02:00
Paul Chote
75cb5c2166 Convert turret facings to WAngle relative to the body. 2020-08-09 19:43:53 +02:00
Paul Chote
70a86bed7a Optimize WRot negation.
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.
2020-08-09 19:43:53 +02:00
dnqbob
f67f8ed05e WithLandingCraftAnimation can stop on all movement 2020-08-09 13:22:56 +02:00
Mustafa Alperen Seki
1ae53220d6 Add CurrentMuzzleFacing to FireClusterWarhead. 2020-08-09 13:18:39 +02:00
Matthias Mailänder
c546cb552e Make the fonts configurable. 2020-08-09 13:14:32 +02:00
Matthias Mailänder
10f8836d7b Fix a null reference exception. 2020-08-09 13:14:32 +02:00
dnqbob
7ecd4124ce Make "RepairableNear" public, helpful for modder 2020-08-08 13:20:39 +02:00
abcdefg30
54cd77be8e Add Tiberium near the transformable tree in cnc64gdi01 2020-08-05 11:45:11 +02:00
Mustafa Alperen Seki
43388cb7fc Don't check HasAdequateRefineryCount if no RefineryTypes defined. 2020-08-05 11:29:22 +02:00
Mustafa Alperen Seki
4cc5104fde Unhardcode AI's MinimumRefineryCount numbers. 2020-08-05 11:29:22 +02:00
Curtis Shmyr
d519cabae3 Add actor experience to the Lua API 2020-08-03 18:35:50 +02:00
abcdefg30
9852e29835 Fix subs targeting naval structures by default 2020-08-03 17:50:36 +02:00
Matthias Mailänder
3a427c3630 Add a sequence reference attribute to label fallbacks. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
336656e8f7 Remove superflous warning as null is a valid value here. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
06ad9666e8 Replace burns with more modular and testable trait combinations. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
728e0c6600 If it defaults to the actor type, then it shouldn't be required. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
657e690bdd Add an image override. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
2d36d0a659 Reflect in naming that negative SelfHealing is a thing. 2020-08-02 22:15:13 +02:00
Matthias Mailänder
c42fd5d2e2 Add IsDecoration as a configurable option. 2020-08-02 22:15:13 +02:00
Trevor Nichols
10bf97eff6 Reduce severity of editorconfig and prefer multiline braces 2020-08-02 14:37:39 +02:00
Matthias Mailänder
ea9992247d Reorder string placeholders. 2020-08-02 12:00:53 +02:00
Matthias Mailänder
b90fecff76 Remove the prefixed method name. 2020-08-02 12:00:53 +02:00
Matthias Mailänder
a4fc9fea3b Unify AIUtils.BotDebug prefixes. 2020-08-02 12:00:53 +02:00
abcdefg30
b7c7eff2a2 Fix the position of the red cross in RA 2020-08-02 11:56:15 +02:00
Stuart McHattie
8c10dc406a Prevent Mac's Cmd+Q from exiting the game
This operation can be devastating if you were trying to assign a control group using Cmd + 1 but accidentally catch the Q key during gameplay.
2020-07-28 23:12:39 +01:00
Stuart McHattie
05c3861426 Add myself to the authors list 2020-07-28 23:12:39 +01:00
Matthias Mailänder
1ef5db8896 Document the built in hitshape types. 2020-07-28 23:42:26 +02:00
Andre Mohren
006a87692a Removed unused imports. 2020-07-28 18:22:51 +02:00
Oliver Brakmann
e019b70420 Fix actor previews for actors with types written in capital letters 2020-07-26 10:57:18 +02:00
Smittytron
70ec5b0344 Add flash to mission paranukes 2020-07-26 10:52:06 +02:00
abcdefg30
5401ace540 Add a death animation to Visceroids 2020-07-24 18:13:11 +02:00
abcdefg30
ab9081c852 Force enable Visceroids in the default rules 2020-07-24 18:13:11 +02:00
Matthias Mailänder
3a9b35980c Revert "Reduce order latency locally"
This reverts commit 20e5219cf4.
2020-07-21 21:58:31 +02:00
Matthias Mailänder
150439d215 Revert "Change where we send orders"
This reverts commit 616d9421d6.
2020-07-21 21:58:31 +02:00
Matthias Mailänder
b01a534a98 Revert "Refactor the OrderManager and world tick loop, improves input latency"
This reverts commit f642cead44.
2020-07-21 21:58:31 +02:00
Trevor Nichols
758b0b08d0 Add to .editorconfig additional naming rules to match this codebase's style 2020-07-21 16:15:30 +02:00
teinarss
f87ba1d8a4 Update SP maps with transformable trees 2020-07-20 14:05:52 +02:00
teinarss
67fa7bdcc9 Add TransformsNearResources 2020-07-20 14:05:52 +02:00
Matthias Mailänder
0b03aca104 Fix linter for player palettes. 2020-07-19 10:44:55 +02:00
Paul Chote
3bf61f1043 Fix incorrect rotation calculation in ThrowsShrapnel. 2020-07-19 10:41:05 +02:00
Paul Chote
ac975f4139 Convert yaml-exposed facings to WAngle. 2020-07-19 10:41:05 +02:00
abcdefg30
6d12301f88 Fix the aircraft facing slider in the editor 2020-07-18 01:45:00 +02:00
Andre Mohren
914950c4a5 When zooming using the mousewheel, zoom towards the pointer location. 2020-07-17 20:12:10 +02:00
Paul Chote
b417b267dd Store quaternion components directly.
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.
2020-07-17 15:02:32 +02:00
Paul Chote
aae497eff1 Pass pre-combined rotations into the rendering code. 2020-07-17 15:02:32 +02:00
Paul Chote
3c9db4c2ac Add WRot.Rotate to allow rotations to be combined. 2020-07-17 15:02:32 +02:00
Paul Chote
8c3793e7ea Rename WRot.Zero to WRot.None. 2020-07-17 15:02:32 +02:00
Oliver Brakmann
60a7f53491 Fix target lines appearing not long enough on screen
Also changes the Delay attribute from ticks to milliseconds.
2020-07-16 00:28:05 +02:00
Mustafa Alperen Seki
04bfd62f2f Fix FireClusterWarhead playing wrong Report sound. 2020-07-15 23:55:01 +02:00
Paul Chote
117b8b3653 Change tiberium colors to match the original game. 2020-07-13 14:02:02 +02:00
Paul Chote
70cb0d2924 Improve TS map importer and reimport classic maps. 2020-07-13 14:02:02 +02:00
Paul Chote
c5ea496c45 Add terrain lighting definitions to TS. 2020-07-13 14:02:02 +02:00
Paul Chote
01e955ca37 Implement TS-style terrain lighting. 2020-07-13 14:02:02 +02:00
Paul Chote
fdb66c769c Change terrain layers to track sequences instead of sprites. 2020-07-13 14:02:02 +02:00
Paul Chote
38b3fbbdbe Fix [RequireExplicitImplementation] failures on event properties. 2020-07-13 14:02:02 +02:00
Paul Chote
3bc5d2d02c Add INotifyEditorPlacementInfo interface.
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.
2020-07-13 14:02:02 +02:00
Paul Chote
ac7eda8ca2 Add support for rendering tinted artwork. 2020-07-13 14:02:02 +02:00
reaperrr
baf58f53b3 Adapt SpreadDamageWH to ImpactOrientation
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).
2020-07-12 19:52:55 +02:00
reaperrr
8513a83331 Add ImpactOrientation to WarheadArgs
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.
2020-07-12 19:52:55 +02:00
Orb
bf7fecff10 TD Balance Summer 2020 2020-07-12 19:31:59 +02:00
Oliver Brakmann
6e1f2f636c Increase GameOverDelay for missions from 1.5 to 3 secs 2020-07-12 15:06:55 +02:00
Oliver Brakmann
8b3db6f3d6 Allow granting a condition to Carryalls currently carrying units 2020-07-12 14:36:01 +02:00
Matthias Mailänder
39d0abe982 Remove bit rot. 2020-07-12 14:32:32 +02:00
teinarss
c2026dc254 Add Discord Rich Presence 2020-07-12 14:27:59 +02:00
Matthias Mailänder
cae6c28754 Change the prefix in front of replays. 2020-07-12 13:43:05 +02:00
Sly
3b99924799 Corrected spelling error 2020-07-10 14:48:22 +02:00
Sly
b2b548b103 Corrected spelling error 2020-07-10 14:46:40 +02:00
Pavel Penev
c2e3806a77 Added a FlashPaletteEffect to RA nukes and removed from D2k 2020-07-10 13:22:54 +02:00
Pavel Penev
25500a7dda Updated a stale copyright header 2020-07-10 13:22:54 +02:00
Pavel Penev
8c394a4cb5 Created FlashPaletteEffectWarhead and removed the hardcoded flashing from NukeLaunch
Not actually hardcoded, but there was a hard dependency in NukeLaunch on FlashPaletteEffect and explicit flashing checks.
2020-07-10 13:22:54 +02:00
Pavel Penev
2e7bd4de4b Fixed a bug with the NukeLaunch's Player palette 2020-07-10 13:22:54 +02:00
Matthias Mailänder
7261322e41 Add support for Visual Studio Code. 2020-07-10 12:33:57 +03:00
abcdefg30
cada396733 Fix a crash when previewing an actor using WithCrateBody in the editor 2020-07-09 20:31:03 +02:00
Chris
9f9709f058 Add python3 support to launch-game.sh 2020-07-09 20:21:48 +02:00
abcdefg30
26fc65209d Fix the bogus Actors iterator 2020-07-09 18:11:53 +02:00
Adam Mitchell
f642cead44 Refactor the OrderManager and world tick loop, improves input latency 2020-07-09 13:48:55 +02:00
Adam Mitchell
616d9421d6 Change where we send orders 2020-07-09 13:48:55 +02:00
Adam Mitchell
20e5219cf4 Reduce order latency locally 2020-07-09 13:48:55 +02:00
Vapre
9edda21b06 Avoid three time array lookup in TraitContainer.Actors. 2020-07-09 12:16:04 +02:00
Paul Chote
6d6822ca15 Update map inits in RA/TD/D2k. 2020-07-08 20:38:30 +02:00
Paul Chote
a2269e7ee7 Convert (Dynamic)FacingInit, (Dynamic)TurretFacingInit to WAngle. 2020-07-08 20:38:30 +02:00
Paul Chote
e8f443f4a9 Remove TurretFacingsInit and PlugsInit. 2020-07-08 20:38:30 +02:00
Ivaylo Draganov
67f8452178 Add button to override duplicate hotkey bindings 2020-07-08 19:59:07 +02:00
Ivaylo Draganov
47f6e407d9 Cancel hotkey rebind on Esc key press 2020-07-08 19:59:07 +02:00
abcdefg30
889e2152a4 Cache ProjectedCellBounds during load time 2020-07-08 18:37:50 +02:00
abcdefg30
173aae1f81 Directly check the map bounds instead of converting to PPos 2020-07-08 18:37:50 +02:00
abcdefg30
baed80983b Fix the launch-game.sh newlines not displaying in the console 2020-07-07 22:30:55 +02:00
abcdefg30
b00423dc76 Correct the crash dialog title 2020-07-07 22:30:55 +02:00
abcdefg30
376ed15079 Correct the support folder location in the crash dialog 2020-07-07 22:30:55 +02:00
abcdefg30
a6d8d6cd8e Use tabs as indentation consistently 2020-07-07 22:30:55 +02:00
Paul Chote
b3ee8b447e Reduce duplication between Map and PlayerRadarTerrain. 2020-07-07 22:12:22 +02:00
Paul Chote
5f588561b6 Rewrite TS minimap rendering:
* 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.
2020-07-07 22:12:22 +02:00
Smittytron
83c53e17e0 Allow repairable tech buildings in campaign-rules 2020-07-07 19:47:10 +02:00
Smittytron
c028488894 Add Soviet 09 2020-07-07 19:47:10 +02:00
abcdefg30
b066005f7e Fix AttackBomber marking aircraft that are not in the world as in range 2020-07-06 22:30:41 +02:00
abcdefg30
87e33a75c6 Fix a crash when calling an airstrike at the map edge 2020-07-06 22:30:41 +02:00
Matthias Mailänder
4961b0943b Add a text base spy disguise decoration. 2020-07-05 21:43:12 +02:00
Smittytron
eda1e9c266 Add Counterstrike mission Siberian Conflict 1: Fresh Tracks 2020-07-05 21:33:56 +02:00
abcdefg30
bc7bf174d8 Don't tick the announcement timer when not in low power
When entering low power it will be reset to 0 again anyway
2020-07-05 20:37:17 +02:00
abcdefg30
2e06d5790b Update the PowerState only when power is added or removed 2020-07-05 20:37:17 +02:00
abcdefg30
ab8790e8f1 Style/Readability changes 2020-07-05 20:37:17 +02:00
abcdefg30
7d630e63e7 Let Railgun implement ISync 2020-07-05 18:10:14 +02:00
Smittytron
77899191f3 Add Aftermath mission Situation Critical 2020-07-05 17:21:43 +02:00
Smittytron
6871873e93 Add Counterstrike mission Fall of Greece 1: Personal War 2020-07-05 15:59:18 +02:00
Smittytron
fc4bd131cd Add Aftermath mission: Production Disruption 2020-07-05 15:58:10 +02:00
Pavel Penev
d866286f82 Added back the DescAttributes on projectiles' Inaccuracy fields 2020-07-05 13:04:18 +02:00
Pavel Penev
76dfda164e Moved projectile inaccuracy calculations to Common.Util
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.
2020-07-05 13:04:18 +02:00
Pavel Penev
134d47e48c Added InaccuracyType.Absolute to projectiles 2020-07-05 13:04:18 +02:00
Pavel Penev
a2dbd5e013 Changed weapons in D2k to use the new PerCellIncrement inaccuracy
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.
2020-07-05 13:04:18 +02:00
Pavel Penev
c27412c83a Added InaccuracyType enum and updated projectiles accordingly
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.
2020-07-05 13:04:18 +02:00
Pavel Penev
4143aba595 Added syncing to some Railgun projectile fields 2020-07-05 13:04:18 +02:00
Ivaylo Draganov
39ccac4022 Refactor command bar buttons to use unified widget state names 2020-07-05 11:50:45 +01:00
Ivaylo Draganov
7943f4deb6 Unify widget state image suffixes (disabled, pressed, hover, focus)
- 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
2020-07-05 11:50:45 +01:00
Curtis Shmyr
2dda2d7689 Added lua IsCloaked actor property 2020-07-04 21:06:52 +02:00
Matthias Mailänder
b8f2a14ea0 Automatically upload release to itch.io using butler. 2020-07-04 20:59:10 +02:00
Oliver Brakmann
595809f090 Fix Carryalls waiting for actors on transit-only tiles 2020-07-04 16:47:17 +02:00
abcdefg30
477db9cd4a Fix travis builds not failing when errors occur during static checking 2020-07-03 21:29:25 +01:00
teinarss
67ff292d62 Refactor WorldRenderer to use less allocations 2020-07-03 17:41:41 +02:00
darkademic
ae882b85a9 Make AI randomly scan map for targets for its air squads. 2020-07-02 23:05:49 +02:00
abcdefg30
5e92915095 Fix the cargo unload regression with scripted transports
The activity is not interruptible, so we'd continue after the Move regardless
2020-07-02 21:14:35 +02:00
Smittytron
95809db03c Move Harvester overrides to campaign-rules.yaml 2020-07-02 19:29:37 +02:00
Smittytron
6d5a5121bc Remove worthless function from Allies08 2020-07-02 19:29:37 +02:00
Smittytron
86992751c7 Update Soviet-08a 2020-07-02 19:29:37 +02:00
Smittytron
2eba8b6c37 Add Soviet-08b 2020-07-02 19:29:37 +02:00
Smittytron
e1523e939d Utilize Panic function with added OnDamaged trigger 2020-06-28 17:30:24 +02:00
Smittytron
15a92f443d Replace paraprop power with scripted drops in Soviet01 2020-06-28 17:30:24 +02:00
KorGgenT
b57c68e392 Fix units walk over tunnels and under bridges. 2020-06-28 17:21:54 +02:00
Matthias Mailänder
e95fcb6bc0 Don't let blossom tree poof all at the same time. 2020-06-28 13:43:33 +02:00
Matthias Mailänder
6581fcb6a7 Add a random interval to idle animations. 2020-06-28 13:43:33 +02:00
tovl
6551337bd8 Make TS walkers AlwaysTurnInPlace. 2020-06-28 00:11:26 +02:00
tovl
137df52fdd Make infantry AlwaysTurnInPlace. 2020-06-28 00:11:26 +02:00
tovl
b79aa7eb6a Add AlwaysTurnInPlace option to Mobile. 2020-06-28 00:11:26 +02:00
Alfred Lang
1c8c49dc8e Fix do allow AI do place plugbuildings like RBG Tower on GDI Component Tower 2020-06-27 10:35:06 +02:00
Andrew Odintsov
f0c808d2fc Replace FloodFill with IEditorAction implementation 2020-06-24 19:08:54 +02:00
Curtis Shmyr
26d9ae88df Replace TargetAndAttack with a global aircraft attack function 2020-06-23 20:09:42 +02:00
Curtis Shmyr
3c7f119bb1 Add a damage parameter to Lua OnDamage callback 2020-06-23 19:58:31 +02:00
Ian T. Jacobsen
fea35923f0 Minefield now shows red when out of map bounds and Minelayer now does not get stuck at edge of map
Made it impossible to detect enemy units again

Fix whitespace
2020-06-21 20:16:57 +02:00
Paul Chote
9627776318 Add pitch and roll to TS aircraft. 2020-06-21 18:05:40 +02:00
Paul Chote
6dcde3af72 Allow voxel-based aircraft to pitch and roll. 2020-06-21 18:05:40 +02:00
Paul Chote
43717a89b5 Add Orientation getter to IFacing. 2020-06-21 18:05:40 +02:00
Matthias Mailänder
c7ba359688 Add drop pod reinforcements. 2020-06-21 17:28:24 +02:00
Matthias Mailänder
dc3dbf6d85 Remove uneccessary parentheses. 2020-06-21 17:28:24 +02:00
Smittytron
71664c85ff Fix TargetTypes regression in SnipeWeapon 2020-06-21 12:34:43 +02:00
Nikita Pozdeev
cb41be113a Fix map editor radar ignoring color from terrain 2020-06-20 14:37:23 +02:00
Matthias Mailänder
4fe7daa85e Fix juggernaut preview being disabled by default. 2020-06-19 21:30:34 +02:00
abcdefg30
f75afc6ee4 Fix a compilation error in WithInfantryBody.cs 2020-06-19 20:01:04 +02:00
abcdefg30
67fd71ab92 Add a ProjectedCellLayer and use it in Shroud.cs 2020-06-19 18:31:51 +02:00
abcdefg30
385e70552e Create CellLayerBase 2020-06-19 18:31:51 +02:00
Matthias Mailänder
1e2c67bfca Increase UPnP device discovery timeout. 2020-06-19 18:00:27 +02:00
Paul Chote
56739f87fb Allow plugs to be configured in the map editor. 2020-06-19 17:57:56 +02:00
Paul Chote
571eb7614f Support multiple turrets in the editor. 2020-06-19 17:57:56 +02:00
Paul Chote
c6c3a8c60d Make ActorPreview and EditorActorPreview wrap ActorReference. 2020-06-19 17:57:56 +02:00
Paul Chote
ae7cfa56b7 Restrict IActorPreviewInitInfo to ActorInit. 2020-06-19 17:57:56 +02:00
Paul Chote
b856613194 Add ISingleInstanceInit interface.
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.
2020-06-19 17:57:56 +02:00
Paul Chote
86305879cb Parse Enum *ValueInit as string values, not integers. 2020-06-19 17:28:01 +02:00
Paul Chote
e5a1a8a706 Replace deprecated API usage. 2020-06-19 17:28:01 +02:00
Paul Chote
27602a4a97 Add WAngle-compatible airstrike/paratrooper APIs. 2020-06-19 17:28:01 +02:00
Paul Chote
a98e460257 Expose WAngle to Lua API and deprecate old Facing. 2020-06-19 17:28:01 +02:00
Paul Chote
0349435650 Remove deprecated Paratrooper API methods. 2020-06-19 17:28:01 +02:00
Paul Chote
c3fbdca18f Add yellow-shirt technician. 2020-06-19 17:09:13 +02:00
Paul Chote
acb5245a28 Restore correct palette and voices for RA civilians.
A new C11 infantry has been added to use the custom
c3 sprite that was originally added back when only
c1 and c2 were used in OpenRA.
2020-06-19 17:09:13 +02:00
Paul Chote
23561cd76b Add custom palette support to WithInfantryBody. 2020-06-19 17:09:13 +02:00
Paul Chote
d3ab3d7d78 Move IndexedPlayerPalette to Mods.Common and add a non-player version. 2020-06-19 17:09:13 +02:00
Matthias Mailänder
5b870be83f Let the 2nd civilian panic when his mate gets electrocuted. 2020-06-19 16:50:28 +02:00
Matthias Mailänder
6130d5622c Add a panic function to the Lua API. 2020-06-19 16:50:28 +02:00
abcdefg30
318c4e3456 Remove InitialStanceAI overrides from campaign missions 2020-06-19 16:46:34 +02:00
abcdefg30
ab701449e2 Change Subs to use the Defend stance by default 2020-06-19 16:46:34 +02:00
abcdefg30
9a3447d863 Fix airstrike and paratroopers power not removing cameras at the map edge 2020-06-19 16:04:54 +02:00
matjaeck
5280637adf Fix PickupUnit not validating cargo on first run. 2020-06-19 15:59:14 +02:00
Matthias Mailänder
3bce55ac44 Cancel the attack when no traits are active. 2020-06-19 13:43:03 +02:00
Curtis Shmyr
a3f79503ed Fix Lua DisplaySystemMessage writing twice 2020-06-16 13:11:02 +02:00
Curtis Shmyr
02d462a82c Fix copying public key to clipboard if already authed 2020-06-13 19:15:27 +02:00
Smittytron
3d17328d0d Fix regression and cleanup scu35ea 2020-06-12 23:50:44 +02:00
reaperrr
0e81abc21b Fix weapons not accounting for Air
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").
2020-06-12 21:00:53 +02:00
Paul Chote
803b930405 Change IFacing.TurnSpeed to WAngle. 2020-06-12 18:35:41 +02:00
Paul Chote
6adf45bcb4 Convert IFacing.Facing and TurnSpeed to WAngle. 2020-06-12 18:35:41 +02:00
Matthias Mailänder
01417c88c5 Add missing actor reference for lint testing. 2020-06-10 19:07:14 +02:00
abcdefg30
60bbbe0d93 Fix the Death Hand launch notification playing for the player not enemy 2020-06-10 18:57:08 +02:00
Matthias Mailänder
888dfd3654 Stop the boat to remove it immediately. 2020-06-09 22:40:32 +02:00
Matthias Mailänder
12de56ff62 Fix crash notication "AlertBeep" not found. 2020-06-09 22:40:32 +02:00
Matthias Mailänder
b7cee41c54 Fix TD gunboat not updating actor map influence. 2020-06-09 22:40:32 +02:00
Paul Chote
10aac03f75 Add CompositeActorInit and simplify chronoshift inits. 2020-06-08 19:18:38 +02:00
Paul Chote
0eb0041f90 Allow ActorInits to target a specific trait by matching the @ suffix. 2020-06-08 19:18:38 +02:00
Paul Chote
b38018af9c Replace IActorInit with an abstract class.
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.
2020-06-08 19:18:38 +02:00
Unknown
4df5ac0385 Change default to ground-attack 2020-06-07 10:31:44 -05:00
Unknown
a7476bc303 Improve detail + double fire rate/half damage 2020-06-07 10:31:44 -05:00
Unknown
cc4b3cb361 Add APC ground attack sprite turret 2020-06-07 10:31:44 -05:00
Ivaylo Draganov
31a965b29a Add suffix to player name in shroud selector 2020-06-06 14:40:48 +01:00
Ivaylo Draganov
7a213338a2 Add helper method to add suffix to player name label 2020-06-06 14:40:48 +01:00
abcdefg30
fb27a25e52 Fix a crash with support powers and units without selection decorations 2020-06-06 13:46:27 +01:00
abcdefg30
534b09ae4a Fix bots not working after adminship was transferred 2020-06-03 18:30:18 +02:00
abcdefg30
341a9f370c Fix a crash in Evacuation 2020-06-02 22:53:40 +02:00
Matthias Mailänder
607d9b2d5c Fix index out of bounds exception for off world aircraft. 2020-06-02 19:25:53 +01:00
abcdefg30
507ce40ad2 Fix a crash in LegacyBridgeLayer 2020-06-02 19:22:19 +01:00
reaperrr
f58c3aed32 Use OccupiesSpace to save more trait look-ups
This time in Locomotor.IsBlockedBy.
2020-06-02 20:08:34 +02:00
reaperrr
55e85bd9ca Save Mobile look-up in BasePathSearch
By casting to OccupiesSpace and then
looking up Info.LocomotorInfo directly.
2020-06-02 20:08:34 +02:00
reaperrr
4bf614c5cd Use OccupiesSpace to avoid Mobile look-up in Move
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.
2020-06-02 20:08:34 +02:00
abcdefg30
96b06c75d1 Make Resupply display target lines for all queued move activities 2020-06-02 18:23:54 +02:00
Matthias Mailänder
d261648ab0 Fix BeingCapturedCondition getting revoked from the wrong actor. 2020-06-02 10:45:49 +02:00
Paul Chote
7b81b9e806 Bullet Facing -> WAngle. 2020-06-01 21:34:32 +02:00
Paul Chote
a93aea3e4e AreaBeam Facing -> WAngle. 2020-06-01 21:34:32 +02:00
Paul Chote
2cfacc2c7d ProjectileArgs facing -> WAngle. 2020-06-01 21:34:32 +02:00
Paul Chote
6d6b21a0eb Convert Aircraft.Facing to WAngle. 2020-06-01 20:25:38 +02:00
Matthias Mailänder
7a78c37851 Add .NET Coding Conventions 2020-05-31 13:27:03 +01:00
Ivaylo Draganov
b8a9f41892 Add missing trait descriptions for cursors and unify the language 2020-05-31 00:12:04 +02:00
Ivaylo Draganov
227567dfe1 Formatting: wrap and indent long argument lists 2020-05-31 00:12:04 +02:00
Ivaylo Draganov
d5ff5c672b Add configurable cursors for entering allied actor targeters 2020-05-31 00:12:04 +02:00
Ivaylo Draganov
393f6eca3a Add configurable target cursors to various traits 2020-05-31 00:12:04 +02:00
Paul Chote
d193ef856e Fix harvest animation facing glitch. 2020-05-30 19:58:03 +02:00
abcdefg30
44d3691fa1 Assign Player.IsBot before calling INotifyCreated.Created 2020-05-30 19:47:29 +02:00
abcdefg30
27d0465891 Remove workarounds for querying the PlayerActor in Created 2020-05-30 19:47:29 +02:00
abcdefg30
52a9fcef3c Rename "Created" to "Initialize" and let it handle adding to the world 2020-05-30 19:47:29 +02:00
abcdefg30
7386816f52 Manually construct the PlayerActor to fix crashes during actor creation 2020-05-30 19:47:29 +02:00
abcdefg30
9c0075b233 Move hardcoded PlayerActorTypes to shared const variables 2020-05-30 19:47:29 +02:00
abcdefg30
e4c5700baf Remove an unused using 2020-05-30 19:47:29 +02:00
reaperrr
e1b7df8b6a Use OccupiesSpace to avoid Mobile look-ups
in PathFinder.FindUnitPath and FindUnitPathToRange.
2020-05-30 04:05:29 -05:00
Paul Chote
c999b2d778 Convert QuantizeFacing to WAngle facings. 2020-05-28 21:23:51 +02:00
Paul Chote
bfb6c671fb Change QuantizeFacing to return a facing instead of an index. 2020-05-28 21:23:51 +02:00
Paul Chote
7c6ec577dc Rewrite ActorInit queries. 2020-05-28 19:04:53 +02:00
Paul Chote
626b40f31b Account for ramps in terrain height calculations. 2020-05-28 09:41:55 -05:00
Paul Chote
5af12440ba Replace MapGrid.CellCorners with a new CellRamp struct. 2020-05-28 09:41:55 -05:00
Paul Chote
4614f6febe Cache cell ramps to avoid repeated tileset lookups. 2020-05-28 09:41:55 -05:00
Pavel Penev
1354ffc32e Added multiple production speedup to D2k
Based on the specification in issue 18051.
2020-05-27 10:32:35 +02:00
Pavel Penev
3723939c99 Adjusted D2k build times to match the original game
Removed custom production queue speedups and custom actor build time slowdowns and adjusted BuildDurations based on the specifications in issue 18051.
2020-05-27 10:32:35 +02:00
Pavel Penev
e099739e13 Reduced HitShape radius of D2k units to minimum
Since they are only used to hold the armor type anyway.
2020-05-27 10:28:25 +02:00
Pavel Penev
21a48cc41d Switched D2k to use the new DamageCalculationType
This brings D2k in line with the damage model of the original game.
2020-05-27 10:28:25 +02:00
Pavel Penev
4740266308 Added DamageCalculationType enum to SpreadDamageWarhead 2020-05-27 10:28:25 +02:00
Pavel Penev
78139413d7 Equalized the DoImpact methods in damage warheads 2020-05-27 10:28:25 +02:00
Pavel Penev
f0578a75f4 Cleaned up DamageWarhead
Reordered methods and fixed access modifiers. Also removed unused using statements from warheads.
2020-05-27 10:28:25 +02:00
abcdefg30
7a0e55a02a Restore trailing whitespaces to windows batch scripts 2020-05-26 22:57:11 +02:00
reaperrr
f132bac80d Add Tree armor type and remove tree-only warheads
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.
2020-05-26 22:51:29 +02:00
reaperrr
109ea4fe5b Fix Barrel explosion damage 2020-05-26 22:46:26 +02:00
Matthias Mailänder
f33feafd0e Add TurnOnIdle. 2020-05-25 13:07:19 +02:00
reaperrr
9195356e3a Upgrade DepthCharge effect setup
- med_explosion instead of small_explosion on surface hit
- only play explosion on surfaced subs
- only play h2obomb2.aud when hitting a submerged sub
2020-05-24 13:26:40 +02:00
reaperrr
eff91108f4 Make RA ships show both explosion and splash
...when destroyed, to imply sinking.
2020-05-24 13:26:40 +02:00
reaperrr
e40c0516e6 Adapt RA warheads to new target types 2020-05-24 13:26:40 +02:00
reaperrr
c580a94ab7 Fix RA weapon ValidTargets 2020-05-24 13:26:40 +02:00
reaperrr
6a545bb942 Streamline RA target types
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.
2020-05-24 13:26:40 +02:00
Matthias Mailänder
672bd2d9fe Don't crash when putting the trait on the World actor. 2020-05-24 12:36:26 +02:00
Ivaylo Draganov
3ab4a584ab Remove trailing white-space from various files 2020-05-23 11:38:44 +02:00
Ivaylo Draganov
150d02ac0d Remove trailing white-space from lua files 2020-05-23 11:38:44 +02:00
Ivaylo Draganov
6d26f60904 Remove trailing white-space from yaml files 2020-05-23 11:38:44 +02:00
abcdefg30
b42276953f Fix a crash when a harvester is rebuilt in cnc64gdi01 2020-05-22 21:25:58 +02:00
abcdefg30
7c290b9f76 Fix not all harvesters in cnc64gdi01 being rebuilt 2020-05-22 21:25:58 +02:00
abcdefg30
51fe1d6629 Let AI autotargeting in D2k ignore sandworms 2020-05-22 20:40:36 +02:00
Matthias Mailänder
8f558d2b47 Add a bullet bounce sound. 2020-05-21 14:44:13 +02:00
abcdefg30
3f5fadf2e9 Move stray update rules into the correct subfolder 2020-05-21 14:08:14 +02:00
abcdefg30
07c16cee1d Add TargetTypes to HealActorsCrateAction 2020-05-21 14:08:14 +02:00
abcdefg30
24130dfcdc Add an update rule for the RenameHealCrateAction rename 2020-05-21 14:08:14 +02:00
abcdefg30
15a2341a91 Rename HealUnitsCrateAction to HealActorsCrateAction 2020-05-21 14:08:14 +02:00
Paul Chote
86f61298e6 Replace ITraitInfo interface with TraitInfo class. 2020-05-21 13:01:04 +02:00
abcdefg30
3cd7ec3878 Make the TS Test AI build aircraft 2020-05-21 10:05:05 +02:00
abcdefg30
8b13d3e4c7 Fix resupply not displaying target lines correctly 2020-05-19 22:11:20 +02:00
Ivaylo Draganov
327d451abc Add trim_trailing_whitespace to .editorconfig 2020-05-18 17:39:24 +02:00
atlimit8
2dac16ee02 add SquadManagerBotModuleInfo.IgnoredEnemyTargetTypes 2020-05-17 22:02:32 +01:00
abcdefg30
d4b92a19d7 Remove bogus weapon override defintions from TD campaign maps 2020-05-17 13:39:51 +01:00
tovl
e0357596f5 Correct aircraft repulsion direction when outside of the map. 2020-05-17 12:46:17 +02:00
atlimit8
1ef27d18c1 check name for Actor.GrantCondition() 2020-05-17 12:33:29 +02:00
Matthias Mailänder
1d2d8ed107 Don't hard-code the transparent background color. 2020-05-16 22:28:52 +01:00
reaperrr
1bf01bc214 Remove WaterStructure TargetType from RA SYRD/SPEN
- 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.
2020-05-15 08:22:02 +02:00
reaperrr
0015deca47 Fix TS Tiberium Fiend target types
Was missing Creep, preventing actors from
auto-targeting it (unlike all other critters).
2020-05-15 08:22:02 +02:00
reaperrr
ddfdc6e90f Clean up TD weapon ValidTargets
- 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
2020-05-15 08:22:02 +02:00
abcdefg30
5db2ad54f2 Fix a scripting error in nod04b 2020-05-14 22:40:44 +01:00
teinarss
b8a5750529 Add map.contains check to CanStayInCell 2020-05-14 20:06:21 +02:00
Andrew Odintsov
98d5b8c7cc Remove redundant call to OnTextEdited 2020-05-14 11:01:48 +02:00
Andrew Odintsov
3f34154a1e Add OnTextEdited call to RemoveSelectedText
This would allow expty text box to be processed and disable filtering
2020-05-14 11:01:48 +02:00
thisisjacob
3119f831b3 Added notice for entering vehicles in docs 2020-05-13 17:25:49 -05:00
thisisjacob
8a07b762a2 Changed documentation for OnEnterComplete 2020-05-13 17:25:49 -05:00
Matthias Mailänder
551ab2fc59 Cache the footprint LINQ for performance. 2020-05-12 20:53:05 -05:00
Zimmermann Gyula
99957e57b9 Update the default mods. 2020-05-12 20:53:05 -05:00
Matthias Mailänder
be2c59bc6e Add upgrade rule to convert ranges to footprints. 2020-05-12 20:53:05 -05:00
Zimmermann Gyula
57f9a49b66 Use footprints in ChronoshiftPower. 2020-05-12 20:53:05 -05:00
Zimmermann Gyula
54bd0eb99d Use footprints in GrantExternalConditionPower. 2020-05-12 20:53:05 -05:00
Zimmermann Gyula
485faac294 Implement SupportPower.CellsMatching. 2020-05-12 20:53:05 -05:00
Andrew Odintsov
d531d6f3ef Simplify groupActors condition 2020-05-12 15:06:50 +02:00
Andrew Odintsov
3a9fdb82f5 Add IsInWorld check for controlled groups 2020-05-12 15:06:50 +02:00
reaperrr
5024ae1156 TS ClusterMissile typo fix 2020-05-10 15:20:25 +02:00
abcdefg30
0135dd9ed3 Use inheritance to shorten the desert shellmap custom rules 2020-05-09 14:36:50 -05:00
abcdefg30
a6e9b86bbe Remove AnnounceOnKill Tanya overwrites from the desert shellmap 2020-05-09 14:36:50 -05:00
abcdefg30
237c4444b5 Remove DeathSounds overwrites from the desert shellmap 2020-05-09 14:36:50 -05:00
reaperrr
a68467292e Use TargetType.Invalid checks instead of IsValidFor 2020-05-09 17:59:23 +02:00
reaperrr
978c69d0c3 Make Warhead.IsValidTarget method protected
IsValidTarget is never called from outside warheads.
2020-05-09 17:59:23 +02:00
reaperrr
3eabc59921 Make resource warheads AirThreshold-aware 2020-05-09 17:59:23 +02:00
reaperrr
2b3d99fac2 Sanitize resource warheads
- Fix potential crash due to invalid target (no CenterPosition)
- Fix potential crash on multiple ResourceLayers
2020-05-09 17:59:23 +02:00
reaperrr
2bdefe0e9e Move AirThreshold to Warhead
To reduce duplication and for later use in more warheads.
2020-05-09 17:59:23 +02:00
reaperrr
de81fc2aca Minor CreateEffectWarhead optimization
Palette only matters if we actually display an explosion.
2020-05-09 17:59:23 +02:00
reaperrr
b514e0a6e7 D2k yaml comment removal
Naming the warhead for its purpose is cleaner
than comments, in my opinion.
2020-05-09 17:56:08 +02:00
reaperrr
715dfa4541 Use args in FireClusterWarhead methods
Instead of directly passing damage modifiers.
2020-05-09 17:56:08 +02:00
reaperrr
ac57a37224 DamageWarhead polish
Use BitSet.IsEmpty.
2020-05-09 17:56:08 +02:00
Paul Chote
afd620b092 Reimplement ClassicQuantizeFacing using a look-up-table. 2020-05-09 10:40:50 -05:00
Paul Chote
552bceb07c SpriteEffect facing -> WAngle. 2020-05-09 10:20:23 -05:00
Paul Chote
fe58ed1283 Animation facing -> WAngle. 2020-05-09 10:20:23 -05:00
Paul Chote
361e2d463c ISpriteSequence facing -> WAngle. 2020-05-09 10:20:23 -05:00
atlimit8
259c8d2c98 Merge ConditionManager trait directly into Actor 2020-05-09 15:46:11 +02:00
abcdefg30
e12c1dc9aa Retire the "release-20190314" path 2020-05-09 13:08:10 +01:00
abcdefg30
7fb49e383d Update and fix the latest update path and rules 2020-05-09 13:08:10 +01:00
Matthias Mailänder
1df3e28253 Initialize RangeModifiers. 2020-05-08 20:58:27 +02:00
Paul Chote
bacec2689d Remove error message duplication. 2020-05-08 15:17:44 +02:00
jrb0001
bf397591f9 Implement IPv6 support for server and direct connect 2020-05-08 15:17:44 +02:00
Matthias Mailänder
bd1a936c7a Add the armed technician. 2020-05-08 09:42:14 +02:00
Matthias Mailänder
0871d6e321 Setup the Firestorm civilian voices. 2020-05-08 09:42:14 +02:00
abcdefg30
265d296db6 Add infiltration sounds support to InfiltrateForSupportPowerReset 2020-05-05 15:16:09 -05:00
Matthias Mailänder
5ec136b57c Don't play the make animation on the wall sprite body. 2020-05-05 13:23:58 +02:00
atlimit8
f1e8f9c9d0 Fixed PNG frame count calculation
This fixes the order of operations and rounding issue, making it columns * rows.
2020-05-02 23:14:31 +02:00
Paul Chote
f03841c4e4 Hide selection decorations when spectators zoom too far out. 2020-05-02 14:30:04 -05:00
Pavel Penev
0ae58ff0ea Adjusted damage spread ranges on weapons in D2k to match the original game 2020-05-02 20:22:01 +01:00
Pavel Penev
390c1899ca Changed weapons in D2k to have a linear damage falloff to match the original game 2020-05-02 20:22:01 +01:00
Matthias Mailänder
89aa6d1e4e Don't attack during buildup. 2020-05-02 20:07:09 +01:00
Matthias Mailänder
24638b02a9 Fix turret build sounds. 2020-05-02 20:07:09 +01:00
Matthias Mailänder
4b0ab6ab37 Add the crumble overlay to the turrets. 2020-05-02 20:07:09 +01:00
Matthias Mailänder
1f02d9f141 Add the make animation for the turrets. 2020-05-02 20:07:09 +01:00
Matthias Mailänder
0103c38c13 Don't change the animation when it's not your turn. 2020-05-02 20:07:09 +01:00
Matthias Mailänder
3cc76f91b4 Fix the make animation for the silos. 2020-05-02 20:07:09 +01:00
abcdefg30
10dc248f07 Remove unused usings from BaseBuilderBotModule 2020-05-02 14:05:44 -05:00
abcdefg30
d1f89c6217 Update the Desc of GrantCondition 2020-05-02 14:05:44 -05:00
abcdefg30
76ba4fc32d Use a modular AI in soviet05 2020-05-02 14:05:44 -05:00
abcdefg30
37f90fff44 Throw LuaExceptions instead of InvalidDataExceptions in ConditionProperties 2020-05-02 14:05:44 -05:00
abcdefg30
9fa6da3bc7 Add PlayerConditionProperties 2020-05-02 14:05:44 -05:00
abcdefg30
aa8cf237ab Make Greece the owner of all starting actors in soviet05 2020-05-02 14:05:44 -05:00
Matthias Mailänder
c131728aa4 Give more context when crashing during .png sheet loading. 2020-05-02 13:26:06 -05:00
Paul Chote
2abd137494 Remove OpenRA.PostProcess.exe.
The LAA flag is now set when packaging
Windows release installers.
2020-05-02 17:26:54 +02:00
Paul Chote
90815ace59 Add a decoration glyph for friendly units in tunnels. 2020-05-02 16:16:16 +02:00
Matthias Mailänder
53d916d7f1 Add some basic error handling to png metadata writing. 2020-05-02 04:13:34 -05:00
reaperrr
2b4035979b Make all warheads use WarheadArgs
Instead of passing damageModifiers directly.
2020-05-02 03:09:18 +03:00
Matthias Mailänder
38cdc93010 Default the optional effect sequence to null 2020-05-01 19:43:36 +03:00
Matthias Mailänder
346dad3898 Remove trailing spaces. 2020-05-01 19:43:36 +03:00
Matthias Mailänder
42256bc262 Add an out of bounds check. 2020-05-01 19:41:06 +03:00
Matthias Mailänder
70babb4067 Validate the target before querying it's center position. 2020-05-01 16:53:29 +02:00
Matthias Mailänder
3603e6373d Check for invalid targets. 2020-04-30 01:42:19 -05:00
Matthias Mailänder
bd1760682f Rename WithNukeLaunch* traits to WithSupportPower*. 2020-04-30 01:37:05 -05:00
Matthias Mailänder
52d0490f95 Supersede INotifyNuke 2020-04-30 01:37:05 -05:00
Matthias Mailänder
b3b0aa75ae Add new interfaces for support powers. 2020-04-30 01:37:05 -05:00
Paul Chote
e42d177920 Include selection decorations when calculating ScreenMap bounds. 2020-04-30 00:09:57 +02:00
Paul Chote
c2156af7b0 Restore missing minelayer pips. 2020-04-29 22:59:48 +02:00
dnqbob
86394eb56c "FindEnemy" functions ignore hidden actors
(helped by reaperrr and abcdefg30)
2020-04-28 15:35:02 +02:00
dnqbob
2d7790f5e4 StateBase.cs modified:
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)
2020-04-28 15:35:02 +02:00
Matthias Mailänder
3df43529a6 Document BitSet<TargetableType> 2020-04-27 16:06:32 +02:00
Matthias Mailänder
a1c9b27057 Add InfiltrateForSupportPowerReset 2020-04-27 16:06:32 +02:00
abcdefg30
089dd233a5 Correct the support dir location in ExtractSettingsDocsCommand 2020-04-26 12:38:11 +01:00
Matthias Mailänder
86a7a0bd6c Move Render*Circle traits to their base traits. 2020-04-26 10:30:50 +02:00
Paul Chote
7ebca36a9c Disable debug callbacks on Intel HD 4000. 2020-04-25 21:03:43 +02:00
Paul Chote
d5aed5a88a Expose GL Profile in settings menu. 2020-04-25 21:03:43 +02:00
Paul Chote
dac1f270ce Restore legacy OpenGL 2.1 support. 2020-04-25 21:03:43 +02:00
Paul Chote
839be24053 Replace PreferGLES settings flag with GLProfile enum. 2020-04-25 21:03:43 +02:00
Paul Chote
91c4179f05 Split GLProfile from GLFeatures. 2020-04-25 21:03:43 +02:00
Matthias Mailänder
a4b427bfac Clarify AttackPanicChance and add PanicChance. 2020-04-24 18:38:54 +02:00
reaperrr
250f5bec18 Misc yaml style fixes 2020-04-24 18:22:35 +02:00
reaperrr
336e2a10e0 Fixed RA STNK turret not using fudged facings 2020-04-24 18:22:35 +02:00
reaperrr
b5e9b7635e MoveClassicFacingFudge update rule 2020-04-24 18:22:35 +02:00
reaperrr
0df7fa1596 Add sequence update rule support 2020-04-24 18:22:35 +02:00
reaperrr
c10487d635 Move ClassicFacingFudge support to Mods.Cnc
This moves the TD/RA-specific re-mapping of sprite facings
and coordinates to Mods.Cnc.
2020-04-24 18:22:35 +02:00
abcdefg30
bc9b3bef74 Fix a crash when completing objectives in Allies06 out of order 2020-04-23 21:56:46 +01:00
abcdefg30
e57462e7ca Make attack moving and guarding use a grouped order 2020-04-21 01:35:40 -05:00
abcdefg30
78bf27709f Add basic support for grouped orders 2020-04-21 01:35:40 -05:00
Matthias Mailänder
fc84cd9204 Add an is in world check to fix a crash. 2020-04-21 01:15:43 -05:00
Matthias Mailänder
e361f7b246 The category field has been pluralized. 2020-04-19 15:21:10 +02:00
Matthias Mailänder
b0497b7505 Fix double whitespace. 2020-04-19 15:21:10 +02:00
Zimmermann Gyula
a894e31fa5 Remove now obsolete tileset palette entry. 2020-04-19 15:21:10 +02:00
Matthias Mailänder
dd062adec2 Add descriptions as those are not obvious in this context. 2020-04-18 13:56:26 -05:00
Matthias Mailänder
d187575a2c Make support power icons configurable and testable. 2020-04-18 13:56:26 -05:00
teinarss
85096c4ba2 Update CoordinateTest to be compatible with new nunit version. 2020-04-18 11:36:25 -05:00
teinarss
e13fd693c3 Add Nuget packages for all dependencies 2020-04-18 11:36:25 -05:00
Mustafa Alperen Seki
cc35512472 Add a trait to reveal the whole map when conditions are met. 2020-04-18 10:49:25 -05:00
abcdefg30
4e548291ce Treat transit-only tiles as invalid locations for minelayers 2020-04-18 13:35:06 +01:00
abcdefg30
3ba86f329f Remove Game.HasInputFocus 2020-04-17 22:26:03 -05:00
Mustafa Alperen Seki
5b34af0f12 Change all instances of ToLower() to ToLowerInvariant() 2020-04-17 17:01:42 -05:00
Adam Mitchell
0a9eb1ff83 Fix units stuck on transit-only when resupplying 2020-04-17 11:13:46 +02:00
abcdefg30
942dd0e5f7 Adapt the utility commands to import crates as well 2020-04-17 10:52:59 +02:00
abcdefg30
400102f3d3 Remove a TODO about grey nod colors 2020-04-17 10:52:59 +02:00
abcdefg30
9ccdeb3d36 Set the wcrate and scrate sequences up 2020-04-17 10:52:59 +02:00
abcdefg30
7e0f0dd2d2 Add missing money crates to TD campaign missions 2020-04-17 10:52:59 +02:00
abcdefg30
d920cbb7f6 Move money crates to a default in the shared campaign rules 2020-04-17 10:52:59 +02:00
Paul Chote
417677e6f4 Work around and explain color picker conversion issue. 2020-04-17 10:41:08 +02:00
Paul Chote
33f3038316 Fix map-specific factions remaining selected when changing map. 2020-04-16 16:49:00 +02:00
Paul Chote
429dbe3e0c Block profiles with revoked keys from joining auth-only servers. 2020-04-16 16:43:10 +02:00
abcdefg30
471fc44751 Add more engineers to the wave in nod07
Otherwise buildings will only be damaged
2020-04-16 13:21:33 +02:00
abcdefg30
1b8e346307 Fix APC reinforcements in nod07a and b 2020-04-16 13:21:33 +02:00
abcdefg30
a456583a08 Fix a crash in nod07b 2020-04-16 13:21:33 +02:00
Paul Chote
a63c17baab Disable IP tooltip in skirmish games. 2020-04-15 23:16:24 +02:00
Paul Chote
9c4faddc0f Switch GeoIP database from MaxMind to IP2Location.
The IP2Location data is licensed under CC BY-SA, which
allows us to distribute the database with releases.
2020-04-15 23:16:24 +02:00
Paul Chote
6828c4c1e9 Fix long player locations overrunning the player tooltip. 2020-04-15 23:16:24 +02:00
Matthias Mailänder
80131e7ec0 Group readonly fields. 2020-04-15 21:42:50 +02:00
Matthias Mailänder
ac381a6f58 Allow multiple ResourceRenderer traits. 2020-04-15 21:42:50 +02:00
Matthias Mailänder
521b516bf9 Mark suggested fields as readonly. 2020-04-15 21:42:50 +02:00
netnazgul
6a825f8e60 Modify preset colors to not get flagged by color validator 2020-04-14 18:31:18 +02:00
Paul Chote
f0a243ca10 Fix mine layer desync.
World.FogObscures depends on the local RenderPlayer and should not
be used from simulation code!
2020-04-12 23:06:55 +02:00
Matthias Mailänder
e5457a3390 Allow wall renderers in mod code. 2020-04-11 16:29:00 +02:00
Matthias Mailänder
47e21f8bef Remove unused using. 2020-04-11 16:29:00 +02:00
Matthias Mailänder
331b854e4e Add a lint check for production bar types. 2020-04-10 21:00:26 +02:00
Matthias Mailänder
274bc9cbba Add missing sequence reference. 2020-04-10 20:56:54 +02:00
Matthias Mailänder
827f8d95b4 Remove unused using. 2020-04-10 20:56:54 +02:00
Matthias Mailänder
2946dd35d5 Spaces to tabs. 2020-04-10 20:14:39 +02:00
Matthias Mailänder
74d884787d Remove trailing tabs/spaces. 2020-04-09 22:32:05 +02:00
Matthias Mailänder
5516e16fb8 Make the default player color configurable in mod.yaml 2020-04-09 22:32:05 +02:00
reaperrr
cadf4eb322 Limit TS fona to temperate theater
Their art wasn't drawn with snow terrain in mind,
so no point in allowing to place them on snow maps.
2020-04-07 22:04:16 +02:00
Matthias Mailänder
269249e86e Fix the fona sequence definitions. 2020-04-07 22:04:16 +02:00
Matthias Mailänder
30f87d2308 Port some Translucent=yes from Art.ini 2020-04-07 22:00:31 +02:00
Zimmermann Gyula
8b7e72b95e Add three additional blending modes. 2020-04-07 22:00:31 +02:00
abcdefg30
1e64048956 Cache PlayerResources and unit cost in Resupply 2020-04-07 21:27:16 +02:00
abcdefg30
8512e696f5 Add Creeps as enemy in all D2k missions 2020-04-07 21:19:08 +02:00
abcdefg30
6a03a9ec5f Fix a yaml error in GDI08a 2020-04-07 20:59:17 +02:00
netnazgul
5e04c99d57 Fix tile errors on the map "Pie of Animosity" 2020-04-07 20:53:28 +02:00
Mustafa Alperen Seki
82f15491c0 Allow Engineers in RA to enter undamaged (Camo) PillBoxes. 2020-04-03 04:09:43 -05:00
Mustafa Alperen Seki
101843fbb7 Make EngineerRepairable conditional. 2020-04-03 04:09:43 -05:00
Zimmermann Gyula
9e534f3804 Add damagetypes to repairing. 2020-03-31 01:10:51 -05:00
Punsho
ca3cfc0184 RA Balance patch 2020-03-29 21:57:12 +02:00
Paul Chote
d62fb901e2 Fix actors with no footprint leaving stale data when deleted. 2020-03-29 21:10:45 +02:00
Matthias Mailänder
73a2b59c2c Add additional notification support to infiltration. 2020-03-29 12:00:16 -05:00
Paul Chote
2c7a56625c Move selectableActor check inside InputOverridesSelection. 2020-03-29 13:20:10 +02:00
Ivaylo Draganov
e2572b214f Adjust spacing and width in editor category dropdown 2020-03-28 20:41:03 +00:00
abcdefg30
d22cd3a74f Adjust the map visibility panel height 2020-03-28 20:41:03 +00:00
abcdefg30
0c8fcedfdf Start with randomized wind strength 2020-03-28 19:46:47 +01:00
Paul Chote
99009c37ce Fix and simplify WeatherOverlay:
- 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
2020-03-28 19:46:47 +01:00
Paul Chote
d9f5771778 Make the right edge of the airfield transitable. 2020-03-28 19:13:14 +01:00
Paul Chote
d35b5070fb Fix minelayers leaking enemy mine positions through the fog. 2020-03-28 18:49:07 +01:00
Paul Chote
02f41f9afc Fix SpriteEffect updating twice in the first tick. 2020-03-28 17:12:25 +01:00
abcdefg30
c797aa1d5e Change syrf to syrd on the desert shellmap 2020-03-27 19:24:22 +01:00
Paul Chote
b2f7f67756 Fix and simplify ScrollPanelWidget thumb rect calculation. 2020-03-26 16:54:46 +01:00
dnqbob
09014ab6d5 transformation can pass exp to new actor 2020-03-26 02:04:44 -05:00
Matthias Mailänder
8f8747d65e Always show the building fake tags 2020-03-26 00:52:24 -05:00
Ivaylo Draganov
be19e137e2 Align lobby bits in the player tab in TD 2020-03-25 13:01:49 +01:00
Paul Chote
3155291064 Restore ability to configure RMB orders + RMB panning. 2020-03-25 12:36:21 +01:00
Paul Chote
a5b22e6a36 Remove text caching from CncLoadScreen.
We have repeatedly failed at invalidating these
cached values when things change, so the small perf
win is not worth the hassle.
2020-03-25 12:20:14 +01:00
Paul Chote
9c251e8b6a Fix detection circle line rendering. 2020-03-24 20:59:46 +01:00
Matthias Mailänder
6056568182 Remove unused terrain type. 2020-03-24 19:48:54 +01:00
Zimmermann Gyula
7b7c1da18d Add a shared parallel production queue. 2020-03-24 13:35:15 -05:00
Paul Chote
fb5b4b3547 Rename Defense button tooltip to Support. 2020-03-24 13:13:18 -05:00
Paul Chote
19918d485e Disable plugs when there are no sockets to place them. 2020-03-24 13:13:18 -05:00
Paul Chote
45c6c6ba10 Fix Waste Refinery bib. 2020-03-24 13:13:18 -05:00
Paul Chote
0e436bc686 Move plugs and superweapons to Building queue. 2020-03-24 13:13:18 -05:00
Ivaylo Draganov
b0dfea0a09 Adjust the stroke of the muted indicator glyph 2020-03-24 16:56:49 +01:00
Paul Chote
2c4e6c4188 Remove special-case rollover rendering. 2020-03-24 00:07:10 -05:00
Paul Chote
9f3254dbd1 Implement isometric selection boxes for TS structures. 2020-03-24 00:07:10 -05:00
Paul Chote
88cdad4189 Add support for polygon selection shapes. 2020-03-24 00:07:10 -05:00
Paul Chote
4ba50a4379 Remove IEquatable from ActorBoundsPair. 2020-03-24 00:07:10 -05:00
Paul Chote
2b6c104011 Update RA decorations. 2020-03-24 00:07:10 -05:00
Paul Chote
4b446d100e Update D2k decorations. 2020-03-24 00:07:10 -05:00
Paul Chote
f9ca2114a9 Update TS decorations. 2020-03-24 00:07:10 -05:00
Paul Chote
afc9c6ef85 Update TD decorations. 2020-03-24 00:07:10 -05:00
Paul Chote
ac200f6173 Rework decoration renderable traits:
- 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.
2020-03-24 00:07:10 -05:00
Paul Chote
73a78eadb1 Move Interactable and Selectable to Mods.Common. 2020-03-24 00:07:10 -05:00
Matthias Mailänder
c5139fb6c2 Remove the hard-coded ban of placing buildings on resources. 2020-03-23 23:48:33 -05:00
Paul Chote
9faf9aa1b9 Replace deprecated native OpenAL with OpenAL Soft on macOS. 2020-03-23 11:13:31 +01:00
unknown
3c2e9be248 Add gdi09ea 2020-03-21 21:09:52 +01:00
Matthias Mailänder
5b59f6612f Remove .lua scripts from the .NET solution file. 2020-03-21 17:30:26 +00:00
abcdefg30
3d69363f35 Add support for destroying enemy carryalls 2020-03-21 10:58:17 +01:00
abcdefg30
b580b4fd33 Add support for an announcement function for carryall reinforcements 2020-03-21 10:58:17 +01:00
abcdefg30
74f86d70f8 Add Ordos06a 2020-03-21 10:58:17 +01:00
abcdefg30
3959104f9b Let VS2019 remove a duplicate line from the solution 2020-03-21 10:58:17 +01:00
Paul Chote
1ff037a257 Remove invalid caching from GCOT. 2020-03-20 17:43:24 +01:00
abcdefg30
32700df117 Fix the settings tooltip container being overwritten ingame 2020-03-20 16:06:06 +01:00
Matthias Mailänder
b4edec215e Fix spy ignoring the target's faction. 2020-03-19 23:11:38 +01:00
Michael Silber
dffa1e45f4 Add gdi08a 2020-03-17 19:04:36 +01:00
Paul Chote
df3b6dde34 Update macOS launcher to fix "View Logs" button. 2020-03-16 20:15:58 +01:00
Matthias Mailänder
834bbf467e Make GlobalLightingPaletteEffect public 2020-03-16 11:10:30 +01:00
Paul Chote
4d4f94208e Cache CandidateMovementCells within the same tick. 2020-03-12 17:07:14 +01:00
Paul Chote
416713de0c Fix infantry switching subcells and blocking eachother while moving. 2020-03-11 15:40:12 +01:00
Paul Chote
c523ca8efe Fix FreeSubCell ignoring preferred subcell requests. 2020-03-11 15:40:12 +01:00
Paul Chote
9acea56108 Fix pathing across transit-only cells. 2020-03-11 15:40:12 +01:00
Paul Chote
44a7422375 Fix variable naming in Locomotor. 2020-03-11 15:40:12 +01:00
abcdefg30
0d0e7eb179 Fix aircraft not taking off properly 2020-03-08 17:20:39 +01:00
abcdefg30
ea6c840343 Fix the panic chance calculation in ScaredyCat 2020-03-08 16:33:23 +01:00
abcdefg30
d2db0913ac Fix the missle jamming chance calculation 2020-03-08 16:33:23 +01:00
Punsho
3721dae74d Making missiles properly go over terrrain and track air units 2020-03-07 13:00:28 +01:00
Matthias Mailänder
9050a2447b Add remappable support to production icons. 2020-03-04 22:02:30 +01:00
abcdefg30
df4c363e9c Notify blockers upon paradropping 2020-03-03 20:51:39 +00:00
abcdefg30
a909a3e692 Ignore self and actors not at ground level in Parachutable.OnLanded 2020-03-03 20:51:39 +00:00
abcdefg30
dd26253905 Fix the IgnoreActor check in Parachutable 2020-03-03 20:51:39 +00:00
abcdefg30
69b7ba2d22 Fix NREs in ProductionParadrop 2020-03-03 20:51:39 +00:00
Paul Chote
d2f306e488 Fix GetActorsAt(CPos, SubCell) with special-case subcells.
If given FullCell or Any we should be returning actors in
any subcell, not none.
2020-03-03 20:06:51 +01:00
Paul Chote
4a6fefa434 Disable idle scanning on RA planes. 2020-03-02 22:22:56 +01:00
Paul Chote
16e0ea611e Revert "Fix AttackFollow ignoring allowMove flag when auto-targeting."
This reverts commit 3e116060cf.
2020-03-02 22:22:56 +01:00
Paul Chote
05a2e77be2 Add support for uncompressed databases. 2020-03-02 17:29:30 +01:00
Paul Chote
dd2fa36261 Fix invalid channel server crash. 2020-03-02 17:29:30 +01:00
abcdefg30
5fa1dec6d8 Fix a crash in --clear-invalid-mod-registrations 2020-03-02 17:26:34 +01:00
Paul Chote
f86d96794d Add explicitly defined version strings to the lua docs. 2020-03-02 17:24:17 +01:00
Paul Chote
304307df5a Fix wiki script again. 2020-03-01 16:41:19 +00:00
Paul Chote
c8856749f3 Only update the wiki from the Linux host. 2020-03-01 16:10:07 +00:00
Paul Chote
ce91c5a76f Fix WithDisguisingInfantryBody idle animation crash. 2020-03-01 14:43:12 +01:00
Paul Chote
e6314a944c Round dropdown arrow position to an integer pixel. 2020-03-01 14:41:17 +01:00
Paul Chote
93d006e14e Fix incorrect end point rendering in DrawConnectedLine. 2020-02-29 18:13:54 +01:00
Paul Chote
d73ed7670a Port missions to the new Paratroopers API. 2020-02-29 16:07:24 +01:00
Paul Chote
c0587cc568 Introduce ActivateParatroopers Lua API.
SendParatroopers and SendParatroopersFrom are now deprecated.
The paratrooper actors themselves can be accessed using the
Trigger.OnPassengerExited trigger.
2020-02-29 16:07:24 +01:00
Paul Chote
ed415cb637 Remove deprecated *Upgrade Lua API methods. 2020-02-29 16:07:24 +01:00
abcdefg30
a10deddf53 Update the Lua API 2020-02-28 18:48:05 +01:00
abcdefg30
a5bc841355 Ignore the types of an exit when the production type is null or empty 2020-02-28 18:48:05 +01:00
Paul Chote
41657dd291 Allow spectators to be kicked after the game starts. 2020-02-28 00:04:49 +01:00
abcdefg30
a7d5b7b8b0 Fix FreeActorWithDelivery not being properly conditional 2020-02-27 18:50:51 +01:00
reaperrr
eb007fc43c Add Frames support to Combine 2020-02-27 18:44:34 +01:00
Paul Chote
301d09ea8f Remove undefined RequiresForceMove from TransformsIntoTransforms. 2020-02-27 18:42:48 +01:00
Paul Chote
ac46b4b791 Fix transparent pixels in Mobile Flack icon. 2020-02-27 00:11:39 +01:00
Paul Chote
fb7c781a66 Add multi-resolution mod icon support. 2020-02-26 23:47:15 +01:00
Paul Chote
e5309ee586 Remove unused InstalledMods.Icons cache. 2020-02-26 23:47:15 +01:00
Paul Chote
84df61c672 Add multi-resolution badge support. 2020-02-26 23:47:15 +01:00
Paul Chote
de4a7cecf0 Rework multi-resolution sprite handling:
- 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.
2020-02-26 23:47:15 +01:00
abc013
c0ece00c4b Prevent production cycling when producing actor does not occupy space 2020-02-26 23:25:41 +01:00
Paul Chote
6ba02800ab Add TransformsIntoTransforms to enable queued MCV redeploy. 2020-02-24 12:56:49 +01:00
Paul Chote
84419e4259 Add queued argument to CanIssueDeployOrder. 2020-02-24 12:56:49 +01:00
Paul Chote
2016ab105e Fix Reverses parsing. 2020-02-23 16:41:57 +01:00
Paul Chote
def65b10bd Don't crash with an unhelpful IndexOutOfRangeException. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
31d98cc802 Reduce the electro death loop length. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
ccbaa4f816 Setup the original laser zap death animation. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
2049d1b26a Allow guessing of sprite sequence length from number of frames. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
15f8469272 Use the original elongated tesla zap death animation. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
43cac2f051 Don't complain about shadow frame length when there are none. 2020-02-23 16:41:57 +01:00
Matthias Mailänder
39b7db2703 Allow repetition of frames in sequence setups. 2020-02-23 16:41:57 +01:00
Paul Chote
d3291ea585 Fix script error in ordos05. 2020-02-23 11:03:23 +01:00
Ivaylo Draganov
2e8740d6a8 Change default hotkey bindings for select and cycle production buildings 2020-02-22 20:06:21 +00:00
Ivaylo Draganov
1bcad55c1f Add a hotkey to select the current production facility 2020-02-22 20:06:21 +00:00
Paul Chote
7ffc689037 Fix TD panel-transparent definition. 2020-02-22 12:39:11 -06:00
Paul Chote
7d17916e3f Load badges on the main thread. 2020-02-22 19:19:20 +01:00
abcdefg30
e877bb1206 Fix GrantConditionOnProduction not using ShowSelectionBar 2020-02-22 18:05:40 +00:00
reaperrr
226159d220 AttackBase ResolveOrder optimization
Only check for "Stop" when the other 'if' didn't apply.
2020-02-22 17:56:47 +00:00
reaperrr
da4ed24064 Mobile ResolveOrder optimization
When the order is "Move", the other two 'if' checks
are redundant, so 'else if' makes more sense here.
2020-02-22 17:56:47 +00:00
reaperrr
b524dc9b72 Carryall ResolveOrder optimization
There can be only one OrderString at a time,
so we make 'PickupUnit' an "else if", too.
2020-02-22 17:56:47 +00:00
reaperrr
1e43a8f590 Minor Aircraft ResolveOrder optimization
Streamline RTB if checks.
2020-02-22 17:56:47 +00:00
Matthias Mailänder
805a8fc556 Specify unicode without BOM as standard. 2020-02-22 18:44:10 +01:00
Robert
885931ae74 Run every color validation together
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!)
2020-02-22 16:31:29 +00:00
Robert
4d4f1d6068 Avoid null vectors when making colors valid
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.
2020-02-22 16:31:29 +00:00
Robert
fafa219d11 Added error message if color could not be adjusted
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.
2020-02-22 16:31:29 +00:00
Paul Chote
eae287efc3 Fix travis packaging. 2020-02-22 10:28:48 -06:00
Paul Chote
8903577227 Update native libraries shipped in the AppImages:
* SDL2 reverted back to 2.0.8 (2.0.9 and 2.0.10 generate compilation
  errors so are missing from the libs tarball)
* Package Freetype 2.0.10
2020-02-22 10:28:48 -06:00
Matthias Mailänder
103cb61020 Add a new rallypoint established notification. 2020-02-22 17:16:17 +01:00
Ivaylo Draganov
1dd1786469 Reduce duplication of "Battlefield Control" chat line label 2020-02-22 15:58:00 +00:00
Ivaylo Draganov
3e2022a3dd Allow players to mute shellmap background music 2020-02-22 15:50:01 +00:00
Paul Chote
28f7604172 Reset nextScanTime only when actually scanning for targets. 2020-02-22 16:30:07 +01:00
Paul Chote
96463634c7 Add --debug-chrome-regions utility command. 2020-02-22 16:18:45 +01:00
Paul Chote
01f5ecb2f9 Fix save game loading screen stripe bounds. 2020-02-22 16:14:32 +01:00
reaperrr
d835090d0b Move LCWCompression support to Mods.Cnc 2020-02-22 15:40:37 +01:00
reaperrr
c687600d66 Duplicate part of LCWCompression to VqaReader
Duplicates the part needed by the VqaReader,
so we can move LCWCompression to Mods.Cnc
ahead of VQA (which has some additional prerequisites).
2020-02-22 15:40:37 +01:00
reaperrr
ed618c807d Streamline LCWCompression code
Just making it more concise to reduce line count.
No functionality/efficiency changes.
2020-02-22 15:40:37 +01:00
Paul Chote
85faa5edf6 Add visual indicator when the game is muted. 2020-02-22 14:42:11 +01:00
Paul Chote
3f601e1ec1 Update color picker hue slider when the color changes. 2020-02-22 14:00:12 +01:00
teinarss
9d68b815a1 Fix tooltip in Observer widgets 2020-02-22 11:38:53 +01:00
teinarss
cffe5e3d9d Add owner token to TooltipContainer 2020-02-22 11:38:53 +01:00
Paul Chote
7e72cd262c Fix FlyAttack invalid target crash. 2020-02-19 23:35:16 -06:00
Paul Chote
9a6602656b Ignore nearEnough if we think the actor can get closer. 2020-02-18 19:37:17 +01:00
Matthias Mailänder
57da756f2f Set the camera pitch to 30° 2020-02-18 00:49:04 +01:00
abcdefg30
40bb45a02b Deprecate the release-20181215 path 2020-02-17 20:14:56 +00:00
abcdefg30
f73d23661f Update the update paths for release-20200202 2020-02-17 20:14:56 +00:00
Paul Chote
09a019f9c6 Add a lint check for LockFaction on mission players. 2020-02-16 20:51:29 +01:00
Paul Chote
4ec258cbdd Add missing LockFaction definitions to nod09, 10a, 10b. 2020-02-16 20:51:29 +01:00
Paul Chote
41d7a2d429 Fix an integer overflow when calculating selection priorities. 2020-02-16 17:57:04 +01:00
abcdefg30
7cec1b771d Fix Actor.CurrentActivity bogusly pointing to finished activities 2020-02-16 16:58:06 +01:00
abcdefg30
b1b74c13c3 Ensure that we never tick an activity before calling OnFirstRun 2020-02-16 16:58:06 +01:00
abcdefg30
c4a5540bfd Ensure that we never run Done child activities 2020-02-16 16:58:06 +01:00
abcdefg30
abcb2ea512 Directly mark queued activities that are cancelled as Done 2020-02-16 16:58:06 +01:00
Paul Chote
f45dd24781 Update AppImage SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
8d23994a04 Update Windows SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
46e0b3b363 Update macOS SDL2 dependency to 2.0.10. 2020-02-16 14:53:42 +01:00
Paul Chote
689049cc12 Fix NRE in ArmyUnit constructor. 2020-02-16 13:57:19 +01:00
Paul Chote
1485194ef3 Automatically scale DPI under Linux. 2020-02-16 13:44:50 +01:00
Paul Chote
4203a3191f Overhaul macOS packaging:
- 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
2020-02-15 18:51:21 +01:00
Paul Chote
7b4019577d Force disable glDebugMessageCallback on Linux+AMD. 2020-02-15 11:38:30 +01:00
Paul Chote
52f4e24e22 Fix spectator minimap not updating when in "Disable Shroud" view. 2020-02-14 23:07:31 +01:00
Paul Chote
ab196a23e6 Fix AttackFollow ignoring allowMove flag when auto-targeting. 2020-02-14 17:30:38 +01:00
Paul Chote
3a688e03f0 Add multiple levels of fallback. 2020-02-12 21:17:39 +00:00
Paul Chote
a43335c7b0 Restore transient blocker check in pathfinding queries. 2020-02-12 21:17:39 +00:00
Paul Chote
585b8dc13c Set default rally point to an empty path. 2020-02-09 16:52:22 +01:00
Paul Chote
b2f0ac15e8 Generalize RallyPointInfo.Offset to support arbitrary length paths. 2020-02-09 16:52:22 +01:00
Paul Chote
9dc4ea8541 Fix production door not closing if the actor stays on the exit cell. 2020-02-09 16:52:22 +01:00
teinarss
817f75c808 Add unique ingame-observer.yaml for D2K 2020-02-09 16:37:21 +01:00
teinarss
7e3830e053 Updated production spec widget to handle overflow 2020-02-09 16:37:21 +01:00
teinarss
b81ede2d64 Added widget showing the army for players in spec 2020-02-09 16:37:21 +01:00
Mustafa Alperen Seki
6ab0ace9e1 Add PlayLaunchSounds() to SupportPowers which are missing it. 2020-02-09 13:34:46 +01:00
Paul Chote
85a5b6cc17 Fix subcell crusher logic. 2020-02-09 13:18:57 +01:00
Ivaylo Draganov
62af58c2e6 Calculate position of dropdown arrow glyph based on image width 2020-02-09 12:53:30 +01:00
abcdefg30
aeacc86028 Remove a loop closure guard variable 2020-02-09 12:18:09 +01:00
abcdefg30
5c4ec1bf0e Fix a crash when a SourceActor does not occupy space 2020-02-09 12:18:09 +01:00
abcdefg30
e3f545cae9 Make WarheadArgs.Source nullable 2020-02-09 12:18:09 +01:00
Paul Chote
71cbfc5968 Change default player color to dark red. 2020-02-08 20:09:02 +01:00
Paul Chote
fdc3a6a32d Change default name from Newbie to Commander. 2020-02-08 20:09:02 +01:00
Paul Chote
e6c1356d59 Add introduction prompt on first run. 2020-02-08 20:09:02 +01:00
Paul Chote
e8df28c518 Extract sysinfo logic to its own class. 2020-02-08 20:09:02 +01:00
Martin Bertsche
98aef70e88 Added display selection option to settings for fullscreen modes. 2020-02-08 18:14:35 +00:00
abcdefg30
de0bb9ee39 Fix a crash in the ReplaceAttackTypeStrafe update rule 2020-02-06 21:52:46 +00:00
tovl
c18857f15d Let immovable actors block individual minefield cells. 2020-02-06 22:26:15 +01:00
Paul Chote
9a0916afbb Add UI Scale dropdown to the settings menu. 2020-02-04 19:56:15 +01:00
Paul Chote
6388a6bff4 Add Graphics.UIScale setting to modify UI size. 2020-02-04 19:56:15 +01:00
Paul Chote
ce445f993c Add SupportDir argument to the launch-dedicated scripts. 2020-02-04 00:21:52 +01:00
Paul Chote
0e39c98989 Ignore empty support directory overrides. 2020-02-04 00:21:52 +01:00
Paul Chote
c2bc313bf0 Fix key repeat events queueing many deploy/scatter/stop orders. 2020-02-01 13:18:04 +01:00
Paul Chote
5c76a6e7a7 Fix key up events queueing duplicate deploy/scatter/stop orders. 2020-02-01 13:18:04 +01:00
Matthias Mailänder
1e8912b4e4 Fix the namespace. 2020-02-01 02:42:25 +01:00
abcdefg30
6cc27eaa76 Fix the description of VeteranProductionIconOverlay 2020-01-31 13:55:56 +01:00
Ivaylo Draganov
1020a7bfab Use common notice colors for UPnP status labels 2020-01-31 00:50:25 +01:00
Ivaylo Draganov
b80928bd95 Display a confirmation prompt on settings panel reset 2020-01-30 23:06:49 +01:00
abcdefg30
a6371f6fa9 Fix mission specific buildings not granting prerequisites 2020-01-29 20:59:45 +00:00
Paul Chote
bf314fdc7b Define window size in effective pixel coordinates. 2020-01-26 20:22:49 +01:00
Paul Chote
f0033c44c7 Use full window resolution on Windows. 2020-01-26 20:22:49 +01:00
Paul Chote
fd64ad7c89 Support rendering at non-integer display scales:
* 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.
2020-01-26 20:22:49 +01:00
Paul Chote
809b1507a6 Fix font rendering at non-integer display scales. 2020-01-26 20:22:49 +01:00
Paul Chote
d91495a041 Allocate 1px empty margin between sprites. 2020-01-26 20:22:49 +01:00
Paul Chote
84daf890d3 Use antialiasing filter when rendering world annotations. 2020-01-26 20:22:49 +01:00
Paul Chote
1bc6fb0f46 Use antialiasing filter when rendering UI icons and actors. 2020-01-26 20:22:49 +01:00
Paul Chote
1f849e9f7d Add antialiasing support for paletted sprites. 2020-01-26 20:22:49 +01:00
Paul Chote
bd4724842c Fix software cursor rendering at fractional scales. 2020-01-26 20:22:49 +01:00
Paul Chote
25a7299c67 Fix scroll event position calculation. 2020-01-26 20:22:49 +01:00
Paul Chote
518450cd8a Extract load screen sheet handling into a superclass. 2020-01-26 20:22:49 +01:00
Paul Chote
57a8cf7a59 Rework Display settings tab. 2020-01-26 17:11:45 +01:00
Paul Chote
83732f299b Add DropDownButtonWidget.PanelAlign. 2020-01-26 17:11:45 +01:00
Paul Chote
f730b55255 Move hardware cursor control to hidden DisableHardwareCursors setting. 2020-01-26 17:11:45 +01:00
Paul Chote
370f7a44fa Restore cursor doubling for "default" cursor. 2020-01-26 17:11:45 +01:00
Paul Chote
f7e5111123 Apply cursor doubling setting without requiring a restart. 2020-01-26 17:11:45 +01:00
Paul Chote
847db5e59b Merge HardwareCursor and SoftwareCursor into CursorManager. 2020-01-26 17:11:45 +01:00
Mustafa Alperen Seki
d7f43b33c7 Make GrantConditionOnAttack PausableConditional 2020-01-26 17:05:02 +01:00
Paul Chote
3a6d88cfef Align settings to the standard row height. 2020-01-26 16:52:14 +01:00
Paul Chote
70f899c8d1 Remove unused localization options from settings.yaml. 2020-01-26 16:52:14 +01:00
Paul Chote
e138afc328 Overhaul Input settings. 2020-01-26 16:52:14 +01:00
Paul Chote
a84c914317 Move highlighting logic into a dedicated widget. 2020-01-26 16:52:14 +01:00
Paul Chote
46d59eef5e Update TD cash glyphs. 2020-01-25 22:02:43 +01:00
Paul Chote
79d25b9eca Update RA cash glyphs. 2020-01-25 22:02:43 +01:00
Paul Chote
cc530649c7 Fix horizontal positioning of dropdown arrow glyph. 2020-01-25 21:56:02 +01:00
abcdefg30
aeb623498f Remove old update rules 2020-01-25 21:29:36 +01:00
Mustafa Alperen Seki
d4b08850f3 Fix conditionality of DisguiseTooltipInfo. 2020-01-25 17:28:15 +02:00
Paul Chote
1fada0f2b4 Add KHR suffix as defined by the KHR_debug spec. 2020-01-25 13:44:06 +01:00
Paul Chote
b08f9886be Add Graphics.DisableGLDebugMessageCallback setting. 2020-01-25 13:44:06 +01:00
reaperrr
46384d25f2 Improve Rectangle HitShape debug overlay
Showing vertical sides, too.
2020-01-25 13:38:35 +01:00
reaperrr
9dcba8710b Add turret-linking support to HitShape
Allows to link a HitShape to the
position and facing of a turret.
2020-01-25 13:38:35 +01:00
reaperrr
b839204c7f Minor WithInfantryBody reorganisation
Move PlayStandAnimation to a more suitable position
inside the file.
2020-01-25 13:26:25 +01:00
reaperrr
595b6c8923 Greatly simplified WithInfantryBody TickIdle code
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.
2020-01-25 13:26:25 +01:00
Ivaylo Draganov
9474bdba5c Use proper glyph for in-game chat close button 2020-01-25 13:17:09 +01:00
abcdefg30
f5aa304e09 Add stray update rules to the correct path 2020-01-25 10:48:50 +00:00
Pavel Penev
93bec9e430 Updated the default mods' weapons 2020-01-24 13:09:37 +01:00
Pavel Penev
d33a5bf94e Added an UpgradeRule CreateScreenShakeWarhead 2020-01-24 13:09:37 +01:00
Pavel Penev
b00154e2bc Created ShakeScreenWarhead and removed the hardcoded shaking from NukeLaunch and MadTank 2020-01-24 13:09:37 +01:00
reaperrr
6220d7e62e Introduce WarheadArgs
- Passes additional arguments to warheads on impact
- Uses that to reduce parameter count of DoImpact by 1
2020-01-21 19:31:34 +01:00
Paul Chote
fdc0a6e2b9 Rework TS Chrome in preparation for UI scaling. 2020-01-19 20:36:59 +01:00
Paul Chote
f37d9a7010 Rework D2k Chrome in preparation for UI scaling. 2020-01-19 20:34:18 +01:00
abcdefg30
9f66e3936d Add issue templates for the new issue template chooser 2020-01-19 17:27:43 +01:00
Paul Chote
f1325e12d4 Extract text contrast radius to ChromeMetrics and reduce to 1px. 2020-01-19 17:18:22 +01:00
Paul Chote
7611449d3d Reimplement text contrast using greyscale dilation. 2020-01-19 17:18:22 +01:00
abcdefg30
15b2d6b9e0 Let all Positionable traits notify visual position changes 2020-01-18 23:07:23 +00:00
Paul Chote
d0f44143c2 Fix activity cancellation on FlyAttack RTB.
* 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).
2020-01-18 16:38:53 +01:00
Paul Chote
51870a471a Add AttackSource enum. 2020-01-18 16:38:53 +01:00
Paul Chote
6f52365f9d Don't run NextActivity if it has been canceled. 2020-01-18 16:38:53 +01:00
Paul Chote
66b8689957 Use 32bit modcontent cursor. 2020-01-17 16:49:58 +01:00
Paul Chote
4fd475f7c2 Add RGBA cursor support. 2020-01-17 16:49:58 +01:00
Paul Chote
522861e484 Support 32 bit png sprites. 2020-01-17 16:49:58 +01:00
Paul Chote
1111ce4754 Add support for 32 bit BGRA sprites. 2020-01-17 16:49:58 +01:00
Paul Chote
cdbee49280 Fix slider ticks in TD. 2020-01-17 13:42:51 +01:00
reaperrr
aa63696933 Update rule for WithPermanentInjury removal 2020-01-16 22:56:39 +01:00
reaperrr
10540839f6 Make crippled TS Cyborgs use permanent TakeCover
This is more in line with original behavior.
Also allows us to remove WithPermanentInjury.
2020-01-16 22:56:39 +01:00
reaperrr
a9eca2cf54 Add support for enabling prone state permanently
Negative ProneTime now activates prone state
permanently as soon as the trait is enabled.
2020-01-16 22:56:39 +01:00
Paul Chote
d6436858a9 Fix IPAddress capitalization. 2020-01-15 12:12:54 +01:00
Paul Chote
38cb818469 Anonymise client IPs and allow server operators to disable sharing. 2020-01-15 12:12:54 +01:00
Paul Chote
422cc2b0d0 Hide location and IP labels if not known. 2020-01-15 12:12:54 +01:00
Paul Chote
d74a5065b9 Require GeoLite2 database path to be specified by the server operator. 2020-01-15 12:12:54 +01:00
Paul Chote
6b2c019caa Evaluate player location on the server. 2020-01-15 12:12:54 +01:00
Paul Chote
c430884c8b Require GeoLite2 database path to be specified by the server operator. 2020-01-15 12:12:54 +01:00
Matthias Mailänder
8dda6d8e3d Remove unnecessary null check. 2020-01-14 22:08:57 +01:00
Matthias Mailänder
c43d581e7f Add cursor palette support to GIMP/Jasc palette definitions. 2020-01-14 22:08:57 +01:00
teinarss
f0b69f8b8d Separated resource rendering into another trait 2020-01-14 19:38:47 +01:00
Matthias Mailänder
0e93d85273 Move the AssetBrowserFileEndingsFilter to IGlobalModData
to avoid mods having to duplicate the whole chrome layout.
2020-01-13 13:46:34 +01:00
Paul Chote
adb3c8e39c Split fixed-wing attack and strafe attack types. 2020-01-12 21:06:35 +01:00
tovl
85bc843554 Fix aircraft failing to engage targets within range. 2020-01-12 21:06:35 +01:00
Matthias Mailänder
c95216cd19 Move the hard-coded shroud palette to the C&C folder. 2020-01-12 19:35:41 +00:00
Paul Chote
cc05621c10 Draw editor terrain/resource preview as part of the world. 2020-01-12 18:30:50 +01:00
Paul Chote
e74033bded Render editor actor previews as part of the world. 2020-01-12 18:30:50 +01:00
Paul Chote
fe25fdf0ff Improve robustness of editor actor cell checks. 2020-01-12 18:30:50 +01:00
Paul Chote
1282650274 Rework RA Chrome in preparation for UI scaling. 2020-01-12 18:16:41 +01:00
Paul Chote
d622015b59 Fix Texture.GetData under GLES. 2020-01-12 17:04:23 +01:00
Paul Chote
524e8875d0 Restore MODIFIER_OVERRIDES handling of unmodified attack move hotkey. 2020-01-12 16:33:35 +01:00
Paul Chote
8c2a2d2cb8 Rework TD/modcontent chrome in preparation for UI scaling. 2020-01-12 15:52:12 +01:00
abcdefg30
a28992aa38 Default LocalClientId in ReplayConnection to -1
We do not have a local client in replays.
This change prevents anything from accidentally using (sometimes there might be clients with ID 0 present).
2020-01-12 14:23:34 +01:00
Paul Chote
0db4085950 Load and save registrations to both the active and legacy support directories. 2020-01-12 14:10:23 +01:00
Paul Chote
f162d90e9f Rework support dir initialization. 2020-01-12 14:10:23 +01:00
abcdefg30
abfb28a4f3 Fix the Build function in gdi04b 2020-01-12 14:04:51 +01:00
abcdefg30
c15a555cff Fix cargo initialisation 2020-01-12 13:58:04 +01:00
abcdefg30
e1c07d32d5 Prevent cell triggers in sarin-gas-2 from firing several times 2020-01-12 13:49:25 +01:00
tovl
fbfef903ac Let movement trigger visibility recalculation. 2020-01-12 04:50:25 +01:00
tovl
695d9a6cb1 Centralize shroud changes in one pass to improve performance. 2020-01-12 04:50:25 +01:00
Paul Chote
0106ed3669 Restore red lines for harvester targets. 2020-01-12 04:08:59 +01:00
abcdefg30
ac42dd79ca Make the command bar directly check if a GuardOrderGenerator is active 2020-01-12 00:54:38 +00:00
abcdefg30
deffc2dd15 Add support for defining the palette of WithResourceLevelOverlay 2020-01-12 00:47:20 +00:00
reaperrr
bb1d5f1d5c Fix ReloadAmmoPool.ResetFire ignoring multipliers 2020-01-11 23:29:37 +00:00
teinarss
43eabdf54a Fix naming in editor 2020-01-11 22:03:26 +00:00
tovl
0e32cbee5e Fix crash in RallyPointIndicator. 2020-01-11 21:26:47 +00:00
reaperrr
308c64c7b1 Fix trait order issues with KillsSelf 2020-01-06 21:47:53 +00:00
reaperrr
16c2062d9d Replace LandOnCondition with landing when paused 2020-01-06 21:47:53 +00:00
reaperrr
ac44367440 Refactor Spin to MaximumSpinSpeed
Additionally, add descriptions to
other FallsToEarth properties.
2020-01-06 21:47:53 +00:00
reaperrr
20beb4abe1 Fix Harpy husk rotor offset 2020-01-06 21:47:53 +00:00
reaperrr
a369634ea8 Display EMP effect on EMP'd aircraft's husks
When EMP'd while airborne.
2020-01-06 21:47:53 +00:00
reaperrr
7a095f30ec Make TS aircraft crash when EMP'd mid-air
And refuse move orders if EMP'd while landed.
Matches original behaviour.
2020-01-06 21:47:53 +00:00
Punsho
59bcac410f Make EMP effect carryall and orca transport 2020-01-06 21:47:53 +00:00
reaperrr
4499343ed2 Make Aircraft actually pausable/disableable
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
2020-01-06 21:47:53 +00:00
reaperrr
4b006bc484 Make Aircraft PausableConditional
Note: This commit only does the minimum changes
to implement PausableConditional, there are no
logic changes yet (like disabling movement on PauseOnCondition).
2020-01-06 21:47:53 +00:00
abcdefg30
23b3c237b7 Update the year numbers in all license headers to 2020 2020-01-05 17:00:34 +00:00
Matthias Mailänder
e33cf8a8ae Fix a crash when cursor is null. 2020-01-05 13:27:53 +00:00
Matthias Mailänder
7e9a3d3bc9 Unhardcode transparent index in manual palettes as well. 2020-01-05 13:17:43 +00:00
Matthias Mailänder
6ea85a1a62 Don't hard-code the transparent background color. 2020-01-05 13:17:43 +00:00
Ivaylo Draganov
535144b208 Use system chat line for audio muted/unmuted notifications 2020-01-04 23:05:25 +00:00
Paul Chote
439cd4aded Rework HardwareCursor sprite padding.
All frames in a sequence now use the same bounds
and hotspot, and have a size that is a multiple of 8.
2020-01-04 22:45:51 +01:00
tovl
2094142b7d Include tunnel check in CanStayInCell. 2020-01-04 16:04:27 +00:00
tovl
196d9670d3 Disallow units from idling on bibs in TS. 2020-01-04 16:04:27 +00:00
tovl
434c46058f Disallow units idling on service depot. 2020-01-04 16:04:27 +00:00
tovl
c360d8bcef Make service depot passable. 2020-01-04 16:04:27 +00:00
teinarss
76221471ff Remove unused code from Cargo trait 2020-01-03 19:34:56 +01:00
teinarss
a9d7535915 Remove cargo initialization from Tick 2020-01-03 19:34:56 +01:00
teinarss
20610d05a2 Remove CurrentAdjacentCells update on each tick in Cargo 2020-01-03 19:34:56 +01:00
Ivaylo Draganov
af5d8a3bbe Add a hotkey to cycle harvesters 2020-01-02 23:42:22 +01:00
abcdefg30
ab348336f5 Fix ants teleporting into the map area
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.
2020-01-02 16:34:38 +00:00
reaperrr
804d61a6a1 Fix DeliverUnit-related crash 2020-01-01 20:42:36 +01:00
Paul Chote
baa5b3d25e Bypass fingerprint validation for skirmish/mission servers. 2020-01-01 20:33:30 +01:00
Paul Chote
8f2bf27edf Replace Server.Dedicated with Server.Type. 2020-01-01 20:33:30 +01:00
abcdefg30
a9f37bc9f1 Remove a leftover geoip reference from the linux packaging script 2019-12-31 17:03:05 +00:00
unknown
79136a520f Remove dublicate function 2019-12-31 17:32:43 +01:00
Paul Chote
adf1c0b616 Remove GeoIP database from install/packaging scripts. 2019-12-31 17:28:30 +01:00
Paul Chote
e063e13ff4 Remove automatic GeoIP download from the build scripts.
The database file is now locked behind an account login.

https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases/
2019-12-31 17:28:30 +01:00
reaperrr
9d7ecdbc2c Disable SupportPowerInstances when player lost
Fixes bots using player actor powers after defeat.
2019-12-30 22:50:54 +01:00
reaperrr
7a57f0e6ef Expose delay of WithDeathAnimation
Allows to show it a few ticks after death if the modder
wishes so.
2019-12-30 18:01:09 +00:00
reaperrr
c55c65f6d7 Add delay support to SpriteEffect 2019-12-30 18:01:09 +00:00
reaperrr
037ce9ebf3 Rename ProneTime to Duration
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.
2019-12-30 11:34:41 +01:00
reaperrr
cef940fea9 Fix TakeCover to be disabled properly
Speed and Damage modifiers were ignoring IsTraitDisabled.
2019-12-30 11:34:41 +01:00
Paul Chote
a7ae93978a Disable sound controls when no audio device is available. 2019-12-29 17:53:44 +01:00
Paul Chote
4052620f94 Rename dummy sound label to "No Sound Output". 2019-12-29 17:53:44 +01:00
Paul Chote
032c412e09 Fix WithTextDecoration rendering. 2019-12-28 21:44:26 +01:00
Paul Chote
5a686b3289 Fix duplicated/distorted SequencePlaceBuildingPreview annotations. 2019-12-28 20:56:09 +01:00
Paul Chote
2bf16a34d6 Filter invalid actor IDs when restoring selection save data. 2019-12-28 20:48:46 +01:00
Paul Chote
7ccc63b51c Fix incorrect region definitions. 2019-12-28 19:15:36 +01:00
Paul Chote
e7253fd643 Manual chrome.yaml cleanups. 2019-12-28 19:15:36 +01:00
Paul Chote
f3d7bf403e Rework chrome.yaml format and panel rendering. 2019-12-28 19:15:36 +01:00
Paul Chote
0b8a367867 Fix MiniYaml parsing of empty comments 2019-12-28 19:15:36 +01:00
abcdefg30
aabfd91001 Fix an indentation style issue in TransformsIntoAircraft 2019-12-28 19:16:21 +03:00
Ivaylo Draganov
3d1b4c2509 Remove "Surrender" button for single player games 2019-12-28 15:06:26 +00:00
Ivaylo Draganov
14bc7885b3 Always prompt the user to confirm when leaving a game 2019-12-28 15:06:26 +00:00
Ivaylo Draganov
2204e807b8 Add restart button to main menu for single player (missions, skirmish, replays) 2019-12-28 15:06:26 +00:00
abcdefg30
baa50c9c53 Pass DamageTypes in Explodes 2019-12-28 10:54:27 +01:00
Paul Chote
7d887f0332 Fix NV shader compile errors in combined.frag. 2019-12-27 20:20:42 +01:00
Paul Chote
51eaa17b1e Replace frame limit text field with a slider. 2019-12-26 17:25:38 +01:00
Paul Chote
35a36b4cdf Disable frame limiter by default
VSync does a more reliable job of this.
2019-12-26 17:25:38 +01:00
Paul Chote
2231183fe0 Account for game ticks when applying the frame limiter. 2019-12-26 17:25:38 +01:00
Paul Chote
656a260171 Add VSync setting. 2019-12-26 17:25:38 +01:00
abcdefg30
959c750851 Move voice playing for orders into a helper function 2019-12-23 15:01:36 +01:00
abcdefg30
4d407da3e6 Fix a potential crash in PlayVoiceForOrders 2019-12-23 15:01:36 +01:00
abcdefg30
bb1d1f8140 Remove a nowadays unnecessary loop safeguard 2019-12-23 14:57:50 +01:00
abcdefg30
d2db707521 Move unit order resolving into a helper function 2019-12-23 14:53:13 +01:00
Abdurrahmaan Iqbal
a107da0888 Fix for mod credits overriding engine credits 2019-12-23 13:48:47 +00:00
Paul Chote
b1f7c5c4e3 Remove overlapping vision ranges from RA actors.
This brings a significant perf saving by reducing
the number of evaluated tiles.
2019-12-23 13:53:08 +01:00
Paul Chote
04bad1ae66 Add MinRange support to AffectsShroud. 2019-12-23 13:53:08 +01:00
Paul Chote
5830d4de6c Fix ATEK vision ranges. 2019-12-23 13:53:08 +01:00
abcdefg30
bb85146544 Make orcas buildable on nod07c 2019-12-21 00:48:03 +01:00
abcdefg30
c4ab5d4561 Fix/Update the patrols on nod07c 2019-12-21 00:48:03 +01:00
abcdefg30
54e2aad1cd Fix broken reinforcements on gdi04 and limit them to 3 waves 2019-12-21 00:48:03 +01:00
abcdefg30
b1f6c69fce Use a global script in Tiberian Dawn 2019-12-21 00:48:03 +01:00
abcdefg30
dbe73a06ad Remove ISync from RallyPoint 2019-12-15 23:21:27 +01:00
Paul Chote
f36d0cc214 Fix ModContent cursor. 2019-12-15 22:29:26 +01:00
abcdefg30
1e138a9774 Drop invisible invalid targets immediately when changing stance 2019-12-14 17:17:36 +01:00
abcdefg30
905e02b765 Prevent a crash in AutoTarget.HasValidTargetPriority 2019-12-14 17:17:36 +01:00
Paul Chote
3487846636 Restore NukePower support for proxy actors. 2019-12-14 17:07:16 +01:00
tovl
203fff0ab7 Allow queued structure rallypoints. 2019-12-13 23:51:03 +01:00
tovl
3236499fb7 Increase IMove.MoveTo call flexibility. 2019-12-13 23:51:03 +01:00
Paul Chote
28dbda29e3 Add zoom hotkeys. 2019-12-13 21:29:43 +01:00
Paul Chote
1dcb903580 Implement new viewport size/zoom UI. 2019-12-13 21:29:43 +01:00
Paul Chote
860117daf9 Implement optimized pixel-art antialiasing mode for non-integer world zoom. 2019-12-13 21:29:43 +01:00
Paul Chote
cd368b43df Draw GPS dots using the UI renderers. 2019-12-13 21:29:43 +01:00
Torleif West
ae4b2591bf fix for RA2 cloning vats
formatting

minor formatting

passing CI

closing line bracket

use production unit

opening should not be followed by a blank line

revert tab change
2019-12-12 22:08:25 +01:00
Paul Chote
b0c65c5eb9 Overhaul cursor double setting. 2019-12-11 13:38:52 +01:00
Paul Chote
010fafc6d3 Fix hardware cursors on systems with >150% DPI scaling. 2019-12-11 13:38:52 +01:00
Paul Chote
79aac08a48 Fix turret positioning in the map editor. 2019-12-11 11:02:04 +01:00
Paul Chote
630ca0aefb Draw editor selection box using the UI renderers. 2019-12-11 11:02:04 +01:00
abcdefg30
2918ecadaa Fix team chat messages not always being displayed 2019-12-10 13:05:38 +01:00
reaperrr
82be8d9990 Move AUD support to Mods.Cnc 2019-12-09 22:06:53 +01:00
reaperrr
4d92fde5f7 Remove VqaReader dependency on AudReader
Use ImaAdpcmReader directly, since VQAs only contain
header-less raw IMA  ADPCM audio.
2019-12-09 22:06:53 +01:00
reaperrr
5afc1c1443 Remove duplication between IMA and AUD readers
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.
2019-12-09 22:06:53 +01:00
abcdefg30
22374ed732 Remove the bogus 'GameSaved' speech notification definition 2019-12-08 21:56:24 +01:00
abcdefg30
bc484a9858 Add 'AirstrikeReady' to 'DisablePrefixes' 2019-12-08 21:56:24 +01:00
abcdefg30
9a57980952 Remove 'AbilityInsufficientPower' from cnc's notifications 2019-12-08 21:56:24 +01:00
Ivaylo Draganov
0900ac2b2f Remove stray "Hotkeys" label in the Input Settings panel in TD 2019-12-08 21:38:28 +01:00
reaperrr
4751b1a176 Move ShpTDLoader, LZO and XORDelta formats to Mods.Cnc
They're pretty much RA/TD-specific formats.
2019-12-08 19:43:51 +00:00
reaperrr
cd123830c3 Move VocLoader from D2k to Cnc
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.
2019-12-08 18:14:17 +00:00
Ivaylo Draganov
93e42b0b27 Add selection tiers as inheritable templates 2019-12-08 18:39:21 +01:00
tovl
088919fecc Change color of selection box based on selection mode. 2019-12-08 17:34:10 +01:00
reaperrr
efc06a020b Move WithDeliveryAnimation to Mods.Common 2019-12-08 16:03:14 +00:00
reaperrr
fe1d3b3821 Move ProductionAirdrop to Mods.Common 2019-12-08 16:03:14 +00:00
reaperrr
948a9c9b19 Add ProductionAirdrop.ActorType update rule 2019-12-08 16:03:14 +00:00
Paul Chote
2603a495e6 Add render_world perf sampler. 2019-12-08 04:36:31 +01:00
Paul Chote
8c41e6a3f7 Remove redundant zoom parameter. 2019-12-08 04:36:31 +01:00
Paul Chote
327866ffc3 Render world via an intermediate FrameBuffer. 2019-12-08 04:36:31 +01:00
Paul Chote
0c8a47b5af Add scissor support to IFrameBuffer. 2019-12-08 04:36:31 +01:00
Paul Chote
e7de7b4c05 Introduce World and UI rendering phases. 2019-12-08 04:36:31 +01:00
Paul Chote
ebd1557523 Draw voxel debug annotations using the UI renderers. 2019-12-08 04:36:31 +01:00
abcdefg30
9a5eaa7cb7 Don't throw an exception when a field is missing 2019-12-07 09:15:38 +01:00
Curtis Shmyr
f037436536 Added TooltipName as an actor Lua property 2019-12-06 09:33:23 +01:00
abcdefg30
b1571ad17a Make Parachutable public 2019-12-05 23:13:35 +01:00
Paul Chote
494a7870d6 Add fallback exits to RA Kennel. 2019-12-05 18:01:09 +01:00
Paul Chote
dbe1d2d928 Add fallback exits to TS barracks. 2019-12-05 18:01:09 +01:00
Paul Chote
2146dd29bb Add priority levels to Exit. 2019-12-05 18:01:09 +01:00
matjaeck
5ac9d2c2f1 Fix botmodules querying the Player actor before it is assigned. 2019-12-05 01:48:56 +01:00
reaperrr
a74235bdbc Move ShpD2 and TmpRA/TD loaders to Mods.Cnc
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.
2019-12-01 16:23:54 +01:00
reaperrr
a98a96b05d Update update rule paths 2019-11-30 20:08:27 +01:00
abc013
b4c116cb31 Fix ExtractLanguageStrings utility command 2019-11-29 16:40:00 +01:00
reaperrr
074ebefee1 Fix FCOM still providing space while being captured 2019-11-27 23:04:28 +01:00
tovl
6fb3dc050b Let CreateGroup use ExtraActors field. 2019-11-26 22:06:37 +01:00
tovl
00ce1d7ee6 Allow additional actor IDs to be send with orders. 2019-11-26 22:06:37 +01:00
reaperrr
b8e15fbe40 Move FastByteReader from LCW to own file
And make it public.
Making it easier to move formats that depend on it
to Mods.Cnc independently later.
2019-11-23 19:04:27 +01:00
reaperrr
3f06541b2b Move Shp conversion/remap commands to Mods.Cnc 2019-11-23 19:04:27 +01:00
reaperrr
65728bc032 Move VocLoader to Mods.D2k
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.
2019-11-23 19:04:27 +01:00
reaperrr
c4597b5c6b Fix RA desert tree fire palette
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.
2019-11-23 18:40:27 +01:00
abcdefg30
142f823e6f Explain that CanEnterCell ignores 'subCell' if there is a free subcell 2019-11-21 14:13:17 +01:00
abcdefg30
25b7386f0d Let Mobile's CanEnterCell consider ToSubCell 2019-11-21 14:13:17 +01:00
abcdefg30
4717e98c48 Add a subCell parameter to IPositionableInfo.CanEnterCell 2019-11-21 14:13:17 +01:00
abcdefg30
980c1e1b6a Fix McvManagerBotModule spamming deploy orders
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.
2019-11-20 16:44:39 +01:00
teinarss
a47f60d3a6 Add a trait PlayerRadarTerrain to track explored terrain 2019-11-20 16:24:56 +01:00
reaperrr
ee00954f2e Replace AmmoPool lookup methods with properties
And gave the more suitable names while at it.
This is more in line with how we do things in
other places.
2019-11-20 15:45:41 +01:00
teinarss
c77aa4c8f9 Add IsDead check to FerryUnit OnFirstRun 2019-11-19 15:59:27 +01:00
reaperrr
8181a452cb Fix some header dates
Seems these were overlooked or merged after
the dates of the other files were updated.
2019-11-17 22:32:51 +01:00
Paul Chote
f39b688c39 Add GrantPrerequisiteChargeDrainPower and DrainPrerequisitePowerOnDamage.
These traits implement the Firestorm defense charge/drain logic.
2019-11-17 17:06:29 +01:00
Paul Chote
1fa90c0474 Allow support powers to override the icon overlay/tooltip labels. 2019-11-17 17:06:29 +01:00
Paul Chote
70b020205d Rename *Time to *Ticks and increase internal resolution. 2019-11-17 17:06:29 +01:00
Paul Chote
e03abdc0da Add support for custom SupportPowerInstances. 2019-11-17 17:06:29 +01:00
Paul Chote
61c56dcb00 Fix DamageModifier crashes when an actor is demolished.
Demolish calls GetDamageModifier with a null Damage.
2019-11-17 17:06:29 +01:00
Paul Chote
6b1e81a7b5 Spawn ejected pilots inside a FrameEndTask. 2019-11-16 23:07:58 +01:00
RoosterDragon
04912ea996 Expose a setting for Weighted A*
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.
2019-11-15 13:05:41 +01:00
Abdurrahmaan Iqbal
72eb4e1749 Fix #17230: Dummy audio output class 2019-11-14 23:46:14 +01:00
blackhand1001
70b1df6ce7 Fix squadmanager adding naval units to ground attack forces.
Fix squadmanager adding naval units to ground attack forces. This was breaking the behavior of both naval and ground squads.
2019-11-09 11:19:09 +01:00
abcdefg30
a586f10875 Don't allow movement for actors without IMove
However, this does not check if any existing IMove traits are enabled.
2019-11-08 23:31:59 +01:00
abcdefg30
980c0c9cd4 Fix actors returning fire at invisible attackers 2019-11-08 23:31:59 +01:00
blackhand1001
d20182f158 Simplify for loop structure now that it only has one check
Simplify for loop structure now that it only has one check
2019-11-08 21:04:32 +01:00
blackhand1001
49d07e9d64 Fix MCV Manager glitch when restrict building area is enabled.
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.
2019-11-08 21:04:32 +01:00
matjaeck
ba73842747 Allow GrantCondition to grant conditions permanently. 2019-11-08 16:37:13 +01:00
matjaeck
900e857bfa Let AI ignore frozen actors and target original actors instead. 2019-11-08 15:32:06 +01:00
Abdurrahmaan Iqbal
d2819dca77 Show dialogue only when there are unsaved changes 2019-11-07 20:33:43 +01:00
blackhand1001
780982dbe2 Add PlaceDefenseTowardsEnemyChance trait to basebuilderbotmodule
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.
2019-11-06 10:30:36 +01:00
reaperrr
2de51ae73c Cache IPathFinder in Mobile at creation
Avoiding look-ups on every move order,
as well as reducing line lengths.
2019-11-03 20:53:29 +01:00
Paul Chote
27205b30e5 Remove landing behaviour from force-move orders on selectable buildings. 2019-11-02 18:29:16 +00:00
abcdefg30
34f4c9bdaa Prevent chronoshifting an empty selection 2019-11-02 11:29:28 +01:00
Abdurrahmaan Iqbal
023750db06 Prevent showing wall connections in unexplored terrain 2019-11-01 22:13:38 +01:00
teinarss
c94cf61069 Fix OccupiedCells for units sharing cells 2019-10-31 21:49:07 +00:00
Paul Chote
5315f8603f Override selection if the mouse is over an already selected actor. 2019-10-30 14:53:23 +01:00
Paul Chote
0e4cb53ada Pass contextual information to TargetOverridesSelection. 2019-10-30 14:53:23 +01:00
Paul Chote
3d6621f7ff Force selection cursor when selection overrides input. 2019-10-30 14:53:23 +01:00
Paul Chote
9d4f683d80 Remove WorldRenderer argument from InputOverridesSelection. 2019-10-30 14:53:23 +01:00
Paul Chote
0cfd6337ff Fix InputOverridesSelection only considering the closest actor. 2019-10-30 14:53:23 +01:00
Paul Chote
230a0b330c Fix EjectOnDeath pilot spawning. 2019-10-29 23:03:11 +01:00
Paul Chote
3ee697a54d Install x64 release into correct Program Files on Windows. 2019-10-28 21:03:49 +01:00
tovl
d2991247a3 Add separate condition to mobile for disabling nudging only. 2019-10-28 19:35:32 +01:00
tovl
38caadfdf0 Clean up nudging code. 2019-10-28 19:35:32 +01:00
tovl
c4d1468f62 Make locomotor cache and nudging logic aware of mobile trait status. 2019-10-28 19:35:32 +01:00
reaperrr
7e5b1abc0e Simplified initial Wanders countdown initialization
I don't see a technical reason for the old approach.
2019-10-27 18:03:34 +02:00
RoosterDragon
b98123d9f8 Use SegmentStream.CreateWithoutOwningStream to avoid reading data into memory.
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.
2019-10-24 20:48:14 +02:00
blackhand1001
9a9bf441ba Add UseResourceStorage trait to CashTrickler 2019-10-23 20:20:03 +02:00
Paul Chote
1599eac66c Rename SelectionBoxRenderable to SelectionBoxAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
43e84c89ef Rename SelectionBarsRenderable to SelectionBarsAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
8e280ef0a7 Rename RangeCircleRenderable to RangeCircleAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
81d9b705a6 Rename DetectionCircleRenderable to DetectionCircleAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
4ec0fa299d Rename TextRenderable to TextAnnotationRenderable. 2019-10-20 23:46:33 +02:00
Paul Chote
7937383bf4 Replace scaleSizeWithZoom with SpriteAnnotation. 2019-10-20 23:46:33 +02:00
Paul Chote
e772adb0a9 Draw annotations using the UI renderers. 2019-10-20 23:46:33 +02:00
Paul Chote
8c1b0f1afe Add IEffectAnnotation interface. 2019-10-20 23:46:33 +02:00
Paul Chote
0ff078968d Change IPlaceBuildingDecorationInfo to use annotations. 2019-10-20 23:46:33 +02:00
Paul Chote
7d1ce0c83b Add annotation support to IOrderGenerator. 2019-10-20 23:46:33 +02:00
Paul Chote
1dc84f48de Migrate traits to IRenderAnnotations. 2019-10-20 23:46:33 +02:00
Paul Chote
edaa7918fc Add IRenderAnnotations(WhenSelected) interfaces. 2019-10-20 23:46:33 +02:00
Paul Chote
060ea80ca4 Fix infantry idle animations playing immediately after creation. 2019-10-20 16:38:25 +02:00
Paul Chote
c15a0a54bb Don't consider unit creation as movement. 2019-10-20 16:38:25 +02:00
Paul Chote
252c833320 Don't override spawn CenterPosition for non-aircraft reinforcements. 2019-10-19 23:45:42 +02:00
abcdefg30
fdd3bffa1d Throw a lua exception when setting an owner to null/nil 2019-10-19 13:34:43 +02:00
Paul Chote
988d6079e3 Disable Carryable while submerged. 2019-10-19 13:11:00 +02:00
Paul Chote
f14d3985a0 Allow carryall pickup orders on deployed vehicles. 2019-10-19 13:11:00 +02:00
Paul Chote
5f8fa7a35a Add UndeployOnPickup to GrantConditionOnDeploy. 2019-10-19 13:11:00 +02:00
Paul Chote
69970d42f3 Prevent movement pausing at invalid position. 2019-10-19 13:11:00 +02:00
Paul Chote
ae34410c80 Replace MoveIntoWorld with ReturnToCell/AssociateWithAirfield. 2019-10-17 23:31:15 +02:00
Paul Chote
9b4d149a06 Revert "Suppress MoveIntoWorldInit for map-placed Mobile actors."
This reverts commit f0c28cc153.
2019-10-17 23:31:15 +02:00
abcdefg30
f5f626cd89 Revert "Production should set SubCellInit"
This reverts commit fa1ca981ac.
2019-10-17 23:31:15 +02:00
Abdurrahmaan Iqbal
763e6d8109 Fix #17229: Refactor ReturnToBase.cs 2019-10-17 10:28:43 +02:00
reaperrr
aa953ba5a1 Remove unused and buggy stand2 sequence from ants
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.
2019-10-15 14:48:11 +02:00
reaperrr
33bba98773 Fix zombie stand2 sequence and run tickrate 2019-10-14 17:28:46 +02:00
abc013
8b1f1b21e7 Adjusted die sequence length of zombie 2019-10-14 17:28:46 +02:00
abc013
3ec0aa55b9 Fixed zombie.shp
Added missing zombie attack frame
and other fixes.
2019-10-14 17:28:46 +02:00
tovl
33d089a9d6 Fix lastVisibleTarget not being set in FlyAttack and AttackActivity. 2019-10-14 01:22:04 +02:00
abcdefg30
1d90e08bd0 Guard against overlaps on HiDPI by having a 5px border on graphs 2019-10-14 01:02:23 +02:00
abcdefg30
acf028581a Special case the TD spectator UI to fit the minimum width 2019-10-14 01:02:23 +02:00
abcdefg30
9084295d7c Reduce the width of the combat stats tab 2019-10-14 01:02:23 +02:00
abcdefg30
3f89f74d8e Reduce the Width of INGAME_OBSERVERSTATS_BG 2019-10-14 01:02:23 +02:00
reaperrr
88d930579b Fix missing rules in prep update path 2019-10-13 22:37:03 +01:00
abc013
3d3814f336 Add isDead-check to the flamethrowers in allies06b 2019-10-13 18:14:10 +02:00
abc013
3e244998cd Make normal difficulty on allies06b easier 2019-10-13 18:14:10 +02:00
Nakarin Srijumrat
17bec1435b increased ingame edge scrollspeed to 30 from 10 2019-10-13 13:20:24 +02:00
teinarss
fa1ca981ac Production should set SubCellInit 2019-10-12 00:08:15 +02:00
abcdefg30
e9020048fb Add an update rule to remove 'yes' and 'no' 2019-10-12 00:07:05 +02:00
abcdefg30
76ad9962d7 Split off a new UpdatePath for changes not going into prep-1908 2019-10-12 00:07:05 +02:00
abcdefg30
55c3f313b1 Remove 'yes' and 'no' in favor of 'true' and 'false' 2019-10-12 00:07:05 +02:00
abc013
c4f48ad521 Use another plug location for placing plugs on a building when current plug location is already blocked 2019-10-11 22:52:55 +02:00
Paul Chote
ba2d2299d9 Update macOS launcher package.
This pulls in a fix for the missing libmono-native-compat.dylib
2019-10-11 21:58:32 +02:00
abcdefg30
f9f1167b62 Minor style fixes 2019-10-11 21:48:24 +02:00
abcdefg30
e2bbbde494 Reduce string allocations in ObserverStatsLogic 2019-10-11 21:48:24 +02:00
abcdefg30
3672b4e674 Keep army and income graph disabled if they were disabled once 2019-10-11 21:48:24 +02:00
abcdefg30
ee839869fc Replace "$/min" by "Income" and increase graph update rates 2019-10-11 21:48:24 +02:00
abcdefg30
4ca42f6e83 Remove $/min from the basic stats 2019-10-11 21:48:24 +02:00
abcdefg30
0ad8320bff Add an XAxisTicksPerLabel property to LineGraphWidget 2019-10-11 21:48:24 +02:00
abcdefg30
feb58801e0 Work around a recursive loop in TargetAndAttack 2019-10-11 21:00:53 +02:00
Paul Chote
3860cd1b98 Add "Deployed" checkbox in the map editor actor properties. 2019-10-10 19:50:05 +02:00
Paul Chote
c08e290f44 Add "Spawn Child Actor" checkbox in the map editor actor properties. 2019-10-10 19:50:05 +02:00
Paul Chote
966290a623 Add EditorActorCheckbox plumbing. 2019-10-10 19:50:05 +02:00
Paul Chote
5eaa99827d Suppress MoveIntoWorldInit for map-placed Mobile actors. 2019-10-07 19:02:48 +02:00
tovl
eed00ded0d pause MovePart when Mobile is paused. 2019-10-06 20:28:20 +01:00
Jonas A. Lind
1557f4c134 Redo buildpaletteorder for RA vehicles
Restructure RA's vehicle build tab. More streamlined and better looking.
2019-10-06 20:22:16 +02:00
abcdefg30
acea19312d Fix FallsToEarth queueing an activity in its ctor 2019-10-06 14:42:50 +01:00
abcdefg30
56726a0533 Add an ICreationActivity interface 2019-10-06 14:42:50 +01:00
abcdefg30
39f8d34494 Fix setting the position of the wrong actor 2019-10-06 14:42:50 +01:00
abcdefg30
ab87e78dff Fix the XAxis of LineGraphWidget not being updated properly 2019-10-06 13:10:58 +01:00
abcdefg30
548ff411ef Cache method call results in variables in Draw of LineGraphWidget 2019-10-06 13:10:58 +01:00
Chris Cameron
36c48e1785 feat: Using a glDebugMessageCallback instead of glGetError on devices that support it 2019-10-05 21:26:20 +01:00
Punsho
460f5bbb30 Make EMP dissable subterranean units while they're underground 2019-10-05 19:19:57 +02:00
Punsho
d9ec3e0d88 Make EMP dissable detection of mobile sensor array 2019-10-05 19:19:57 +02:00
Punsho
e1e7691fb4 Make laser fence dissable on emp 2019-10-05 19:19:57 +02:00
tovl
ac6431acf8 Clean up usage of CancelActivity. 2019-10-05 19:07:54 +02:00
teinarss
1e786b8e31 Add null check to EditorDefaultBrush for resources 2019-10-05 18:39:39 +02:00
Paul Chote
575541ff4e Remove double-negative from appimage wrapper. 2019-10-05 18:25:13 +02:00
Paul Chote
e94f20f7ca Reset environment variables before switching mods. 2019-10-05 18:25:13 +02:00
Paul Chote
3bda890f7b Add Engine.LaunchWrapper launch argument for mod switching. 2019-10-05 18:25:13 +02:00
Paul Chote
bdd0f68a4a Compile using Mono 6.4.0. 2019-10-05 18:24:45 +02:00
Paul Chote
275365917c Update packaged mono to 6.4.0. 2019-10-05 18:24:45 +02:00
SoScared
b9b7f435dd Redo buildpaletteorder for D2K buildings 2019-10-05 18:21:08 +02:00
Andre Mohren
7f7341a369 Fixed incorrect sequence frame amount checks using Stride. 2019-10-05 18:03:09 +02:00
Paul Chote
c30bb28210 Filter invalid actors when loading and saving games. 2019-10-05 17:50:10 +02:00
Paul Chote
3ad3c39b21 Replace actor list with count in UnitBuilderBotModule. 2019-10-05 17:50:10 +02:00
abcdefg30
b839796b89 Fix double clicking a save in the save game dialogue loading it 2019-10-05 17:39:23 +02:00
abcdefg30
ca92e13b24 Fix harvesters idling on Infiltration 2019-10-05 16:09:42 +02:00
abcdefg30
294908485f Fix the town attackers in Infiltration not stopping 2019-10-05 16:09:42 +02:00
abcdefg30
d2a2c11326 Remove unnecessary SearchFromHarvesterRadius overwrites from TD missions 2019-10-05 16:03:32 +02:00
abcdefg30
716aeb1e8c Add SearchFromProcRadius to TD missions that need it 2019-10-05 16:03:32 +02:00
abcdefg30
321c891bc0 Fix a crash when MaxLevel of GainsExperience is zero 2019-10-05 15:56:59 +02:00
teinarss
d34bce9eab Remove CanEnterCell from OccupiedCells 2019-10-05 14:37:54 +02:00
teinarss
9bfc324c04 Mark cells that have changed MovementType as dirty 2019-10-05 14:37:54 +02:00
Ivaylo Draganov
ad02adff3e Set duplicates flag for hotkeys in HotkeyManager 2019-10-05 13:17:20 +02:00
Punsho
38f5d2c100 RA balance changes for September 2019 2019-10-05 11:03:06 +01:00
Michael Silber
81eb939d4d Fix destroyed truck escaping ra mission sarin-gas-1 2019-10-04 22:41:10 +01:00
Paul Chote
865d8d77e0 Expire invalid instances from the SupportPowerBotModule cache. 2019-10-01 19:25:30 +02:00
Paul Chote
cf427f8cb3 Drop invalid power references when loading save games. 2019-10-01 19:25:30 +02:00
abcdefg30
6f85711252 Increase the SearchFromProcRadius radius in soviet05 2019-09-30 20:28:26 +02:00
abcdefg30
70c278dec5 Remove the now unnecessary Helper refinery 2019-09-30 20:28:26 +02:00
Punsho
9ca7eb6ab1 Make mine targetable on attack everything stance for AutoTargetGround 2019-09-28 14:20:23 +02:00
teinarss
93704ccfcf Add check to see if transport is dead to UnreserveSpace 2019-09-28 14:08:01 +02:00
abcdefg30
411316726b Fix the expansion mcv in soviet05 being transported off the map 2019-09-28 14:01:36 +02:00
abcdefg30
4d2b70acd1 Revert the search radius decrease in D2k 2019-09-28 13:58:24 +02:00
abcdefg30
c0620bd186 Revert the search radius decrease in TS 2019-09-28 13:58:24 +02:00
teinarss
0e6fa51bb0 Rename duplicated actors 2019-09-27 18:04:29 +02:00
teinarss
76034c198e Added Undo Redo to editor 2019-09-27 17:40:32 +02:00
teinarss
1f78b3a425 Cleanup in MapEditorTabsLogic 2019-09-27 17:40:32 +02:00
tovl
48059e8249 Skip rally point if order is queued after resupply. 2019-09-26 18:39:44 +02:00
tovl
09cd56b367 Add missing target line to aircraft taking off from resupplying. 2019-09-26 18:39:44 +02:00
tovl
145b6a05a3 Refactor unreserve actions. 2019-09-26 18:39:44 +02:00
tovl
5787f74af9 Prevent bogus attackmove on take-off. 2019-09-26 18:39:44 +02:00
Punsho
78d7f79817 Fix ctank and stank building faster then they should 2019-09-26 17:13:42 +02:00
abcdefg30
9356c8afd0 Fix unarmed units idling on the ts shellmap 2019-09-24 16:48:52 +02:00
abcdefg30
72bff74ca5 Fix passengers idling on the ts shellmap 2019-09-24 16:48:52 +02:00
abcdefg30
2d304efb73 Convert all spaces to tabs in the ts shellmap script 2019-09-24 16:48:52 +02:00
abcdefg30
c7784cbc8e Fix reinforcements on the ts shellmap not attack moving 2019-09-24 16:48:52 +02:00
Punsho
e1a5a725b0 Fix MRV not auto targeting vehicles 2019-09-22 18:46:56 +02:00
tovl
3d4838b5bc Make airlift landing direction configurable. 2019-09-21 18:16:34 +02:00
tovl
b4270af170 Fix airlift direction in isometric mods. 2019-09-21 18:16:34 +02:00
tovl
3fb54ea6ea Add option for airlift to arrive from player baseline. 2019-09-21 18:16:34 +02:00
tovl
ed7667683b Fix deployed units being nudgeable. 2019-09-19 20:52:13 +02:00
SoScared
61aaac888b Add map Climax to RA map pool 2019-09-16 00:21:47 +02:00
RoosterDragon
6c9fbd40dc Implement IEquatable on structs.
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.
2019-09-15 19:56:58 +02:00
tovl
4a609bbee8 Allow units to give way when path is blocked by oncoming unit. 2019-09-15 17:51:34 +01:00
Ivaylo Draganov
32309bb8ea Add duplicate hotkey tracking with a boolean property on the definition 2019-09-15 16:35:18 +02:00
Paul Chote
df2300bee0 Fix player viewport saving for non-spectators. 2019-09-15 15:11:47 +02:00
Oliver Brakmann
6e18de4370 Fix idling aircraft on Intervention 2019-09-15 15:02:01 +02:00
abcdefg30
0462cfa507 Remove selling from Infilitration
It is weird, unsatisfying for the player and inconsistent with the rest of our missions
2019-09-15 14:51:32 +02:00
abcdefg30
aee9ee6187 Fix potentially bogus usages of OnAllRemovedFromWorld 2019-09-15 14:51:32 +02:00
RoosterDragon
31918e8712 Add UnionRectangles extension method. 2019-09-14 22:09:40 +02:00
Paul Chote
0e6c37d765 Convert TerrainGeometryOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
f45423ed76 Convert EditorSelectionLayer to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
b3984c8db4 Convert WarheadDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
999ad0e18a Convert CustomTerrainDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
ccd07b6cfe Convert ExitsDebugOverlay to IRenderAboveShroudWhenSelected. 2019-09-14 18:49:44 +02:00
Paul Chote
60e42c1ea1 Convert CombatDebugOverlay to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
Paul Chote
c9ed749908 Add (Polygon|Circle|Line)AnnotationRenderable. 2019-09-14 18:49:44 +02:00
Paul Chote
a9a43d54f7 Convert WithRangeCircle to IRenderAboveShroud. 2019-09-14 18:49:44 +02:00
abcdefg30
7f6149713e Fix actors with no footprint not being copied and pasted 2019-09-13 23:55:48 +01:00
tovl
eb39080248 Allow minefields to start and end on occupied cells. 2019-09-13 23:47:34 +01:00
matt barbier
97fe36af5a Moved GrantExternalConditionToProduced into the Traits/Conditions folder 2019-09-13 22:04:35 +01:00
teinarss
c15f66aa62 PlayerStatistics should stop ticking after lost/win 2019-09-13 21:42:11 +01:00
reaperrr
694680720e Updated AcceptsOrder check to be more readable
This hopefully also fixes handling of multiple enabled
RejectsOrders traits.
2019-09-13 19:49:19 +01:00
abcdefg30
465ee97090 Prevent users from selecting a directional target outside the map 2019-09-13 14:47:29 +02:00
Paul Chote
a8b1762464 Fix ActorPreviewWidget viewport manipulation. 2019-09-13 11:24:57 +02:00
tovl
46c0b4cf31 Fix crash with dead cargo. 2019-09-13 10:34:15 +02:00
Jan Beich
4f99982ef1 Extend Linux dllmap to other systems
- 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)
2019-09-13 00:25:50 +02:00
Jan Beich
fe48eede0e command -v with more than one argument is non-portable
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
2019-09-13 00:25:50 +02:00
Paul Chote
afe3e24cda Remove duplication in Texture. 2019-09-12 18:58:37 +01:00
Paul Chote
ce8112fb5a Migrate rendering to OpenGL 3.2 / OpenGL ES 3.0. 2019-09-12 18:58:37 +01:00
Paul Chote
91c63034d3 Clean references to disposed textures. 2019-09-12 18:58:37 +01:00
teinarss
d712bdea85 Locomotor cache should handle custom layers 2019-09-09 21:39:25 +02:00
abcdefg30
912a424596 Replaced "Earned this min" by an Oil Derrick count in the economy statistics 2019-09-08 12:47:33 +02:00
abcdefg30
1e6660ecb2 Add an "UpdatesDerrickCount" trait 2019-09-08 12:47:33 +02:00
Paul Chote
8f267ebcef Remove IronCurtainable from RA aircraft. 2019-09-08 12:24:27 +02:00
teinarss
c13fb80257 Fix crushable logic for actors in cell 2019-09-07 13:31:57 +01:00
abcdefg30
ca8ca2df5c Fix a division by zero error in FindAndDeliverResources
by preventing an overflow through dividing directly
2019-09-07 10:48:20 +01:00
puritylake
aff3bf369b #17018 Gets rif of cutoff line in chat window 2019-09-06 23:02:50 +02:00
teinarss
6fe31e44cb More robust logic for ThisMinute stats 2019-09-06 14:00:42 +02:00
teinarss
6795fb6967 GetAvailableSubCell should block cells outside the map 2019-09-06 13:32:09 +02:00
abcdefg30
9516ee511d Remove the duplicate Selectable trait on TENF 2019-09-06 13:18:37 +02:00
Paul Chote
1d106e71c4 Save screenshots via the frame buffer. 2019-09-04 20:20:04 +02:00
Paul Chote
c0ee346c1c Render via an intermediate frame buffer. 2019-09-04 20:20:04 +02:00
Paul Chote
d2298b6f04 Allow FrameBuffer clear color to be customized. 2019-09-04 20:20:04 +02:00
Paul Chote
09dd66fd5a Correctly fix BlendMode.Subtractive alpha handling. 2019-09-04 20:20:04 +02:00
Paul Chote
b93c7cabb3 Render voxels before BeginFrame. 2019-09-04 20:20:04 +02:00
Oliver Brakmann
5d786f411f Update comment in Activity.cs
SequenceActivities() was removed.
2019-09-02 01:45:35 +02:00
reaperrr
801f5ba525 Rename FlyCircle to FlyIdle and make it tick TickIdle
It now handles both hovering and circling aircraft, for consistency.
2019-09-01 16:38:44 +02:00
teinarss
ce29dcad87 Update PlayerResources capacity from INotify* methods 2019-08-28 00:32:01 +02:00
reaperrr
8edd202b64 Move InflictDamage method back to DamageWarhead
From TargetDamageWarhead.
Saves a few lines and allows warheads that are not
TargetDamageWarhead-based to use it.
2019-08-27 23:05:19 +02:00
reaperrr
07de3ba5e0 Change default preview facing to 96
92 is not a multiple of 8, and all sprite actors
in the official mods have at most 32 facings.
2019-08-27 22:59:22 +02:00
Paul Chote
2b4ad71151 Remove unused OwnerLinkedProc field. 2019-08-25 17:20:38 +02:00
Paul Chote
815ea1e13b Make LastSearchFailed local to FindAndDeliverResources. 2019-08-25 17:20:38 +02:00
Paul Chote
1d2b3ac917 Update the displayed replay filename after renaming. 2019-08-25 16:10:29 +02:00
Paul Chote
c1be8d277e Disable player color for TD walls. 2019-08-25 15:33:46 +02:00
Paul Chote
19d9541aad Disable player color for RA walls. 2019-08-25 15:33:46 +02:00
teinarss
4dd8472d9b Reset server after game 2019-08-25 15:30:45 +02:00
Paul Chote
6702395357 Fix flare animation definition in RA and TD. 2019-08-25 15:24:32 +02:00
tovl
946c9f420b Fix Move not cancelling during turns. 2019-08-25 13:13:37 +02:00
Paul Chote
8b0f2e1462 Fix NRE in SquadManagerBotModule. 2019-08-24 14:33:11 +02:00
Paul Chote
d5f42c0628 Recalculate visibility during moves too. 2019-08-23 14:31:29 +02:00
Paul Chote
76d1447a91 Fix incorrect shroud visibility for stationary units. 2019-08-23 14:31:29 +02:00
Paul Chote
4db3da61e1 Avoid an integer (long) overflow in FindAndDeliverResources. 2019-08-23 14:15:51 +02:00
Ivaylo Draganov
be1f820674 Move hotkey dialog logic into SettingsLogic, fix bugs and improve usability of the dialog 2019-08-23 14:08:09 +02:00
tovl
ed8abe9861 Define nearenough parameter for aircraft so they can exit movement early when stuck. 2019-08-23 13:54:58 +02:00
reaperrr
e71001f4f8 Fix Resupply closeEnough bugs
Fixes that
- RepairableNear actors wouldn't move close enough
- isCloseEnough would return 'true' even if the host
  is invalid.
2019-08-22 10:26:36 +01:00
Paul Chote
8457dfdc39 Add Gatekeeper notice to macOS dmg. 2019-08-21 15:16:00 +01:00
Paul Chote
a491bae39b Bind triggers to RA Shellmap's APC passengers. 2019-08-21 11:24:20 +02:00
Paul Chote
f31cfe5b96 Fix SendParatroopers return value. 2019-08-21 11:24:20 +02:00
Paul Chote
ab94ea9715 Discourage harvesters from wandering too far from the refinery. 2019-08-20 20:22:39 +02:00
Paul Chote
7e4da8ea2c Don't reload after finishing a field. 2019-08-20 19:51:12 +02:00
Paul Chote
7311ae889f Clear placed mines queued fields too. 2019-08-20 19:51:12 +02:00
Paul Chote
9aec48aec3 Lay mines in order from start to end. 2019-08-20 19:51:12 +02:00
abcdefg30
3a51cf0ef8 Update AUTHORS 2019-08-20 19:26:02 +02:00
teinarss
7544d4b4e6 Cells with Temporary blockers should not exit early in locomotor cache 2019-08-19 19:06:57 +02:00
abcdefg30
345905bf68 Remove the gunboat from Lost Souls 2019-08-19 16:55:35 +02:00
abcdefg30
8cf6aa267c Allow single observers to use spectator team chat in mp 2019-08-19 16:45:15 +02:00
tovl
3fe78a8311 Add to AUTHORS. 2019-08-19 00:33:38 +02:00
tovl
2d394f33b8 Fix units from transports appearing at load point. 2019-08-19 00:33:38 +02:00
tovl
70459b311e Refactor FlyAttack to make strafing runs interruptible when target becomes invalid. 2019-08-18 12:50:20 +02:00
Paul Chote
e600848947 Fix crash for invalid Resupply hosts. 2019-08-18 12:48:17 +02:00
2457 changed files with 101009 additions and 75422 deletions

View File

@@ -1,17 +1,106 @@
; Top-most http://editorconfig.org/ file
root = true
charset=utf-8
; Unix-style newlines
[*]
end_of_line = LF
insert_final_newline = true
trim_trailing_whitespace = true
; 4-column tab indentation
; 4-column tab indentation and .NET coding conventions
[*.cs]
indent_style = tab
indent_size = 4
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_prefer_braces = when_multiline:suggestion
csharp_using_directive_placement = outside_namespace:suggestion
csharp_new_line_before_open_brace = all
csharp_space_around_binary_operators = before_and_after
#### Naming styles ####
dotnet_naming_style.camel_case.capitalization = camel_case
dotnet_naming_style.pascal_case.capitalization = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal
dotnet_naming_symbols.const_private_field.applicable_kinds = field
dotnet_naming_symbols.const_private_field.required_modifiers = const
dotnet_naming_symbols.const_private_field.applicable_accessibilities = private
dotnet_naming_symbols.internal_field.applicable_kinds = field
dotnet_naming_symbols.internal_field.applicable_accessibilities = internal
dotnet_naming_symbols.static_private_or_internal_field.required_modifiers = static
dotnet_naming_symbols.static_private_or_internal_field.applicable_accessibilities = internal, private
dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field
dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal
# Naming rules
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.severity = none
dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.symbols = static_private_or_internal_field
dotnet_naming_rule.static_private_or_internal_field_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.const_private_field_should_be_pascal_case.severity = warning
dotnet_naming_rule.const_private_field_should_be_pascal_case.symbols = const_private_field
dotnet_naming_rule.const_private_field_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.severity = warning
dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.symbols = internal_field
dotnet_naming_rule.const_private_or_internal_field_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.private_or_internal_field_should_be_camel_case.severity = warning
dotnet_naming_rule.private_or_internal_field_should_be_camel_case.symbols = private_or_internal_field
dotnet_naming_rule.private_or_internal_field_should_be_camel_case.style = camel_case
# Naming rules
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_after_colon_in_inheritance_clause = true
#require a space after a keyword in a control flow statement such as a for loop
csharp_space_after_keywords_in_control_flow_statements = true
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_before_colon_in_inheritance_clause = true
#Formatting - wrapping options
#leave code block on single line
csharp_preserve_single_line_blocks = true
#leave statements and member declarations on the same line
csharp_preserve_single_line_statements = true
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
; 4-column tab indentation
[*.yaml]
indent_style = tab
indent_size = 4
indent_size = 4

View File

@@ -1,39 +0,0 @@
<!--
This is a guideline, which shall help to write enhancement requests or bug reports.
Fill in the placeholders below. Delete any headings and placeholders that you do not use.
Before you start check if a similar request/bug report already exists in this Github issue tracker and comment there.
When submitting a feature or enhancement request:
1. Explain briefly what the enhancement is and why you think it would be useful.
2. Provide any other necessary or useful information regarding your issue, such as (code) examples or related links.
When submitting a bug report, please follow the template below:
-->
### Issue Summary
<!-- Explanation of the issue. Expectation vs. actual behavior. -->
... ... ...
#### System Information
- **Operating System:** [e.g. Windows 10, Mac OS 10.12, Ubuntu 16.04, ...]
- **.NET / Mono Version:** [e.g. .NET 4.7.1, Mono 4.6.2, ...]
- **OpenRA Version:** [e.g. release-20180218, playtest-20180208, ...]
- **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) -->

33
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@@ -0,0 +1,33 @@
---
name: Bug report
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. -->

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Frequently Asked Questions
url: https://github.com/OpenRA/OpenRA/wiki/FAQ#frequently-asked-questions
about: Explanations for common problems and questions.
- name: OpenRA Forum
url: https://forum.openra.net/
about: Please ask questions about modding here.
- name: OpenRA Discord server
url: https://discord.openra.net/
about: Join the community Discord server for community discussion and support.
- name: OpenRA IRC Channel
url: https://webchat.freenode.net/#openra
about: Join our development IRC channel on freenode for discussion of development topics.

35
.github/ISSUE_TEMPLATE/crash-report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Crash report
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. -->

View File

@@ -0,0 +1,35 @@
---
name: Feature / Enhancement request
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. -->
ALTERNATIVES

55
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: Continuous Integration
on:
push:
pull_request:
branches: [ bleed ]
jobs:
linux-mono:
name: Linux (mono)
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Check Code
run: |
mono --version
make check
- name: Check Mods
run: |
sudo apt-get install lua5.1
make check-scripts
make test
windows:
name: Windows (Net 5.0)
runs-on: windows-2019
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Install .NET 5
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Check Code
shell: powershell
run: |
# Work around runtime failures on the GH Actions runner
dotnet nuget locals all --clear
.\make.ps1 check
dotnet build OpenRA.Test\OpenRA.Test.csproj -c Debug --nologo -p:TargetPlatform=win-x64
dotnet test bin\OpenRA.Test.dll --test-adapter-path:.
- name: Check Mods
run: |
chocolatey install lua --version 5.1.5.52
$ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\"
.\make.ps1 check-scripts
.\make.ps1 test

107
.github/workflows/documentation.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Deploy Documentation
on:
workflow_dispatch:
inputs:
tag:
description: 'Git Tag'
required: true
default: 'release-xxxxxxxx'
jobs:
wiki:
name: Update Wiki
if: github.repository == 'openra/openra'
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.tag }}
- name: Prepare Environment
run: |
make all
- name: Clone Wiki
uses: actions/checkout@v2
with:
repository: openra/openra.wiki
token: ${{ secrets.DOCS_TOKEN }}
path: wiki
- name: Update Wiki (Playtest)
if: startsWith(github.event.inputs.tag, 'playtest-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings (playtest).md"
- name: Update Wiki (Release)
if: startsWith(github.event.inputs.tag, 'release-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --settings-docs "${GIT_TAG}" > "wiki/Settings.md"
- name: Push Wiki
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
cd wiki
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add --all
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
git push origin master
docs:
name: Update docs.openra.net
if: github.repository == 'openra/openra'
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.tag }}
- name: Prepare Environment
run: |
make all
- name: Clone docs.openra.net
uses: actions/checkout@v2
with:
repository: openra/docs
token: ${{ secrets.DOCS_TOKEN }}
path: docs
- name: Update docs.openra.net (Playtest)
if: startsWith(github.event.inputs.tag, 'playtest-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --docs "${GIT_TAG}" > "docs/api/playtest/traits.md"
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/playtest/weapons.md"
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/playtest/lua.md"
- name: Update docs.openra.net (Release)
if: startsWith(github.event.inputs.tag, 'release-')
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
./utility.sh all --docs "${GIT_TAG}" > "docs/api/release/traits.md"
./utility.sh all --weapon-docs "${GIT_TAG}" > "docs/api/release/weapons.md"
./utility.sh all --lua-docs "${GIT_TAG}" > "docs/api/release/lua.md"
- name: Push docs.openra.net
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
cd docs
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add --all
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
git push origin master

88
.github/workflows/itch.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: Deploy itch.io Packages
on:
workflow_dispatch:
inputs:
tag:
description: 'Git Tag'
required: true
default: 'release-xxxxxxxx'
jobs:
itch:
name: Deploy to itch.io
runs-on: ubuntu-20.04
if: github.repository == 'openra/openra'
steps:
- name: Download Packages
env:
GIT_TAG: ${{ github.event.inputs.tag }}
run: |
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64.exe"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}-x64-winportable.zip" -O "OpenRA-${GIT_TAG}-x64-win-itch.zip"
wget -q "https://github.com${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-${GIT_TAG}.dmg"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Dune-2000-x86_64.AppImage"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Red-Alert-x86_64.AppImage"
wget -q "https://github.com/${{ github.repository }}/releases/download/${GIT_TAG}/OpenRA-Tiberian-Dawn-x86_64.AppImage"
wget -q "https://raw.githubusercontent.com/${{ github.repository }}/${GIT_TAG}/packaging/.itch.toml"
zip -u "OpenRA-${GIT_TAG}-x64-win-itch.zip" .itch.toml
- name: Publish Windows Installer
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: win
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}-x64.exe"
- name: Publish Windows Itch Bundle
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: itch
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}-x64-win-itch.zip
- name: Publish macOS Package
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: macos
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-${{ github.event.inputs.tag }}}.dmg"
- name: Publish RA AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-ra
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Red-Alert-x86_64.AppImage
- name: Publish TD AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-cnc
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Tiberian-Dawn-x86_64.AppImage
- name: Publish D2k AppImage
uses: josephbmanley/butler-publish-itchio-action@master
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: linux-d2k
ITCH_GAME: openra
ITCH_USER: openra-developers
VERSION: ${{ github.event.inputs.tag }}
PACKAGE: OpenRA-Dune-2000-x86_64.AppImage

94
.github/workflows/packaging.yml vendored Normal file
View File

@@ -0,0 +1,94 @@
name: Release Packaging
on:
push:
tags:
- 'release-*'
- 'playtest-*'
- 'devtest-*'
jobs:
linux:
name: Linux AppImages
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
- name: Package AppImages
run: |
mkdir -p build/linux
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/linux/*
macos:
name: macOS Disk Images
runs-on: macos-10.15
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
- name: Package Disk Images
env:
MACOS_DEVELOPER_IDENTITY: ${{ secrets.MACOS_DEVELOPER_IDENTITY }}
MACOS_DEVELOPER_CERTIFICATE_BASE64: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_BASE64 }}
MACOS_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_PASSWORD }}
MACOS_DEVELOPER_USERNAME: ${{ secrets.MACOS_DEVELOPER_USERNAME }}
MACOS_DEVELOPER_PASSWORD: ${{ secrets.MACOS_DEVELOPER_PASSWORD }}
run: |
mkdir -p build/macos
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/macos/*
windows:
name: Windows Installers
runs-on: ubuntu-20.04
steps:
- name: Clone Repository
uses: actions/checkout@v2
- name: Install .NET 5
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Prepare Environment
run: |
echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
sudo apt install nsis wine64
- name: Package Installers
run: |
mkdir -p build/windows
./packaging/windows/buildpackage.sh "${GIT_TAG}" "${PWD}/build/windows"
- name: Upload Packages
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
overwrite: true
file_glob: true
file: build/windows/*

2
.gitignore vendored
View File

@@ -26,7 +26,7 @@ mods/*/*.pdb
/*.exe
/*.exe.config
thirdparty/download/*
*.mmdb.gz
IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
# backup files by various editors
*~

View File

@@ -1,86 +0,0 @@
# Travis-CI Build for OpenRA
# see travis-ci.org for details
dist: xenial
language: csharp
mono: 5.20.1
cache:
directories:
- thirdparty/download
addons:
apt:
packages:
- lua5.1
- dpkg
- markdown
- zlib1g-dev
- libbz2-dev
- cmake
- genisoimage
- fakeroot
- zsync
# Environment variables
env:
secure: "C0+Hlfa0YGErxUuWV00Tj6p45otC/D3YwYFuLpi2mj1rDFn/4dgh5WRngjvdDBVbXJ3duaZ78jPHWm1jr7vn2jqj9yETsCIK9psWd38ep/FEBM0SDr6MUD89OuXk/YyvxJAE+UXF6bXg7giey09g/CwBigjMW7ynET3wNAWPHPs="
# Fetch dependencies
# Run the build script
# Check source code with StyleCop
# call OpenRA to check for YAML errors
# Run the NUnit tests
script:
- travis_retry make all-dependencies
- make all
- make check
- make check-scripts
- make test
- make nunit
# Automatically update the trait documentation and Lua API
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && cd packaging && ./update-wiki.sh $TRAVIS_BRANCH; cd ..
# Only watch the development branch and tagged release.
branches:
only:
- /^release-.*$/
- /^playtest-.*$/
- /^pkgtest-.*$/
- /^prep-.*$/
- bleed
# Notify developers when build passed/failed.
notifications:
irc:
template:
- "%{repository}#%{build_number} %{commit} %{author}: %{message} %{build_url}"
channels:
- "irc.freenode.net#openra"
use_notice: true
skip_join: true
before_deploy:
- wget http://mirrors.kernel.org/ubuntu/pool/universe/n/nsis/nsis-common_3.03-2_all.deb
- wget http://mirrors.kernel.org/ubuntu/pool/universe/n/nsis/nsis_3.03-2_amd64.deb
- sudo dpkg -i nsis-common_3.03-2_all.deb
- sudo dpkg -i nsis_3.03-2_amd64.deb
- makensis -VERSION
- export PATH=$PATH:$HOME/usr/bin
- DOTVERSION=`echo ${TRAVIS_TAG} | sed "s/-/\\./g"`
- cd packaging
- mkdir build
- ./package-all.sh ${TRAVIS_TAG} ${PWD}/build/
deploy:
provider: releases
api_key:
secure: "g/LU11f+mjqv+lj0sR1UliHwogXL4ofJUwoG5Dbqlvdf5UTLWytw/OWSCv8RGyuh10miyWeaoqHh1cn2C1IFhUEqN1sSeKKKOWOTvJ2FR5mzi9uH3d/MOBzG5icQ7Qh0fZ1YPz5RaJJhYu6bmfvA/1gD49GoaX2kxQL4J5cEBgg="
file_glob: true
file: build/*
skip_cleanup: true
on:
all_branches: true
tags: true
repo: OpenRA/OpenRA

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"recommendations": [
"ms-dotnettools.csharp",
"EditorConfig.EditorConfig",
"ms-vscode.mono-debug"
]
}

65
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,65 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch (TD)",
"type": "clr",
"linux": {
"type": "mono"
},
"osx": {
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=cnc"],
"preLaunchTask": "build",
},
{
"name": "Launch (RA)",
"type": "clr",
"linux": {
"type": "mono"
},
"osx": {
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=ra"],
"preLaunchTask": "build",
},
{
"name": "Launch (D2k)",
"type": "clr",
"linux": {
"type": "mono"
},
"osx": {
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=d2k"],
"preLaunchTask": "build",
},
{
"name": "Launch (TS)",
"type": "clr",
"linux": {
"type": "mono"
},
"osx": {
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=ts"],
"preLaunchTask": "build",
},
]
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"omnisharp.enableRoslynAnalyzers": true
}

13
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "make",
"args": ["all"],
"windows": {
"command": "make.cmd"
}
}
]
}

32
AUTHORS
View File

@@ -3,26 +3,27 @@ hard work of many contributors.
The OpenRA developers are:
* Chris Forbes (chrisf)
* Igor Popov (ihptru)
* Lukas Franke (abcdefg30)
* Oliver Brakmann (obrakmann)
* Paul Chote (pchote)
* Reaperrr
* Tom Roostan (RoosterDragon)
Previous developers included:
* Alli Witheford (alzeih)
* Caleb Anderson (RobotCaleb)
* Curtis Shmyr (hamb)
* Daniel Hernandez (Mancano)
* Igor Popov (ihptru)
* Matthias Mailänder (Mailaender)
* Megan Bowra-Dean (beedee)
* Mike Bundy (kehaar)
* Oliver Brakmann (obrakmann)
* Pavel Penev (penev92)
* Robert Pepperell (ytinasni)
* ScottNZ
* Tom Roostan (RoosterDragon)
Also thanks to:
* abmyii
* Adam Valy (Tschokky)
* Akseli Virtanen (RAGEQUIT)
* Alexander Fast (mizipzor)
@@ -39,10 +40,12 @@ Also thanks to:
* Biofreak
* Braxton Williams (Buddytex)
* Brendan Gluth (Mechanical_Man)
* Brent Gardner (bggardner)
* Bryan Wilbur
* Bugra Cuhadaroglu (BugraC)
* Christer Ulfsparre (Holloweye)
* Chris Cameron (Vesuvian)
* Chris Grant (Unit158)
* Christer Ulfsparre (Holloweye)
* clem
* Cody Brittain (Generalcamo)
* Constantin Helmig (CH4Code)
@@ -135,15 +138,19 @@ Also thanks to:
* Sebastien Kerguen (xanax)
* Shawn Collins (UberWaffe)
* Simon Verbeke (Saticmotion)
* Stuart McHattie (SDJMcHattie)
* Taryn Hill (Phrohdoh)
* Teemu Nieminen (Temeez)
* Tim Mylemans (gecko)
* Tirili
* Tomas Einarsson (Mesacer)
* Tom van Leth (tovl)
* Trevor Nichols (ocdi)
* Tristan Keating (Kilkakon)
* Tristan Mühlbacher (MicroBit)
* UnknownProgrammer
* Vladimir Komarov (VrKomarov)
* Wojciech Walaszek (Voidwalker)
* Wuschel
Using GNU FreeFont distributed under the GNU GPL
@@ -157,12 +164,6 @@ FreeType License.
Using OpenAL Soft distributed under the GNU LGPL.
Using MaxMind GeoIP2 .NET API distributed under
the Apache 2.0 license.
Using GeoLite2 data created by MaxMind and
distributed under the CC BY-SA 3.0 license.
Using SDL2-CS and OpenAL-CS created by Ethan
Lee and released under the zlib license.
@@ -182,6 +183,17 @@ Krueger and distributed under the GNU GPL terms.
Using rix0rrr.BeaconLib developed by Rico Huijbers
distributed under MIT License.
Using DiscordRichPresence developed by Lachee
distributed under MIT License.
Using Json.NET developed by James Newton-King
distributed under MIT License.
Using ANGLE distributed under the BS3 3-Clause license.
This site or product includes IP2Location LITE data
available from http://www.ip2location.com.
Finally, special thanks goes to the original teams
at Westwood Studios and EA for creating the classic
games which OpenRA aims to reimagine.

File diff suppressed because one or more lines are too long

View File

@@ -8,30 +8,28 @@ Windows
Compiling OpenRA requires the following dependencies:
* [Windows PowerShell >= 4.0](http://microsoft.com/powershell) (included by default in recent Windows 10 versions)
* [.NET Framework 4.6.1 (Developer Pack)](https://dotnet.microsoft.com/download/dotnet-framework/net461) (or via Visual Studio 2017)
* [.NET Core 2.2 SDK](https://dotnet.microsoft.com/download/dotnet-core/2.2) (or via Visual Studio 2017)
* [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) (or via Visual Studio)
Type `make dependencies` in a command terminal to download pre-compiled native libraries for:
* [SDL 2](http://www.libsdl.org/download-2.0.php)
* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm)
* [zlib](http://gnuwin32.sourceforge.net/packages/zlib.htm)
* [OpenAL](http://kcat.strangesoft.net/openal.html)
* [liblua 5.1](http://luabinaries.sourceforge.net/download.html)
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.
Mono, version 6.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.
Use `make dependencies` to map the native libraries to your system and fetch the remaining CLI dependencies to place them at the appropriate places.
To compile OpenRA, run `make` 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 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.
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`.
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`.
If you choose to use system libraries, or your system is not x86_64, you will need to install the following using your system package manager:
* [SDL 2](http://www.libsdl.org/download-2.0.php)
* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm)
* [OpenAL](http://kcat.strangesoft.net/openal.html)
* [liblua 5.1](http://luabinaries.sourceforge.net/download.html)
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`.
Arch Linux
----------
@@ -89,24 +87,23 @@ sudo zypper in mono-devel openal-soft freetype2 SDL2 lua51 xdg-utils zenity
Red Hat Enterprise Linux (and rebuilds, e.g. CentOS)
----------------------------------------------------
The EPEL repository is required in order for the following command to run properly.
The EPEL repository is required in order for the following command to run properly.
```
sudo yum install "pkgconfig(mono)" SDL2 freetype "lua = 5.1" openal-soft xdg-utils zenity
```
OSX
macOS
=====
Before compiling OpenRA you must install the following dependencies:
* [Mono >= 5.4](https://www.mono-project.com/download/stable/#download-mac)
* [Mono >= 6.4](https://www.mono-project.com/download/stable/#download-mac)
Use `make dependencies` to download pre-compiled native libraries for:
* [SDL 2](http://www.libsdl.org/download-2.0.php)
* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm)
* [OpenAL](http://kcat.strangesoft.net/openal.html)
* [liblua 5.1](http://luabinaries.sourceforge.net/download.html)
To compile OpenRA, run `make` from the command line. Run with `./launch-game.sh`.
To compile OpenRA, run `make` from the command line.
The default behaviour 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`. If you choose to use system libraries you will need to install:
* [SDL 2](http://www.libsdl.org/download-2.0.php) (`brew install sdl2`)
* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) (`brew install freetype`)
* [OpenAL](http://kcat.strangesoft.net/openal.html) (`brew install openal-soft`)
* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) (`brew install lua@5.1`)
Run with `./launch-game.sh`.

389
Makefile
View File

@@ -3,55 +3,43 @@
# to compile, run:
# make [DEBUG=true]
#
# to check unit tests (requires NUnit version >= 2.6), run:
# make nunit [NUNIT_CONSOLE=<path-to/nunit[2]-console>] [NUNIT_LIBS_PATH=<path-to-libs-dir>] [NUNIT_LIBS=<nunit-libs>]
# Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths
# Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing /
# Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix)
# to compile using system libraries for native dependencies, run:
# make [DEBUG=true] TARGETPLATFORM=unix-generic
#
# to check the official mods for erroneous yaml files, run:
# make test
#
# to check the official mod dlls for StyleCop violations, run:
# to check the engine and official mod dlls for code style violations, run:
# make check
#
# to install, run:
# to compile and install Red Alert, Tiberian Dawn, and Dune 2000, run:
# make [prefix=/foo] [bindir=/bar/bin] install
#
# to install Linux startup scripts, desktop files and icons:
# make install-linux-shortcuts [DEBUG=false]
# to install Linux startup scripts, desktop files, icons, and MIME metadata
# make install-linux-shortcuts
#
# to install the engine and common mod files (omitting the default mods):
# make install-engine
# make install-common-mod-files
#
# to uninstall, run:
# make uninstall
# to install Linux AppStream metadata
# make install-linux-appdata
#
# for help, run:
# make help
#
# to start the game, run:
# openra
############################## TOOLCHAIN ###############################
#
# List of .NET assemblies that we can guarantee exist
# OpenRA.Game.dll is a harmless false positive that we can ignore
WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.Game.exe OpenRA.Utility.exe OpenRA.Platforms.Default.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll OpenRA.Game.dll
WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.dll OpenRA.Utility.dll OpenRA.Server.dll OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll
# These are explicitly shipped alongside our core files by the packaging script
WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll MaxMind.Db.dll Eluant.dll rix0rrr.BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.dll
WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll
# These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack
# This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories
WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll
NUNIT_LIBS_PATH :=
NUNIT_LIBS := $(NUNIT_LIBS_PATH)nunit.framework.dll
WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll Microsoft.Win32.Registry.dll System.Security.AccessControl.dll System.Security.Principal.Windows.dll System.Xml.Linq.dll System.Runtime.Serialization.dll
######################### UTILITIES/SETTINGS ###########################
#
# install locations
# Install locations for local installs and downstream packaging
prefix ?= /usr/local
datarootdir ?= $(prefix)/share
datadir ?= $(datarootdir)
@@ -61,325 +49,124 @@ libdir ?= $(prefix)/lib
gameinstalldir ?= $(libdir)/openra
BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
DATA_INSTALL_DIR = $(DESTDIR)$(gameinstalldir)
DATA_INSTALL_DIR = $(DESTDIR)$(datadir)
OPENRA_INSTALL_DIR = $(DESTDIR)$(gameinstalldir)
# install tools
# Toolchain
CWD = $(shell pwd)
MSBUILD = msbuild -verbosity:m -nologo
MONO = mono
RM = rm
RM_R = $(RM) -r
RM_F = $(RM) -f
RM_RF = $(RM) -rf
CP = cp
CP_R = $(CP) -r
INSTALL = install
INSTALL_DIR = $(INSTALL) -d
INSTALL_PROGRAM = $(INSTALL) -m755
INSTALL_DATA = $(INSTALL) -m644
# Toolchain
MSBUILD = msbuild -verbosity:m -nologo
VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`)
# Enable 32 bit builds while generating the windows installer
WIN32 = false
# program targets
VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`)
# dependencies
# Detect target platform for dependencies if not given by the user
ifndef TARGETPLATFORM
UNAME_S := $(shell uname -s)
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_S),Darwin)
os-dependencies = osx-dependencies
TARGETPLATFORM = osx-x64
else
os-dependencies = linux-dependencies
ifeq ($(UNAME_M),x86_64)
TARGETPLATFORM = linux-x64
else
TARGETPLATFORM = unix-generic
endif
endif
endif
OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.dll
##################### DEVELOPMENT BUILDS AND TESTS #####################
#
all:
@command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.18."; exit 1)
@$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO"
ifeq ($(TARGETPLATFORM), unix-generic)
@./configure-system-libraries.sh
endif
@./fetch-geoip.sh
clean:
@-$(RM_RF) ./bin ./*/bin ./*/obj
@$(MSBUILD) -t:Clean -p:Mono=true
@-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
check:
@echo
@echo "Compiling in debug mode..."
@$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO"
@echo
@echo "Checking runtime assemblies..."
@$(OPENRA_UTILITY) all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES)
@echo
@echo "Checking for explicit interface violations..."
@$(OPENRA_UTILITY) all --check-explicit-interfaces
@echo
@echo "Checking for incorrect conditional trait interface overrides..."
@$(OPENRA_UTILITY) all --check-conditional-trait-interface-overrides
check-scripts:
@echo
@echo "Checking for Lua syntax errors..."
@luac -p $(shell find mods/*/maps/* -iname '*.lua')
@luac -p $(shell find lua/* -iname '*.lua')
@luac -p $(shell find mods/*/bits/scripts/* -iname '*.lua')
check: dependencies
@echo
@echo "Compiling in debug mode..."
@$(MSBUILD) -t:build -p:Configuration=Debug
@echo
@echo "Checking runtime assemblies..."
@mono --debug OpenRA.Utility.exe all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES)
@echo
@echo "Checking for explicit interface violations..."
@mono --debug OpenRA.Utility.exe all --check-explicit-interfaces
@echo
@echo "Checking for incorrect conditional trait interface overrides..."
@mono --debug OpenRA.Utility.exe all --check-conditional-trait-interface-overrides
NUNIT_CONSOLE := $(shell test -f thirdparty/download/nunit3-console.exe && echo mono thirdparty/download/nunit3-console.exe || \
which nunit3-console 2>/dev/null || which nunit2-console 2>/dev/null || which nunit-console 2>/dev/null)
nunit: core
@echo
@echo "Checking unit tests..."
@if [ "$(NUNIT_CONSOLE)" = "" ] ; then \
echo 'nunit[3|2]-console not found!'; \
echo 'Was "make dependencies" called or is NUnit installed?'>&2; \
echo 'See "make help".'; \
exit 1; \
fi
@if $(NUNIT_CONSOLE) --help | head -n 1 | grep -E "NUnit version (1|2\.[0-5])";then \
echo 'NUnit version >= 2.6 required'>&2; \
echo 'Try "make dependencies" first to use NUnit from NuGet.'>&2; \
echo 'See "make help".'; \
exit 1; \
fi
@$(NUNIT_CONSOLE) --noresult OpenRA.Test.nunit
test: core
test: all
@echo
@echo "Testing Tiberian Sun mod MiniYAML..."
@mono --debug OpenRA.Utility.exe ts --check-yaml
@$(OPENRA_UTILITY) ts --check-yaml
@echo
@echo "Testing Dune 2000 mod MiniYAML..."
@mono --debug OpenRA.Utility.exe d2k --check-yaml
@$(OPENRA_UTILITY) d2k --check-yaml
@echo
@echo "Testing Tiberian Dawn mod MiniYAML..."
@mono --debug OpenRA.Utility.exe cnc --check-yaml
@$(OPENRA_UTILITY) cnc --check-yaml
@echo
@echo "Testing Red Alert mod MiniYAML..."
@mono --debug OpenRA.Utility.exe ra --check-yaml
@$(OPENRA_UTILITY) ra --check-yaml
########################## MAKE/INSTALL RULES ##########################
############# LOCAL INSTALLATION AND DOWNSTREAM PACKAGING ##############
#
all: dependencies core
core:
@command -v $(MSBUILD) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.4."; exit 1)
ifeq ($(WIN32), $(filter $(WIN32),true yes y on 1))
@$(MSBUILD) -t:build -p:Configuration="Release-x86"
else
@$(MSBUILD) -t:build -p:Configuration=Release
endif
clean:
@ $(MSBUILD) -t:clean
@-$(RM_F) *.config
@-$(RM_F) *.exe *.dll *.dylib ./OpenRA*/*.dll *.pdb mods/**/*.dll mods/**/*.pdb *.resources
@-$(RM_RF) ./*/bin ./*/obj
@-$(RM_RF) ./thirdparty/download
distclean: clean
cli-dependencies:
@./thirdparty/fetch-thirdparty-deps.sh
@ $(CP_R) thirdparty/download/*.dll .
@ $(CP_R) thirdparty/download/*.dll.config .
@ test -f OpenRA.Game/obj/project.assets.json || $(MSBUILD) -t:restore
linux-dependencies: cli-dependencies geoip-dependencies linux-native-dependencies
linux-native-dependencies:
@./thirdparty/configure-native-deps.sh
windows-dependencies: cli-dependencies geoip-dependencies
ifeq ($(WIN32), $(filter $(WIN32),true yes y on 1))
@./thirdparty/fetch-thirdparty-deps-windows.sh x86
else
@./thirdparty/fetch-thirdparty-deps-windows.sh x64
endif
osx-dependencies: cli-dependencies geoip-dependencies
@./thirdparty/fetch-thirdparty-deps-osx.sh
@ $(CP_R) thirdparty/download/osx/*.dylib .
@ $(CP_R) thirdparty/download/osx/*.dll.config .
geoip-dependencies:
@./thirdparty/fetch-geoip-db.sh
@ $(CP) thirdparty/download/GeoLite2-Country.mmdb.gz .
dependencies: $(os-dependencies)
all-dependencies: cli-dependencies windows-dependencies osx-dependencies geoip-dependencies
version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml
@echo "$(VERSION)" > VERSION
@for i in $? ; do \
awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \
awk '{sub("/[^/]*: User$$", "/$(VERSION): User"); print $0}' $${i}.tmp > $${i} && \
rm $${i}.tmp; \
done
@sh -c '. ./packaging/functions.sh; set_engine_version $(VERSION) .'
@sh -c '. ./packaging/functions.sh; set_mod_version $(VERSION) mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml'
install: dependencies core install-core
install:
@sh -c '. ./packaging/functions.sh; install_assemblies_mono $(CWD) $(OPENRA_INSTALL_DIR) $(TARGETPLATFORM) True True True'
@sh -c '. ./packaging/functions.sh; install_data $(CWD) $(OPENRA_INSTALL_DIR) cnc d2k ra'
install-linux-shortcuts: install-linux-scripts install-linux-icons install-linux-desktop
install-engine:
@-echo "Installing OpenRA engine to $(DATA_INSTALL_DIR)"
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) OpenRA.Game.exe "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) OpenRA.Server.exe "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) OpenRA.Utility.exe "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) OpenRA.Platforms.Default.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_DATA) OpenRA.Platforms.Default.dll.config "$(DATA_INSTALL_DIR)"
@$(INSTALL_DATA) "GeoLite2-Country.mmdb.gz" "$(DATA_INSTALL_DIR)/GeoLite2-Country.mmdb.gz"
@$(INSTALL_DATA) VERSION "$(DATA_INSTALL_DIR)/VERSION"
@$(INSTALL_DATA) AUTHORS "$(DATA_INSTALL_DIR)/AUTHORS"
@$(INSTALL_DATA) COPYING "$(DATA_INSTALL_DIR)/COPYING"
@$(CP_R) glsl "$(DATA_INSTALL_DIR)"
@$(CP_R) lua "$(DATA_INSTALL_DIR)"
@$(CP) SDL2-CS* "$(DATA_INSTALL_DIR)"
@$(CP) OpenAL-CS* "$(DATA_INSTALL_DIR)"
@$(CP) Eluant* "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) ICSharpCode.SharpZipLib.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) FuzzyLogicLibrary.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) Open.Nat.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) MaxMind.Db.dll "$(DATA_INSTALL_DIR)"
@$(INSTALL_PROGRAM) rix0rrr.BeaconLib.dll "$(DATA_INSTALL_DIR)"
install-common-mod-files:
@-echo "Installing OpenRA common mod files to $(DATA_INSTALL_DIR)"
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)/mods"
@$(CP_R) mods/common "$(DATA_INSTALL_DIR)/mods/"
@$(INSTALL_PROGRAM) mods/common/OpenRA.Mods.Common.dll "$(DATA_INSTALL_DIR)/mods/common"
@$(INSTALL_PROGRAM) mods/common/OpenRA.Mods.Cnc.dll "$(DATA_INSTALL_DIR)/mods/common"
@$(INSTALL_DATA) "global mix database.dat" "$(DATA_INSTALL_DIR)/global mix database.dat"
install-default-mods:
@-echo "Installing OpenRA default mods to $(DATA_INSTALL_DIR)"
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)/mods"
@$(CP_R) mods/cnc "$(DATA_INSTALL_DIR)/mods/"
@$(CP_R) mods/ra "$(DATA_INSTALL_DIR)/mods/"
@$(CP_R) mods/d2k "$(DATA_INSTALL_DIR)/mods/"
@$(INSTALL_PROGRAM) mods/d2k/OpenRA.Mods.D2k.dll "$(DATA_INSTALL_DIR)/mods/d2k"
@$(CP_R) mods/modcontent "$(DATA_INSTALL_DIR)/mods/"
install-core: install-engine install-common-mod-files install-default-mods
@$(CP) *.sh "$(DATA_INSTALL_DIR)"
install-linux-icons:
for SIZE in 16x16 32x32 48x48 64x64 128x128; do \
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps"; \
$(INSTALL_DATA) packaging/linux/icons/ra_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-ra.png"; \
$(INSTALL_DATA) packaging/linux/icons/cnc_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-cnc.png"; \
$(INSTALL_DATA) packaging/linux/icons/d2k_$$SIZE.png "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-d2k.png"; \
done
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps"
$(INSTALL_DATA) packaging/linux/icons/ra_scalable.svg "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-ra.svg"
$(INSTALL_DATA) packaging/linux/icons/cnc_scalable.svg "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-cnc.svg"
install-linux-desktop:
@$(INSTALL_DIR) "$(DESTDIR)$(datadir)/applications"
@sed 's/{MODID}/ra/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Red Alert/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-ra.desktop
@$(INSTALL_DATA) packaging/linux/openra-ra.desktop "$(DESTDIR)$(datadir)/applications"
@sed 's/{MODID}/cnc/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Tiberian Dawn/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-cnc.desktop
@$(INSTALL_DATA) packaging/linux/openra-cnc.desktop "$(DESTDIR)$(datadir)/applications"
@sed 's/{MODID}/d2k/g' packaging/linux/openra.desktop.in | sed 's/{MODNAME}/Dune 2000/g' | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-d2k.desktop
@$(INSTALL_DATA) packaging/linux/openra-d2k.desktop "$(DESTDIR)$(datadir)/applications"
@-$(RM) packaging/linux/openra-ra.desktop packaging/linux/openra-cnc.desktop packaging/linux/openra-d2k.desktop
install-linux-mime:
@$(INSTALL_DIR) "$(DESTDIR)$(datadir)/mime/packages/"
@sed 's/{MODID}/ra/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml
@$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-ra.xml"
@sed 's/{MODID}/cnc/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml
@$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-cnc.xml"
@sed 's/{MODID}/d2k/g' packaging/linux/openra-mimeinfo.xml.in | sed 's/{TAG}/$(VERSION)/g' > packaging/linux/openra-mimeinfo.xml
@$(INSTALL_DATA) packaging/linux/openra-mimeinfo.xml "$(DESTDIR)$(datadir)/mime/packages/openra-d2k.xml"
install-linux-shortcuts:
@sh -c '. ./packaging/functions.sh; install_linux_shortcuts $(CWD) $(OPENRA_INSTALL_DIR) $(BIN_INSTALL_DIR) $(DATA_INSTALL_DIR) $(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
@$(INSTALL_DATA) packaging/linux/openra-ra.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
@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
@$(INSTALL_DATA) packaging/linux/openra-cnc.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
@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
@$(INSTALL_DATA) packaging/linux/openra-d2k.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
@-$(RM) packaging/linux/openra-ra.appdata.xml packaging/linux/openra-cnc.appdata.xml packaging/linux/openra-d2k.appdata.xml
install-man-page:
@$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man6/"
@mono --debug OpenRA.Utility.exe all --man-page > openra.6
@$(INSTALL_DATA) openra.6 "$(DESTDIR)$(mandir)/man6/"
@-$(RM) openra.6
install-linux-scripts:
ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0))
@sed 's/{DEBUG}//' packaging/linux/openra.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra.debug.in
@sed 's/{DEBUG}//' packaging/linux/openra-server.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra-server.debug.in
else
@sed 's/{DEBUG}/--debug/' packaging/linux/openra.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra.debug.in
@sed 's/{DEBUG}/--debug/' packaging/linux/openra-server.in | sed 's|{GAME_INSTALL_DIR}|$(gameinstalldir)|' | sed 's|{BIN_DIR}|$(bindir)|' > packaging/linux/openra-server.debug.in
endif
@sed 's/{MODID}/ra/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Red Alert/g' > packaging/linux/openra-ra
@sed 's/{MODID}/cnc/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Tiberian Dawn/g' > packaging/linux/openra-cnc
@sed 's/{MODID}/d2k/g' packaging/linux/openra.debug.in | sed 's/{TAG}/$(VERSION)/g' | sed 's/{MODNAME}/Dune 2000/g' > packaging/linux/openra-d2k
@$(INSTALL_DIR) "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-ra "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-cnc "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-d2k "$(BIN_INSTALL_DIR)"
@-$(RM) packaging/linux/openra-ra packaging/linux/openra-cnc packaging/linux/openra-d2k packaging/linux/openra.debug.in
@sed 's/{MODID}/ra/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Red Alert/g' > packaging/linux/openra-ra-server
@sed 's/{MODID}/cnc/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Tiberian Dawn/g' > packaging/linux/openra-cnc-server
@sed 's/{MODID}/d2k/g' packaging/linux/openra-server.debug.in | sed 's/{MODNAME}/Dune 2000/g' > packaging/linux/openra-d2k-server
@$(INSTALL_DIR) "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-ra-server "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-cnc-server "$(BIN_INSTALL_DIR)"
@$(INSTALL_PROGRAM) -m +rx packaging/linux/openra-d2k-server "$(BIN_INSTALL_DIR)"
@-$(RM) packaging/linux/openra-ra-server packaging/linux/openra-cnc-server packaging/linux/openra-d2k-server packaging/linux/openra-server.debug.in
uninstall:
@-$(RM_R) "$(DATA_INSTALL_DIR)"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-ra"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-ra-server"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-cnc"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-cnc-server"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-d2k"
@-$(RM_F) "$(BIN_INSTALL_DIR)/openra-d2k-server"
@-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-ra.desktop"
@-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-cnc.desktop"
@-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra-d2k.desktop"
@-for SIZE in 16x16 32x32 48x48 64x64 128x128; do \
$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-ra.png"; \
$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-cnc.png"; \
$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/$$SIZE/apps/openra-d2k.png"; \
done
@-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-ra.svg"
@-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/scalable/apps/openra-cnc.svg"
@-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-ra.xml"
@-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-cnc.xml"
@-$(RM_F) "$(DESTDIR)$(datadir)/mime/packages/openra-d2k.xml"
@-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-ra.appdata.xml"
@-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-cnc.appdata.xml"
@-$(RM_F) "$(DESTDIR)$(datadir)/appdata/openra-d2k.appdata.xml"
@-$(RM_F) "$(DESTDIR)$(mandir)/man6/openra.6"
@sh -c '. ./packaging/functions.sh; install_linux_appdata $(CWD) $(DATA_INSTALL_DIR) cnc d2k ra'
help:
@echo 'to compile, run:'
@echo ' make [DEBUG=false]'
@echo ' make [DEBUG=true]'
@echo
@echo 'to check unit tests (requires NUnit version >= 2.6), run:'
@echo ' make nunit [NUNIT_CONSOLE=<path-to/nunit[3|2]-console>] [NUNIT_LIBS_PATH=<path-to-libs-dir>] [NUNIT_LIBS=<nunit-libs>]'
@echo ' Use NUNIT_CONSOLE if nunit[3|2]-console was not downloaded by `make dependencies` nor is it in bin search paths'
@echo ' Use NUNIT_LIBS_PATH if NUnit libs are not in search paths. Include trailing /'
@echo ' Use NUNIT_LIBS if NUnit libs have different names (such as including a prefix or suffix)'
@echo 'to compile using system libraries for native dependencies, run:'
@echo ' make [DEBUG=true] TARGETPLATFORM=unix-generic'
@echo
@echo 'to check the official mods for erroneous yaml files, run:'
@echo ' make test'
@echo
@echo 'to install, run:'
@echo ' make [prefix=/foo] [bindir=/bar/bin] install'
@echo 'to check the engine and official mod dlls for code style violations, run:'
@echo ' make test'
@echo
@echo 'to install Linux startup scripts, desktop files and icons'
@echo ' make install-linux-shortcuts [DEBUG=false]'
@echo 'to compile and install Red Alert, Tiberian Dawn, and Dune 2000 run:'
@echo ' make [prefix=/foo] install'
@echo
@echo 'to uninstall, run:'
@echo ' make uninstall'
@echo 'to install Linux startup scripts, desktop files, icons, and MIME metadata'
@echo ' make install-linux-shortcuts'
@echo
@echo 'to start the game, run:'
@echo ' openra'
@echo 'to install Linux AppStream metadata'
@echo ' make install-linux-appdata'
########################### MAKEFILE SETTINGS ##########################
#
@@ -387,4 +174,4 @@ help:
.SUFFIXES:
.PHONY: check-scripts check nunit test all core clean distclean cli-dependencies linux-dependencies linux-native-dependencies windows-dependencies osx-dependencies geoip-dependencies dependencies all-dependencies version install install-linux-shortcuts install-engine install-common-mod-files install-default-mods install-core install-linux-icons install-linux-desktop install-linux-mime install-linux-appdata install-man-page install-linux-scripts uninstall help
.PHONY: all clean check check-scripts test version install install-linux-shortcuts install-linux-appdata help

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -26,7 +26,7 @@ namespace OpenRA.Activities
public readonly Color Color;
public readonly Sprite Tile;
public TargetLineNode(Target target, Color color, Sprite tile = null)
public TargetLineNode(in Target target, Color color, Sprite tile = null)
{
// Note: Not all activities are drawable. In that case, pass Target.Invalid as target,
// if "yield break" in TargetLineNode(Actor self) is not feasible.
@@ -40,21 +40,50 @@ namespace OpenRA.Activities
* Things to be aware of when writing activities:
*
* - Use "return true" at least once somewhere in the tick method.
* - Do not "reuse" (with "SequenceActivities", for example) activity objects that have already started running.
* - Do not "reuse" activity objects (by queuing them as next or child, for example) that have already started running.
* Queue a new instance instead.
* - Avoid calling actor.CancelActivity(). It is almost always a bug. Call activity.Cancel() instead.
* - Do not evaluate dynamic state (an actor's location, health, conditions, etc.) in the activity's constructor,
* as that might change before the activity gets to tick for the first time. Use the OnFirstRun() method instead.
*/
public abstract class Activity : IActivityInterface
{
public ActivityState State { get; private set; }
protected Activity ChildActivity { get; private set; }
public Activity NextActivity { get; private set; }
Activity childActivity;
protected Activity ChildActivity
{
get { return SkipDoneActivities(childActivity); }
private set { childActivity = value; }
}
Activity nextActivity;
public Activity NextActivity
{
get { return SkipDoneActivities(nextActivity); }
private set { nextActivity = value; }
}
internal static Activity SkipDoneActivities(Activity first)
{
// If first.Cancel() was called while it was queued (i.e. before it first ticked), its state will be Done
// rather than Queued (the activity system guarantees that it cannot be Active or Canceling).
// An unknown number of ticks may have elapsed between the Cancel() call and now,
// so we cannot make any assumptions on the value of first.NextActivity.
// We must not return first (ticking it would be bogus), but returning null would potentially
// drop valid activities queued after it. Walk the queue until we find a valid activity or
// (more likely) run out of activities.
while (first != null && first.State == ActivityState.Done)
first = first.NextActivity;
return first;
}
public bool IsInterruptible { get; protected set; }
public bool ChildHasPriority { get; protected set; }
public bool IsCanceling { get { return State == ActivityState.Canceling; } }
bool finishing;
bool firstRunCompleted;
bool lastRun;
public Activity()
@@ -71,9 +100,13 @@ namespace OpenRA.Activities
if (State == ActivityState.Queued)
{
OnFirstRun(self);
firstRunCompleted = true;
State = ActivityState.Active;
}
if (!firstRunCompleted)
throw new InvalidOperationException("Actor {0} attempted to tick activity {1} before running its OnFirstRun method.".F(self, GetType()));
// Only run the parent tick when the child is done.
// We must always let the child finish on its own before continuing.
if (ChildHasPriority)
@@ -152,8 +185,7 @@ namespace OpenRA.Activities
/// </summary>
internal void OnActorDisposeOuter(Actor self)
{
if (ChildActivity != null)
ChildActivity.OnActorDisposeOuter(self);
ChildActivity?.OnActorDisposeOuter(self);
OnActorDispose(self);
}
@@ -166,10 +198,10 @@ namespace OpenRA.Activities
if (!IsInterruptible)
return;
if (ChildActivity != null)
ChildActivity.Cancel(self);
ChildActivity?.Cancel(self);
State = ActivityState.Canceling;
// Directly mark activities that are queued and therefore didn't run yet as done
State = State == ActivityState.Queued ? ActivityState.Done : ActivityState.Canceling;
}
public void Queue(Activity activity)
@@ -209,11 +241,9 @@ namespace OpenRA.Activities
Console.WriteLine(GetType().ToString().Split('.').Last());
if (ChildActivity != null)
ChildActivity.PrintActivityTree(self, origin, level + 1);
ChildActivity?.PrintActivityTree(self, origin, level + 1);
if (NextActivity != null)
NextActivity.PrintActivityTree(self, origin, level);
NextActivity?.PrintActivityTree(self, origin, level);
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -26,7 +26,7 @@ namespace OpenRA.Activities
public override bool Tick(Actor self)
{
if (a != null) a();
a?.Invoke();
return true;
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Eluant;
using Eluant.ObjectBinding;
@@ -44,7 +45,12 @@ namespace OpenRA
public bool WillDispose { get; private set; }
public bool Disposed { get; private set; }
public Activity CurrentActivity { get; private set; }
Activity currentActivity;
public Activity CurrentActivity
{
get { return Activity.SkipDoneActivities(currentActivity); }
private set { currentActivity = value; }
}
public int Generation;
public Actor ReplacedByActor;
@@ -63,16 +69,40 @@ namespace OpenRA
{
get
{
// TODO: Support non-zero pitch/roll in IFacing (IOrientation?)
var facingValue = facing != null ? facing.Facing : 0;
return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facingValue));
return facing != null ? facing.Orientation : WRot.None;
}
}
/// <summary>Value used to represent an invalid token.</summary>
public static readonly int InvalidConditionToken = -1;
class ConditionState
{
/// <summary>Delegates that have registered to be notified when this condition changes.</summary>
public readonly List<VariableObserverNotifier> Notifiers = new List<VariableObserverNotifier>();
/// <summary>Unique integers identifying granted instances of the condition.</summary>
public readonly HashSet<int> Tokens = new HashSet<int>();
}
readonly Dictionary<string, ConditionState> conditionStates = new Dictionary<string, ConditionState>();
/// <summary>Each granted condition receives a unique token that is used when revoking.</summary>
readonly Dictionary<int, string> conditionTokens = new Dictionary<int, string>();
int nextConditionToken = 1;
/// <summary>Cache of condition -> enabled state for quick evaluation of token counter conditions.</summary>
readonly Dictionary<string, int> conditionCache = new Dictionary<string, int>();
/// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary>
readonly IReadOnlyDictionary<string, int> readOnlyConditionCache;
internal SyncHash[] SyncHashes { get; private set; }
readonly IFacing facing;
readonly IHealth health;
readonly IResolveOrder[] resolveOrders;
readonly IRenderModifier[] renderModifiers;
readonly IRender[] renders;
readonly IMouseBounds[] mouseBounds;
@@ -80,17 +110,28 @@ namespace OpenRA
readonly IDefaultVisibility defaultVisibility;
readonly INotifyBecomingIdle[] becomingIdles;
readonly INotifyIdle[] tickIdles;
readonly ITargetablePositions[] targetablePositions;
readonly IEnumerable<ITargetablePositions> enabledTargetablePositions;
WPos[] staticTargetablePositions;
bool created;
bool setStaticTargetablePositions;
internal Actor(World world, string name, TypeDictionary initDict)
{
var duplicateInit = initDict.WithInterface<ISingleInstanceInit>().GroupBy(i => i.GetType())
.FirstOrDefault(i => i.Count() > 1);
if (duplicateInit != null)
throw new InvalidDataException("Duplicate initializer '{0}'".F(duplicateInit.Key.Name));
var init = new ActorInitializer(this, initDict);
readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache);
World = world;
ActorID = world.NextAID();
if (initDict.Contains<OwnerInit>())
Owner = init.Get<OwnerInit, Player>();
var ownerInit = init.GetOrDefault<OwnerInit>();
if (ownerInit != null)
Owner = ownerInit.Value(world);
if (name != null)
{
@@ -100,42 +141,125 @@ namespace OpenRA
throw new NotImplementedException("No rules definition for unit " + name);
Info = world.Map.Rules.Actors[name];
foreach (var trait in Info.TraitsInConstructOrder())
{
AddTrait(trait.Create(init));
// Some traits rely on properties provided by IOccupySpace in their initialization,
// so we must ready it now, we cannot wait until all traits have finished construction.
if (trait is IOccupySpaceInfo)
OccupiesSpace = Trait<IOccupySpace>();
IPositionable positionable = null;
var resolveOrdersList = new List<IResolveOrder>();
var renderModifiersList = new List<IRenderModifier>();
var rendersList = new List<IRender>();
var mouseBoundsList = new List<IMouseBounds>();
var visibilityModifiersList = new List<IVisibilityModifier>();
var becomingIdlesList = new List<INotifyBecomingIdle>();
var tickIdlesList = new List<INotifyIdle>();
var targetablesList = new List<ITargetable>();
var targetablePositionsList = new List<ITargetablePositions>();
var syncHashesList = new List<SyncHash>();
foreach (var traitInfo in Info.TraitsInConstructOrder())
{
var trait = traitInfo.Create(init);
AddTrait(trait);
// PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
// actor that allows us to provide some fast implementations of commonly used methods that are relied on by
// performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
// Note: The blocks are required to limit the scope of the t's, so we make an exception to our normal style
// rules for spacing in order to keep these assignments compact and readable.
{ if (trait is IPositionable t) positionable = t; }
{ if (trait is IOccupySpace t) OccupiesSpace = t; }
{ if (trait is IEffectiveOwner t) EffectiveOwner = t; }
{ if (trait is IFacing t) facing = t; }
{ if (trait is IHealth t) health = t; }
{ if (trait is IResolveOrder t) resolveOrdersList.Add(t); }
{ if (trait is IRenderModifier t) renderModifiersList.Add(t); }
{ if (trait is IRender t) rendersList.Add(t); }
{ if (trait is IMouseBounds t) mouseBoundsList.Add(t); }
{ if (trait is IVisibilityModifier t) visibilityModifiersList.Add(t); }
{ if (trait is IDefaultVisibility t) defaultVisibility = t; }
{ if (trait is INotifyBecomingIdle t) becomingIdlesList.Add(t); }
{ if (trait is INotifyIdle t) tickIdlesList.Add(t); }
{ if (trait is ITargetable t) targetablesList.Add(t); }
{ if (trait is ITargetablePositions t) targetablePositionsList.Add(t); }
{ if (trait is ISync t) syncHashesList.Add(new SyncHash(t)); }
}
resolveOrders = resolveOrdersList.ToArray();
renderModifiers = renderModifiersList.ToArray();
renders = rendersList.ToArray();
mouseBounds = mouseBoundsList.ToArray();
visibilityModifiers = visibilityModifiersList.ToArray();
becomingIdles = becomingIdlesList.ToArray();
tickIdles = tickIdlesList.ToArray();
Targetables = targetablesList.ToArray();
var targetablePositions = targetablePositionsList.ToArray();
enabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled);
SyncHashes = syncHashesList.ToArray();
setStaticTargetablePositions = positionable == null && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled);
}
}
internal void Initialize(bool addToWorld = true)
{
created = true;
// Make sure traits are usable for condition notifiers
foreach (var t in TraitsImplementing<INotifyCreated>())
t.Created(this);
var allObserverNotifiers = new HashSet<VariableObserverNotifier>();
foreach (var provider in TraitsImplementing<IObservesVariables>())
{
foreach (var variableUser in provider.GetVariableObservers())
{
allObserverNotifiers.Add(variableUser.Notifier);
foreach (var variable in variableUser.Variables)
{
var cs = conditionStates.GetOrAdd(variable);
cs.Notifiers.Add(variableUser.Notifier);
// Initialize conditions that have not yet been granted to 0
// NOTE: Some conditions may have already been granted by INotifyCreated calling GrantCondition,
// and we choose to assign the token count to safely cover both cases instead of adding an if branch.
conditionCache[variable] = cs.Tokens.Count;
}
}
}
// PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
// actor that allows us to provide some fast implementations of commonly used methods that are relied on by
// performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
EffectiveOwner = TraitOrDefault<IEffectiveOwner>();
facing = TraitOrDefault<IFacing>();
health = TraitOrDefault<IHealth>();
renderModifiers = TraitsImplementing<IRenderModifier>().ToArray();
renders = TraitsImplementing<IRender>().ToArray();
mouseBounds = TraitsImplementing<IMouseBounds>().ToArray();
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
defaultVisibility = Trait<IDefaultVisibility>();
becomingIdles = TraitsImplementing<INotifyBecomingIdle>().ToArray();
tickIdles = TraitsImplementing<INotifyIdle>().ToArray();
Targetables = TraitsImplementing<ITargetable>().ToArray();
targetablePositions = TraitsImplementing<ITargetablePositions>().ToArray();
world.AddFrameEndTask(w =>
{
// Caching this in a AddFrameEndTask, because trait construction order might cause problems if done directly at creation time.
// All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and
// all targetable positions can be cached if all ITargetablePositions have no conditional requirements.
if (!Info.HasTraitInfo<IPositionableInfo>() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled))
staticTargetablePositions = targetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray();
});
// Update all traits with their initial condition state
foreach (var notify in allObserverNotifiers)
notify(this, readOnlyConditionCache);
SyncHashes = TraitsImplementing<ISync>().Select(sync => new SyncHash(sync)).ToArray();
// All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and
// all targetable positions can be cached if all ITargetablePositions have no conditional requirements.
if (setStaticTargetablePositions)
staticTargetablePositions = enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray();
// TODO: Other traits may need initialization after being notified of initial condition state.
// TODO: A post condition initialization notification phase may allow queueing activities instead.
// The initial activity should run before any activities queued by INotifyCreated.Created
// However, we need to know which traits are enabled (via conditions), so wait for after the calls and insert the activity as the first
ICreationActivity creationActivity = null;
foreach (var ica in TraitsImplementing<ICreationActivity>())
{
if (!ica.IsTraitEnabled())
continue;
if (creationActivity != null)
throw new InvalidOperationException("More than one enabled ICreationActivity trait: {0} and {1}".F(creationActivity.GetType().Name, ica.GetType().Name));
var activity = ica.GetCreationActivity();
if (activity == null)
continue;
creationActivity = ica;
activity.Queue(CurrentActivity);
CurrentActivity = activity;
}
if (addToWorld)
World.Add(this);
}
public void Tick()
@@ -198,7 +322,7 @@ namespace OpenRA
yield return r;
}
public Rectangle MouseBounds(WorldRenderer wr)
public Polygon MouseBounds(WorldRenderer wr)
{
foreach (var mb in mouseBounds)
{
@@ -207,18 +331,22 @@ namespace OpenRA
return bounds;
}
return Rectangle.Empty;
return Polygon.Empty;
}
public void QueueActivity(bool queued, Activity nextActivity)
{
if (!queued)
CancelActivity();
QueueActivity(nextActivity);
}
public void QueueActivity(Activity nextActivity)
{
if (!created)
throw new InvalidOperationException("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 +355,7 @@ namespace OpenRA
public void CancelActivity()
{
if (CurrentActivity != null)
CurrentActivity.Cancel(this);
CurrentActivity?.Cancel(this);
}
public override int GetHashCode()
@@ -280,8 +407,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)
WillDispose = true;
@@ -300,11 +426,16 @@ namespace OpenRA
World.TraitDict.RemoveActor(this);
Disposed = true;
if (luaInterface != null)
luaInterface.Value.OnActorDestroyed();
luaInterface?.Value.OnActorDestroyed();
});
}
public void ResolveOrder(Order order)
{
foreach (var r in resolveOrders)
r.ResolveOrder(this, order);
}
// TODO: move elsewhere.
public void ChangeOwner(Player newOwner)
{
@@ -408,13 +539,71 @@ namespace OpenRA
if (staticTargetablePositions != null)
return staticTargetablePositions;
var enabledTargetablePositionTraits = targetablePositions.Where(Exts.IsTraitEnabled);
if (enabledTargetablePositionTraits.Any())
return enabledTargetablePositionTraits.SelectMany(tp => tp.TargetablePositions(this));
if (enabledTargetablePositions.Any())
return enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this));
return new[] { CenterPosition };
}
#region Conditions
void UpdateConditionState(string condition, int token, bool isRevoke)
{
ConditionState conditionState = conditionStates.GetOrAdd(condition);
if (isRevoke)
conditionState.Tokens.Remove(token);
else
conditionState.Tokens.Add(token);
conditionCache[condition] = conditionState.Tokens.Count;
// Conditions may be granted or revoked before the state is initialized.
// These notifications will be processed after INotifyCreated.Created.
if (created)
foreach (var notify in conditionState.Notifiers)
notify(this, readOnlyConditionCache);
}
/// <summary>
/// Grants a specified condition if it is valid.
/// Otherwise, just returns InvalidConditionToken.
/// </summary>
/// <returns>The token that is used to revoke this condition.</returns>
public int GrantCondition(string condition)
{
if (string.IsNullOrEmpty(condition))
return InvalidConditionToken;
var token = nextConditionToken++;
conditionTokens.Add(token, condition);
UpdateConditionState(condition, token, false);
return token;
}
/// <summary>
/// Revokes a previously granted condition.
/// </summary>
/// <param name="token">The token ID returned by GrantCondition.</param>
/// <returns>The invalid token ID.</returns>
public int RevokeCondition(int token)
{
if (!conditionTokens.TryGetValue(token, out var condition))
throw new InvalidOperationException("Attempting to revoke condition with invalid token {0} for {1}.".F(token, this));
conditionTokens.Remove(token);
UpdateConditionState(condition, token, true);
return InvalidConditionToken;
}
/// <summary>Returns whether the specified token is valid for RevokeCondition</summary>
public bool TokenValid(int token)
{
return conditionTokens.ContainsKey(token);
}
#endregion
#region Scripting interface
Lazy<ScriptActorInterface> luaInterface;
@@ -432,8 +621,7 @@ namespace OpenRA
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
{
Actor a, b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out Actor a) || !right.TryGetClrValue(out Actor b))
return false;
return a == b;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -89,9 +89,7 @@ namespace OpenRA
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CPos a;
CVec b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out CPos a) || !right.TryGetClrValue(out CVec b))
throw new LuaException("Attempted to call CPos.Add(CPos, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
return new LuaCustomClrObject(a + b);
@@ -99,21 +97,18 @@ namespace OpenRA
public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CPos a;
var rightType = right.WrappedClrType();
if (!left.TryGetClrValue(out a))
if (!left.TryGetClrValue(out CPos a))
throw new LuaException("Attempted to call CPos.Subtract(CPos, (CPos|CVec)) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, rightType.Name));
if (rightType == typeof(CPos))
{
CPos b;
right.TryGetClrValue(out b);
right.TryGetClrValue(out CPos b);
return new LuaCustomClrObject(a - b);
}
else if (rightType == typeof(CVec))
{
CVec b;
right.TryGetClrValue(out b);
right.TryGetClrValue(out CVec b);
return new LuaCustomClrObject(a - b);
}
@@ -122,8 +117,7 @@ namespace OpenRA
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CPos a, b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out CPos a) || !right.TryGetClrValue(out CPos b))
return false;
return a == b;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -75,8 +75,7 @@ namespace OpenRA
public LuaValue Add(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CVec a, b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
throw new LuaException("Attempted to call CVec.Add(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
return new LuaCustomClrObject(a + b);
@@ -84,8 +83,7 @@ namespace OpenRA
public LuaValue Subtract(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CVec a, b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
throw new LuaException("Attempted to call CVec.Subtract(CVec, CVec) with invalid arguments ({0}, {1})".F(left.WrappedClrType().Name, right.WrappedClrType().Name));
return new LuaCustomClrObject(a - b);
@@ -98,8 +96,7 @@ namespace OpenRA
public LuaValue Equals(LuaRuntime runtime, LuaValue left, LuaValue right)
{
CVec a, b;
if (!left.TryGetClrValue(out a) || !right.TryGetClrValue(out b))
if (!left.TryGetClrValue(out CVec a) || !right.TryGetClrValue(out CVec b))
return false;
return a == b;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -0,0 +1,20 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using OpenRA.Primitives;
namespace OpenRA
{
public class DefaultPlayer : IGlobalModData
{
public readonly Color Color = Color.FromAhsl(0, 0, 238);
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -90,8 +90,7 @@ namespace OpenRA
public void CancelAsync()
{
lock (syncObject)
if (wc != null)
wc.CancelAsync();
wc?.CancelAsync();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -18,26 +19,23 @@ namespace OpenRA.Effects
public class DelayedImpact : IEffect
{
readonly Target target;
readonly Actor firedBy;
readonly IEnumerable<int> damageModifiers;
readonly IWarhead wh;
readonly WarheadArgs args;
int delay;
public DelayedImpact(int delay, IWarhead wh, Target target, Actor firedBy, IEnumerable<int> damageModifiers)
public DelayedImpact(int delay, IWarhead wh, Target target, WarheadArgs args)
{
this.wh = wh;
this.delay = delay;
this.target = target;
this.firedBy = firedBy;
this.damageModifiers = damageModifiers;
this.args = args;
}
public void Tick(World world)
{
if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); wh.DoImpact(target, firedBy, damageModifiers); });
world.AddFrameEndTask(w => { w.Remove(this); wh.DoImpact(target, args); });
}
public IEnumerable<IRenderable> Render(WorldRenderer wr) { yield break; }

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -24,4 +24,5 @@ namespace OpenRA.Effects
public interface ISpatiallyPartitionable { }
public interface IEffectAboveShroud { IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr); }
public interface IEffectAnnotation { IEnumerable<IRenderable> RenderAnnotation(WorldRenderer wr); }
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -16,6 +16,7 @@ using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA
{
@@ -30,6 +31,8 @@ namespace OpenRA
public readonly string LaunchPath;
public readonly string[] LaunchArgs;
public Sprite Icon { get; internal set; }
public Sprite Icon2x { get; internal set; }
public Sprite Icon3x { get; internal set; }
public static string MakeKey(Manifest mod) { return MakeKey(mod.Id, mod.Metadata.Version); }
public static string MakeKey(ExternalMod mod) { return MakeKey(mod.Id, mod.Version); }
@@ -41,14 +44,34 @@ namespace OpenRA
readonly Dictionary<string, ExternalMod> mods = new Dictionary<string, ExternalMod>();
readonly SheetBuilder sheetBuilder;
Sheet CreateSheet()
{
var sheet = new Sheet(SheetType.BGRA, new Size(512, 512));
// We must manually force the buffer creation to avoid a crash
// that is indirectly triggered by rendering from a Sheet that
// has not yet been written to.
sheet.CreateBuffer();
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
return sheet;
}
public ExternalMods()
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, 256);
// Don't try to load mod icons if we don't have a texture to put them in
if (Game.Renderer != null)
sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet);
// If the player has defined a local support directory (in the game directory)
// then this will override both the regular and system support dirs
var sources = new[] { Platform.SystemSupportDir, Platform.SupportDir };
foreach (var source in sources.Distinct())
// Several types of support directory types are available, depending on
// how the player has installed and launched the game.
// Read registration metadata from all of them
var sources = Enum.GetValues(typeof(SupportDirType))
.Cast<SupportDirType>()
.Select(t => Platform.GetSupportDir(t))
.Distinct();
foreach (var source in sources)
{
var metadataPath = Path.Combine(source, "ModMetadata");
if (!Directory.Exists(metadataPath))
@@ -73,11 +96,23 @@ namespace OpenRA
void LoadMod(MiniYaml yaml, string path = null, bool forceRegistration = false)
{
var mod = FieldLoader.Load<ExternalMod>(yaml);
var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon");
if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value))
if (sheetBuilder != null)
{
using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value)))
mod.Icon = sheetBuilder.Add(new Png(stream));
var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon");
if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value)))
mod.Icon = sheetBuilder.Add(new Png(stream));
var icon2xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon2x");
if (icon2xNode != null && !string.IsNullOrEmpty(icon2xNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(icon2xNode.Value.Value)))
mod.Icon2x = sheetBuilder.Add(new Png(stream), 1f / 2);
var icon3xNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon3x");
if (icon3xNode != null && !string.IsNullOrEmpty(icon3xNode.Value.Value))
using (var stream = new MemoryStream(Convert.FromBase64String(icon3xNode.Value.Value)))
mod.Icon3x = sheetBuilder.Add(new Png(stream), 1f / 3);
}
// Avoid possibly overwriting a valid mod with an obviously bogus one
@@ -86,40 +121,52 @@ namespace OpenRA
mods[key] = mod;
}
internal void Register(Manifest mod, string launchPath, ModRegistration registration)
internal void Register(Manifest mod, string launchPath, IEnumerable<string> launchArgs, ModRegistration registration)
{
if (mod.Metadata.Hidden)
return;
var iconData = "";
var key = ExternalMod.MakeKey(mod);
var yaml = new MiniYamlNode("Registration", new MiniYaml("", new List<MiniYamlNode>()
{
new MiniYamlNode("Id", mod.Id),
new MiniYamlNode("Version", mod.Metadata.Version),
new MiniYamlNode("Title", mod.Metadata.Title),
new MiniYamlNode("LaunchPath", launchPath),
new MiniYamlNode("LaunchArgs", new[] { "Game.Mod=" + mod.Id }.Concat(launchArgs).JoinWith(", "))
}));
using (var stream = mod.Package.GetStream("icon.png"))
if (stream != null)
iconData = Convert.ToBase64String(stream.ReadAllBytes());
yaml.Value.Nodes.Add(new MiniYamlNode("Icon", Convert.ToBase64String(stream.ReadAllBytes())));
var key = ExternalMod.MakeKey(mod);
var yaml = new List<MiniYamlNode>()
{
new MiniYamlNode("Registration", new MiniYaml("", new List<MiniYamlNode>()
{
new MiniYamlNode("Id", mod.Id),
new MiniYamlNode("Version", mod.Metadata.Version),
new MiniYamlNode("Title", mod.Metadata.Title),
new MiniYamlNode("Icon", iconData),
new MiniYamlNode("LaunchPath", launchPath),
new MiniYamlNode("LaunchArgs", "Game.Mod=" + mod.Id)
}))
};
using (var stream = mod.Package.GetStream("icon-2x.png"))
if (stream != null)
yaml.Value.Nodes.Add(new MiniYamlNode("Icon2x", Convert.ToBase64String(stream.ReadAllBytes())));
using (var stream = mod.Package.GetStream("icon-3x.png"))
if (stream != null)
yaml.Value.Nodes.Add(new MiniYamlNode("Icon3x", Convert.ToBase64String(stream.ReadAllBytes())));
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
sources.Add(Platform.GetSupportDir(SupportDirType.User));
// If using the modern support dir we must also write the registration
// to the legacy support dir for older engine versions, but ONLY if it exists
var legacyPath = Platform.GetSupportDir(SupportDirType.LegacyUser);
if (Directory.Exists(legacyPath))
sources.Add(legacyPath);
}
// Make sure the mod is available for this session, even if saving it fails
LoadMod(yaml.First().Value, forceRegistration: true);
LoadMod(yaml.Value, forceRegistration: true);
var lines = new List<MiniYamlNode> { yaml }.ToLines().ToArray();
foreach (var source in sources.Distinct())
{
var metadataPath = Path.Combine(source, "ModMetadata");
@@ -127,7 +174,7 @@ namespace OpenRA
try
{
Directory.CreateDirectory(metadataPath);
File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), yaml.ToLines().ToArray());
File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), lines);
}
catch (Exception e)
{
@@ -148,10 +195,16 @@ namespace OpenRA
{
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
// User support dir may be using the modern or legacy value, or overridden by the user
// Add all the possibilities and let the .Distinct() below ignore the duplicates
sources.Add(Platform.GetSupportDir(SupportDirType.User));
sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser));
sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser));
}
var activeModKey = ExternalMod.MakeKey(activeMod);
foreach (var source in sources.Distinct())
@@ -207,10 +260,16 @@ namespace OpenRA
{
var sources = new List<string>();
if (registration.HasFlag(ModRegistration.System))
sources.Add(Platform.SystemSupportDir);
sources.Add(Platform.GetSupportDir(SupportDirType.System));
if (registration.HasFlag(ModRegistration.User))
sources.Add(Platform.SupportDir);
{
// User support dir may be using the modern or legacy value, or overridden by the user
// Add all the possibilities and let the .Distinct() below ignore the duplicates
sources.Add(Platform.GetSupportDir(SupportDirType.User));
sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser));
sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser));
}
var key = ExternalMod.MakeKey(mod);
mods.Remove(key);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -80,7 +80,7 @@ namespace OpenRA
static int WindingDirectionTest(int2 v0, int2 v1, int2 p)
{
return (v1.X - v0.X) * (p.Y - v0.Y) - (p.X - v0.X) * (v1.Y - v0.Y);
return Math.Sign((v1.X - v0.X) * (p.Y - v0.Y) - (p.X - v0.X) * (v1.Y - v0.Y));
}
public static bool PolygonContains(this int2[] polygon, int2 p)
@@ -101,6 +101,16 @@ namespace OpenRA
return windingNumber != 0;
}
public static bool LinesIntersect(int2 a, int2 b, int2 c, int2 d)
{
// If line segments AB and CD intersect:
// - the triangles ACD and BCD must have opposite sense (clockwise or anticlockwise)
// - the triangles CAB and DAB must have opposite sense
// Segments intersect if the orientation (clockwise or anticlockwise) of the two points in each line segment are opposite with respect to the other
// Assumes that lines are not colinear
return WindingDirectionTest(c, d, a) != WindingDirectionTest(c, d, b) && WindingDirectionTest(a, b, c) != WindingDirectionTest(a, b, d);
}
public static bool HasModifier(this Modifiers k, Modifiers mod)
{
// PERF: Enum.HasFlag is slower and requires allocations.
@@ -110,13 +120,19 @@ namespace OpenRA
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
where V : new()
{
return d.GetOrAdd(k, _ => new V());
return d.GetOrAdd(k, new V());
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, V v)
{
if (!d.TryGetValue(k, out var ret))
d.Add(k, ret = v);
return ret;
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
{
V ret;
if (!d.TryGetValue(k, out ret))
if (!d.TryGetValue(k, out var ret))
d.Add(k, ret = createFn(k));
return ret;
}
@@ -151,6 +167,26 @@ namespace OpenRA
return xs.ElementAt(r.Next(xs.Count));
}
public static Rectangle Union(this IEnumerable<Rectangle> rects)
{
// PERF: Avoid LINQ.
var first = true;
var result = Rectangle.Empty;
foreach (var rect in rects)
{
if (first)
{
first = false;
result = rect;
continue;
}
result = Rectangle.Union(rect, result);
}
return result;
}
public static float Product(this IEnumerable<float> xs)
{
return xs.Aggregate(1f, (a, x) => a * x);
@@ -323,8 +359,7 @@ namespace OpenRA
public static int IntegerDivisionRoundingAwayFromZero(int dividend, int divisor)
{
int remainder;
var quotient = Math.DivRem(dividend, divisor, out remainder);
var quotient = Math.DivRem(dividend, divisor, out var remainder);
if (remainder == 0)
return quotient;
return quotient + (Math.Sign(dividend) == Math.Sign(divisor) ? 1 : -1);
@@ -375,8 +410,7 @@ namespace OpenRA
// Check for a key conflict:
if (d.ContainsKey(key))
{
List<string> dupKeyMessages;
if (!dupKeys.TryGetValue(key, out dupKeyMessages))
if (!dupKeys.TryGetValue(key, out var dupKeyMessages))
{
// Log the initial conflicting value already inserted:
dupKeyMessages = new List<string>();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -18,7 +18,6 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -122,8 +121,7 @@ namespace OpenRA
{
ret = null;
MiniYaml yaml;
if (!md.TryGetValue(yamlName, out yaml))
if (!md.TryGetValue(yamlName, out var yaml))
return false;
ret = GetValue(field.Name, field.FieldType, yaml, field);
@@ -181,42 +179,36 @@ namespace OpenRA
public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field)
{
var value = yaml.Value;
if (value != null) value = value.Trim();
var value = yaml.Value?.Trim();
if (fieldType == typeof(int))
{
int res;
if (Exts.TryParseIntegerInvariant(value, out res))
if (Exts.TryParseIntegerInvariant(value, out var res))
return res;
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(ushort))
{
ushort res;
if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res))
if (ushort.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res))
return res;
return InvalidValueAction(value, fieldType, fieldName);
}
if (fieldType == typeof(long))
{
long res;
if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out res))
if (long.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var res))
return res;
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(float))
{
float res;
if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res))
if (value != null && float.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res))
return res * (value.Contains('%') ? 0.01f : 1f);
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(decimal))
{
decimal res;
if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res))
if (value != null && decimal.TryParse(value.Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res))
return res * (value.Contains('%') ? 0.01m : 1m);
return InvalidValueAction(value, fieldType, fieldName);
}
@@ -228,16 +220,14 @@ namespace OpenRA
}
else if (fieldType == typeof(Color))
{
Color color;
if (value != null && Color.TryParse(value, out color))
if (value != null && Color.TryParse(value, out var color))
return color;
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(Hotkey))
{
Hotkey res;
if (Hotkey.TryParse(value, out res))
if (Hotkey.TryParse(value, out var res))
return res;
return InvalidValueAction(value, fieldType, fieldName);
@@ -248,8 +238,7 @@ namespace OpenRA
}
else if (fieldType == typeof(WDist))
{
WDist res;
if (WDist.TryParse(value, out res))
if (WDist.TryParse(value, out var res))
return res;
return InvalidValueAction(value, fieldType, fieldName);
@@ -261,8 +250,7 @@ namespace OpenRA
var parts = value.Split(',');
if (parts.Length == 3)
{
WDist rx, ry, rz;
if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz))
if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var rz))
return new WVec(rx, ry, rz);
}
}
@@ -282,8 +270,7 @@ namespace OpenRA
for (var i = 0; i < vecs.Length; ++i)
{
WDist rx, ry, rz;
if (WDist.TryParse(parts[3 * i], out rx) && WDist.TryParse(parts[3 * i + 1], out ry) && WDist.TryParse(parts[3 * i + 2], out rz))
if (WDist.TryParse(parts[3 * i], out var rx) && WDist.TryParse(parts[3 * i + 1], out var ry) && WDist.TryParse(parts[3 * i + 2], out var rz))
vecs[i] = new WVec(rx, ry, rz);
}
@@ -299,8 +286,7 @@ namespace OpenRA
var parts = value.Split(',');
if (parts.Length == 3)
{
WDist rx, ry, rz;
if (WDist.TryParse(parts[0], out rx) && WDist.TryParse(parts[1], out ry) && WDist.TryParse(parts[2], out rz))
if (WDist.TryParse(parts[0], out var rx) && WDist.TryParse(parts[1], out var ry) && WDist.TryParse(parts[2], out var rz))
return new WPos(rx, ry, rz);
}
}
@@ -309,8 +295,7 @@ namespace OpenRA
}
else if (fieldType == typeof(WAngle))
{
int res;
if (Exts.TryParseIntegerInvariant(value, out res))
if (Exts.TryParseIntegerInvariant(value, out var res))
return new WAngle(res);
return InvalidValueAction(value, fieldType, fieldName);
}
@@ -321,8 +306,7 @@ namespace OpenRA
var parts = value.Split(',');
if (parts.Length == 3)
{
int rr, rp, ry;
if (Exts.TryParseIntegerInvariant(parts[0], out rr) && Exts.TryParseIntegerInvariant(parts[1], out rp) && Exts.TryParseIntegerInvariant(parts[2], out ry))
if (Exts.TryParseIntegerInvariant(parts[0], out var rr) && Exts.TryParseIntegerInvariant(parts[1], out var rp) && Exts.TryParseIntegerInvariant(parts[2], out var ry))
return new WRot(new WAngle(rr), new WAngle(rp), new WAngle(ry));
}
}
@@ -361,8 +345,7 @@ namespace OpenRA
var vecs = new CVec[parts.Length / 2];
for (var i = 0; i < vecs.Length; i++)
{
int rx, ry;
if (int.TryParse(parts[2 * i], out rx) && int.TryParse(parts[2 * i + 1], out ry))
if (int.TryParse(parts[2 * i], out var rx) && int.TryParse(parts[2 * i + 1], out var ry))
vecs[i] = new CVec(rx, ry);
}
@@ -415,7 +398,12 @@ namespace OpenRA
}
}
else if (fieldType == typeof(bool))
return ParseYesNo(value, fieldType, fieldName);
{
if (bool.TryParse(value.ToLowerInvariant(), out var result))
return result;
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(int2[]))
{
if (value != null)
@@ -447,7 +435,7 @@ namespace OpenRA
ret.SetValue(GetValue(fieldName, fieldType.GetElementType(), parts[i].Trim(), field), i);
return ret;
}
else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(HashSet<>))
else if (fieldType.IsGenericType && (fieldType.GetGenericTypeDefinition() == typeof(HashSet<>) || fieldType.GetGenericTypeDefinition() == typeof(List<>)))
{
var set = Activator.CreateInstance(fieldType);
if (value == null)
@@ -504,8 +492,7 @@ namespace OpenRA
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float xx = 0;
float yy = 0;
float res;
if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res))
if (float.TryParse(parts[0].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var res))
xx = res * (parts[0].Contains('%') ? 0.01f : 1f);
if (float.TryParse(parts[1].Replace("%", ""), NumberStyles.Float, NumberFormatInfo.InvariantInfo, out res))
yy = res * (parts[1].Contains('%') ? 0.01f : 1f);
@@ -519,13 +506,11 @@ namespace OpenRA
if (value != null)
{
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float x = 0;
float y = 0;
float z = 0;
float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out x);
float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out y);
float.TryParse(parts[0], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var x);
float.TryParse(parts[1], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out var y);
// z component is optional for compatibility with older float2 definitions
float z = 0;
if (parts.Length > 2)
float.TryParse(parts[2], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out z);
@@ -561,14 +546,16 @@ namespace OpenRA
}
else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (string.IsNullOrEmpty(value))
return null;
var innerType = fieldType.GetGenericArguments().First();
var innerValue = GetValue("Nullable<T>", innerType, value, field);
return fieldType.GetConstructor(new[] { innerType }).Invoke(new[] { innerValue });
}
else if (fieldType == typeof(DateTime))
{
DateTime dt;
if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out dt))
if (DateTime.TryParseExact(value, "yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var dt))
return dt;
return InvalidValueAction(value, fieldType, fieldName);
}
@@ -592,20 +579,6 @@ namespace OpenRA
return null;
}
static object ParseYesNo(string p, Type fieldType, string field)
{
if (string.IsNullOrEmpty(p))
return InvalidValueAction(p, fieldType, field);
p = p.ToLowerInvariant();
if (p == "yes") return true;
if (p == "true") return true;
if (p == "no") return false;
if (p == "false") return false;
return InvalidValueAction(p, fieldType, field);
}
public sealed class FieldLoadInfo
{
public readonly FieldInfo Field;
@@ -732,8 +705,7 @@ namespace OpenRA
if (translations == null)
return key;
string value;
if (!translations.TryGetValue(key, out value))
if (!translations.TryGetValue(key, out var value))
return key;
return value;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -15,7 +15,6 @@ using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA
@@ -95,7 +94,7 @@ namespace OpenRA
return ((Array)v).Cast<object>().Select(FormatValue).JoinWith(", ");
}
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(HashSet<>))
if (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(HashSet<>) || t.GetGenericTypeDefinition() == typeof(List<>)))
{
return ((System.Collections.IEnumerable)v).Cast<object>().Select(FormatValue).JoinWith(", ");
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -63,19 +63,16 @@ namespace OpenRA.FileSystem
{
// Raw directories are the easiest and one of the most common cases, so try these first
var resolvedPath = Platform.ResolvePath(filename);
if (!filename.Contains("|") && Directory.Exists(resolvedPath))
if (!resolvedPath.Contains("|") && Directory.Exists(resolvedPath))
return new Folder(resolvedPath);
// Children of another package require special handling
IReadOnlyPackage parent;
string subPath = null;
if (TryGetPackageContaining(filename, out parent, out subPath))
if (TryGetPackageContaining(filename, out var parent, out var subPath))
return parent.OpenPackage(subPath, this);
// Try and open it normally
IReadOnlyPackage package;
var stream = Open(filename);
if (TryParsePackage(stream, filename, out package))
if (TryParsePackage(stream, filename, out var package))
return package;
// No package loaders took ownership of the stream, so clean it up
@@ -97,8 +94,7 @@ namespace OpenRA.FileSystem
{
name = name.Substring(1);
Manifest mod;
if (!installedMods.TryGetValue(name, out mod))
if (!installedMods.TryGetValue(name, out var mod))
throw new InvalidOperationException("Could not load mod '{0}'. Available mods: {1}".F(name, installedMods.Keys.JoinWith(", ")));
package = mod.Package;
@@ -122,8 +118,7 @@ namespace OpenRA.FileSystem
public void Mount(IReadOnlyPackage package, string explicitName = null)
{
var mountCount = 0;
if (mountedPackages.TryGetValue(package, out mountCount))
if (mountedPackages.TryGetValue(package, out var mountCount))
{
// Package is already mounted
// Increment the mount count and bump up the file loading priority
@@ -149,8 +144,7 @@ namespace OpenRA.FileSystem
public bool Unmount(IReadOnlyPackage package)
{
var mountCount = 0;
if (!mountedPackages.TryGetValue(package, out mountCount))
if (!mountedPackages.TryGetValue(package, out var mountCount))
return false;
if (--mountCount <= 0)
@@ -203,16 +197,12 @@ namespace OpenRA.FileSystem
var package = fileIndex[filename]
.LastOrDefault(x => x.Contains(filename));
if (package != null)
return package.GetStream(filename);
return null;
return package?.GetStream(filename);
}
public Stream Open(string filename)
{
Stream s;
if (!TryOpen(filename, out s))
if (!TryOpen(filename, out var s))
throw new FileNotFoundException("File not found: {0}".F(filename), filename);
return s;
@@ -238,8 +228,7 @@ namespace OpenRA.FileSystem
var explicitSplit = filename.IndexOf('|');
if (explicitSplit > 0)
{
IReadOnlyPackage explicitPackage;
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage))
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
{
s = explicitPackage.GetStream(filename.Substring(explicitSplit + 1));
if (s != null)
@@ -274,12 +263,9 @@ namespace OpenRA.FileSystem
{
var explicitSplit = filename.IndexOf('|');
if (explicitSplit > 0)
{
IReadOnlyPackage explicitPackage;
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage))
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
if (explicitPackage.Contains(filename.Substring(explicitSplit + 1)))
return true;
}
return fileIndex.ContainsKey(filename);
}
@@ -293,8 +279,7 @@ namespace OpenRA.FileSystem
if (explicitSplit < 0)
return false;
IReadOnlyPackage explicitPackage;
if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out explicitPackage))
if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
return false;
if (installedMods[modID].Package == explicitPackage)
@@ -310,7 +295,7 @@ namespace OpenRA.FileSystem
public static string ResolveAssemblyPath(string path, Manifest manifest, InstalledMods installedMods)
{
var explicitSplit = path.IndexOf('|');
if (explicitSplit > 0)
if (explicitSplit > 0 && !path.StartsWith("^"))
{
var parent = path.Substring(0, explicitSplit);
var filename = path.Substring(explicitSplit + 1);
@@ -321,8 +306,7 @@ namespace OpenRA.FileSystem
if (parentPath.StartsWith("$", StringComparison.Ordinal))
{
Manifest mod;
if (!installedMods.TryGetValue(parentPath.Substring(1), out mod))
if (!installedMods.TryGetValue(parentPath.Substring(1), out var mod))
return null;
if (!(mod.Package is Folder))

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -12,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileSystem
{
@@ -32,10 +33,11 @@ namespace OpenRA.FileSystem
{
get
{
foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
yield return Path.GetFileName(filename);
foreach (var filename in Directory.GetDirectories(path))
yield return Path.GetFileName(filename);
// Order may vary on different file systems and it matters for hashing.
return Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)
.Concat(Directory.GetDirectories(path))
.Select(Path.GetFileName)
.OrderBy(f => f);
}
}
@@ -58,17 +60,15 @@ namespace OpenRA.FileSystem
return new Folder(resolvedPath);
// Zip files loaded from Folders (and *only* from Folders) can be read-write
IReadWritePackage readWritePackage;
if (ZipFileLoader.TryParseReadWritePackage(resolvedPath, out readWritePackage))
if (ZipFileLoader.TryParseReadWritePackage(resolvedPath, out var readWritePackage))
return readWritePackage;
// Other package types can be loaded normally
IReadOnlyPackage package;
var s = GetStream(filename);
if (s == null)
return null;
if (context.TryParsePackage(s, filename, out package))
if (context.TryParsePackage(s, filename, out var package))
return package;
s.Dispose();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -14,7 +14,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.SharpZipLib.Zip;
using OpenRA.Primitives;
namespace OpenRA.FileSystem
{
@@ -67,8 +66,7 @@ namespace OpenRA.FileSystem
public void Dispose()
{
if (pkg != null)
pkg.Close();
pkg?.Close();
}
public IReadOnlyPackage OpenPackage(string filename, FileSystem context)
@@ -82,12 +80,11 @@ namespace OpenRA.FileSystem
return new ZipFolder(this, filename);
// Other package types can be loaded normally
IReadOnlyPackage package;
var s = GetStream(filename);
if (s == null)
return null;
if (context.TryParsePackage(s, filename, out package))
if (context.TryParsePackage(s, filename, out var package))
return package;
s.Dispose();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -17,11 +17,13 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime;
using System.Threading;
using System.Threading.Tasks;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Primitives;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
@@ -38,9 +40,10 @@ namespace OpenRA
public static ModData ModData;
public static Settings Settings;
public static ICursor Cursor;
public static CursorManager Cursor;
public static bool HideCursor;
static WorldRenderer worldRenderer;
static string modLaunchWrapper;
internal static OrderManager OrderManager;
static Server.Server server;
@@ -49,7 +52,6 @@ namespace OpenRA
public static Renderer Renderer;
public static Sound Sound;
public static bool HasInputFocus = false;
public static string EngineVersion { get; private set; }
public static LocalPlayerProfile LocalPlayerProfile;
@@ -60,26 +62,26 @@ namespace OpenRA
public static event Action OnShellmapLoaded = () => { };
public static OrderManager JoinServer(string host, int port, string password, bool recordReplay = true)
public static OrderManager JoinServer(ConnectionTarget endpoint, string password, bool recordReplay = true)
{
var connection = new NetworkConnection(host, port);
var connection = new NetworkConnection(endpoint);
if (recordReplay)
connection.StartRecording(() => { return TimestampedFilename(); });
var om = new OrderManager(host, port, password, connection);
var om = new OrderManager(endpoint, password, connection);
JoinInner(om);
return om;
}
static string TimestampedFilename(bool includemilliseconds = false)
public static string TimestampedFilename(bool includemilliseconds = false, string extra = "")
{
var format = includemilliseconds ? "yyyy-MM-ddTHHmmssfffZ" : "yyyy-MM-ddTHHmmssZ";
return "OpenRA-" + DateTime.UtcNow.ToString(format, CultureInfo.InvariantCulture);
return ModData.Manifest.Id + extra + "-" + DateTime.UtcNow.ToString(format, CultureInfo.InvariantCulture);
}
static void JoinInner(OrderManager om)
{
if (OrderManager != null) OrderManager.Dispose();
OrderManager?.Dispose();
OrderManager = om;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged(OrderManager);
@@ -87,12 +89,12 @@ namespace OpenRA
public static void JoinReplay(string replayFile)
{
JoinInner(new OrderManager("<no server>", -1, "", new ReplayConnection(replayFile)));
JoinInner(new OrderManager(new ConnectionTarget(), "", new ReplayConnection(replayFile)));
}
static void JoinLocal()
{
JoinInner(new OrderManager("<no server>", -1, "", new EchoConnection()));
JoinInner(new OrderManager(new ConnectionTarget(), "", new EchoConnection()));
}
// More accurate replacement for Environment.TickCount
@@ -103,14 +105,14 @@ namespace OpenRA
public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } }
public static int LocalTick { get { return OrderManager.LocalFrameNumber; } }
public static event Action<string, int> OnRemoteDirectConnect = (a, b) => { };
public static event Action<ConnectionTarget> OnRemoteDirectConnect = _ => { };
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return OrderManager.Connection.LocalClientId; } }
public static void RemoteDirectConnect(string host, int port)
public static void RemoteDirectConnect(ConnectionTarget endpoint)
{
OnRemoteDirectConnect(host, port);
OnRemoteDirectConnect(endpoint);
}
// Hacky workaround for orderManager visibility
@@ -153,8 +155,7 @@ namespace OpenRA
internal static void StartGame(string mapUID, WorldType type)
{
// Dispose of the old world before creating a new one.
if (worldRenderer != null)
worldRenderer.Dispose();
worldRenderer?.Dispose();
Cursor.SetCursor(null);
BeforeGameStart();
@@ -170,11 +171,13 @@ namespace OpenRA
worldRenderer = new WorldRenderer(ModData, OrderManager.World);
// Proactively collect memory during loading to reduce peak memory.
GC.Collect();
using (new PerfTimer("LoadComplete"))
OrderManager.World.LoadComplete(worldRenderer);
// Proactively collect memory during loading to reduce peak memory.
GC.Collect();
if (OrderManager.GameStarted)
@@ -189,6 +192,14 @@ namespace OpenRA
worldRenderer.RefreshPalette();
Cursor.SetCursor("default");
// Now loading is completed, now is the ideal time to run a GC and compact the LOH.
// - All the temporary garbage created during loading can be collected.
// - Live objects are likely to live for the length of the game or longer,
// thus promoting them into a higher generation is not an issue.
// - We can remove any fragmentation in the LOH caused by temporary loading garbage.
// - A loading screen is visible, so a delay won't matter to the user.
// Much better to clean up now then to drop frames during gameplay for GC pauses.
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
}
@@ -232,7 +243,7 @@ namespace OpenRA
LobbyInfoChanged += lobbyReady;
om = JoinServer(IPAddress.Loopback.ToString(), CreateLocalServer(mapUID), "");
om = JoinServer(CreateLocalServer(mapUID), "");
}
public static bool IsHost
@@ -251,20 +262,26 @@ namespace OpenRA
public static void InitializeSettings(Arguments args)
{
Settings = new Settings(Platform.ResolvePath(Path.Combine(Platform.SupportDirPrefix, "settings.yaml")), args);
Settings = new Settings(Path.Combine(Platform.SupportDir, "settings.yaml"), args);
}
public static RunStatus InitializeAndRun(string[] args)
{
Initialize(new Arguments(args));
// Proactively collect memory during loading to reduce peak memory.
GC.Collect();
return Run();
}
static void Initialize(Arguments args)
{
var engineDirArg = args.GetValue("Engine.EngineDir", null);
if (!string.IsNullOrEmpty(engineDirArg))
Platform.OverrideEngineDir(engineDirArg);
var supportDirArg = args.GetValue("Engine.SupportDir", null);
if (supportDirArg != null)
if (!string.IsNullOrEmpty(supportDirArg))
Platform.OverrideSupportDir(supportDirArg);
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
@@ -272,7 +289,7 @@ namespace OpenRA
// Load the engine version as early as possible so it can be written to exception logs
try
{
EngineVersion = File.ReadAllText(Platform.ResolvePath(Path.Combine(".", "VERSION"))).Trim();
EngineVersion = File.ReadAllText(Path.Combine(Platform.EngineDir, "VERSION")).Trim();
}
catch { }
@@ -280,6 +297,7 @@ namespace OpenRA
EngineVersion = "Unknown";
Console.WriteLine("Engine version is {0}", EngineVersion);
Console.WriteLine("Runtime: {0}", Platform.RuntimeVersion);
// Special case handling of Game.Mod argument: if it matches a real filesystem path
// then we use this to override the mod search path, and replace it with the mod id
@@ -300,6 +318,7 @@ namespace OpenRA
Log.AddChannel("graphics", "graphics.log");
Log.AddChannel("geoip", "geoip.log");
Log.AddChannel("nat", "nat.log");
Log.AddChannel("client", "client.log");
var platforms = new[] { Settings.Game.Platform, "Default", null };
foreach (var p in platforms)
@@ -310,10 +329,17 @@ namespace OpenRA
Settings.Game.Platform = p;
try
{
var rendererPath = Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms." + p + ".dll"));
var assembly = Assembly.LoadFile(rendererPath);
var rendererPath = Path.Combine(Platform.BinDir, "OpenRA.Platforms." + p + ".dll");
#if !MONO
var loader = new AssemblyLoader(rendererPath);
var platformType = loader.LoadDefaultAssembly().GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t));
#else
var assembly = Assembly.LoadFile(rendererPath);
var platformType = assembly.GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t));
#endif
if (platformType == null)
throw new InvalidOperationException("Platform dll must include exactly one IPlatform implementation.");
@@ -328,45 +354,51 @@ namespace OpenRA
Log.Write("graphics", "{0}", e);
Console.WriteLine("Renderer initialization failed. Check graphics.log for details.");
if (Renderer != null)
Renderer.Dispose();
Renderer?.Dispose();
if (Sound != null)
Sound.Dispose();
Sound?.Dispose();
}
}
GeoIP.Initialize();
if (Settings.Server.DiscoverNatDevices)
discoverNat = UPnP.DiscoverNatDevices(Settings.Server.NatDiscoveryTimeout);
var modSearchArg = args.GetValue("Engine.ModSearchPaths", null);
var modSearchPaths = modSearchArg != null ?
FieldLoader.GetValue<string[]>("Engine.ModsPath", modSearchArg) :
new[] { Path.Combine(".", "mods") };
new[] { Path.Combine(Platform.EngineDir, "mods") };
Mods = new InstalledMods(modSearchPaths, explicitModPaths);
Console.WriteLine("Internal mods:");
foreach (var mod in Mods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Metadata.Title, mod.Value.Metadata.Version);
modLaunchWrapper = args.GetValue("Engine.LaunchWrapper", null);
ExternalMods = new ExternalMods();
Manifest currentMod;
if (modID != null && Mods.TryGetValue(modID, out currentMod))
if (modID != null && Mods.TryGetValue(modID, out _))
{
var launchPath = args.GetValue("Engine.LaunchPath", Assembly.GetEntryAssembly().Location);
var launchPath = args.GetValue("Engine.LaunchPath", null);
var launchArgs = new List<string>();
// Sanitize input from platform-specific launchers
// Process.Start requires paths to not be quoted, even if they contain spaces
if (launchPath.First() == '"' && launchPath.Last() == '"')
if (launchPath != null && launchPath.First() == '"' && launchPath.Last() == '"')
launchPath = launchPath.Substring(1, launchPath.Length - 2);
ExternalMods.Register(Mods[modID], launchPath, ModRegistration.User);
if (launchPath == null)
{
// When launching the assembly directly we must propagate the Engine.EngineDir argument if defined
// Platform-specific launchers are expected to manage this internally.
launchPath = Assembly.GetEntryAssembly().Location;
if (!string.IsNullOrEmpty(engineDirArg))
launchArgs.Add("Engine.EngineDir=\"" + engineDirArg + "\"");
}
ExternalMod activeMod;
if (ExternalMods.TryGetValue(ExternalMod.MakeKey(Mods[modID]), out activeMod))
ExternalMods.Register(Mods[modID], launchPath, launchArgs, ModRegistration.User);
if (ExternalMods.TryGetValue(ExternalMod.MakeKey(Mods[modID]), out var activeMod))
ExternalMods.ClearInvalidRegistrations(activeMod, ModRegistration.User);
}
@@ -383,18 +415,15 @@ namespace OpenRA
LobbyInfoChanged = () => { };
ConnectionStateChanged = om => { };
BeforeGameStart = () => { };
OnRemoteDirectConnect = (a, b) => { };
OnRemoteDirectConnect = endpoint => { };
delayedActions = new ActionQueue();
Ui.ResetAll();
if (worldRenderer != null)
worldRenderer.Dispose();
worldRenderer?.Dispose();
worldRenderer = null;
if (server != null)
server.Shutdown();
if (OrderManager != null)
OrderManager.Dispose();
server?.Shutdown();
OrderManager?.Dispose();
if (ModData != null)
{
@@ -416,7 +445,7 @@ namespace OpenRA
ModData = new ModData(Mods[mod], Mods, true);
LocalPlayerProfile = new LocalPlayerProfile(Platform.ResolvePath(Path.Combine("^", Settings.Game.AuthProfile)), ModData.Manifest.Get<PlayerDatabase>());
LocalPlayerProfile = new LocalPlayerProfile(Path.Combine(Platform.SupportDir, Settings.Game.AuthProfile), ModData.Manifest.Get<PlayerDatabase>());
if (!ModData.LoadScreen.BeforeLoad())
return;
@@ -430,40 +459,22 @@ namespace OpenRA
var grid = ModData.Manifest.Contains<MapGrid>() ? ModData.Manifest.Get<MapGrid>() : null;
Renderer.InitializeDepthBuffer(grid);
if (Cursor != null)
Cursor.Dispose();
Cursor?.Dispose();
if (Settings.Graphics.HardwareCursors)
{
try
{
Cursor = new HardwareCursor(ModData.CursorProvider);
}
catch (Exception e)
{
Log.Write("debug", "Failed to initialize hardware cursors. Falling back to software cursors.");
Log.Write("debug", "Error was: " + e.Message);
Console.WriteLine("Failed to initialize hardware cursors. Falling back to software cursors.");
Console.WriteLine("Error was: " + e.Message);
Cursor = new SoftwareCursor(ModData.CursorProvider);
}
}
else
Cursor = new SoftwareCursor(ModData.CursorProvider);
Cursor = new CursorManager(ModData.CursorProvider);
PerfHistory.Items["render"].HasNormalTick = false;
PerfHistory.Items["batches"].HasNormalTick = false;
PerfHistory.Items["render_world"].HasNormalTick = false;
PerfHistory.Items["render_widgets"].HasNormalTick = false;
PerfHistory.Items["render_flip"].HasNormalTick = false;
PerfHistory.Items["terrain_lighting"].HasNormalTick = false;
JoinLocal();
try
{
if (discoverNat != null)
discoverNat.Wait();
discoverNat?.Wait();
}
catch (Exception e)
{
@@ -509,8 +520,15 @@ namespace OpenRA
{
try
{
var path = mod.LaunchPath;
var args = launchArguments != null ? mod.LaunchArgs.Append(launchArguments) : mod.LaunchArgs;
var p = Process.Start(mod.LaunchPath, args.Select(a => "\"" + a + "\"").JoinWith(" "));
if (modLaunchWrapper != null)
{
path = modLaunchWrapper;
args = new[] { mod.LaunchPath }.Concat(args);
}
var p = Process.Start(path, args.Select(a => "\"" + a + "\"").JoinWith(" "));
if (p == null || p.HasExited)
onFailed();
else
@@ -543,14 +561,14 @@ namespace OpenRA
using (new PerfTimer("Renderer.SaveScreenshot"))
{
var mod = ModData.Manifest.Metadata;
var directory = Platform.ResolvePath(Platform.SupportDirPrefix, "Screenshots", ModData.Manifest.Id, mod.Version);
var directory = Path.Combine(Platform.SupportDir, "Screenshots", ModData.Manifest.Id, mod.Version);
Directory.CreateDirectory(directory);
var filename = TimestampedFilename(true);
var path = Path.Combine(directory, string.Concat(filename, ".png"));
Log.Write("debug", "Taking screenshot " + path);
Renderer.Context.SaveScreenshot(path);
Renderer.SaveScreenshot(path);
Debug("Saved screenshot " + filename);
}
}
@@ -619,14 +637,13 @@ namespace OpenRA
Sync.RunUnsynced(Settings.Debug.SyncCheckUnsyncedCode, world, () => world.TickRender(worldRenderer));
}
if (benchmark != null)
benchmark.Tick(LocalTick);
benchmark?.Tick(LocalTick);
}
}
static void LogicTick()
{
delayedActions.PerformActions(RunTime);
PerformDelayedActions();
if (OrderManager.Connection.ConnectionState != lastConnectionState)
{
@@ -639,6 +656,11 @@ namespace OpenRA
InnerLogicTick(worldRenderer.World.OrderManager);
}
public static void PerformDelayedActions()
{
delayedActions.PerformActions(RunTime);
}
public static void TakeScreenshot()
{
takeScreenshot = true;
@@ -650,24 +672,39 @@ namespace OpenRA
{
++RenderFrame;
// worldRenderer is null during the initial install/download screen
if (worldRenderer != null)
// Prepare renderables (i.e. render voxels) before calling BeginFrame
using (new PerfSample("render_prepare"))
{
Renderer.BeginFrame(worldRenderer.Viewport.TopLeft, worldRenderer.Viewport.Zoom);
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
Renderer.WorldModelRenderer.BeginFrame();
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
if (!worldRenderer.World.IsLoadingGameSave)
// World rendering is disabled while the loading screen is displayed
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
{
worldRenderer.Viewport.Tick();
worldRenderer.PrepareRenderables();
}
Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
}
// worldRenderer is null during the initial install/download screen
// World rendering is disabled while the loading screen is displayed
// Use worldRenderer.World instead of OrderManager.World to avoid a rendering mismatch while processing orders
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
{
Renderer.BeginWorld(worldRenderer.Viewport.Rectangle);
Sound.SetListenerPosition(worldRenderer.Viewport.CenterPosition);
using (new PerfSample("render_world"))
worldRenderer.Draw();
}
else
Renderer.BeginFrame(int2.Zero, 1f);
using (new PerfSample("render_widgets"))
{
Renderer.WorldModelRenderer.BeginFrame();
Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
Renderer.BeginUI();
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
worldRenderer.DrawAnnotations();
Ui.Draw();
@@ -695,8 +732,10 @@ namespace OpenRA
PerfHistory.Items["render"].Tick();
PerfHistory.Items["batches"].Tick();
PerfHistory.Items["render_world"].Tick();
PerfHistory.Items["render_widgets"].Tick();
PerfHistory.Items["render_flip"].Tick();
PerfHistory.Items["terrain_lighting"].Tick();
}
static void Loop()
@@ -742,6 +781,7 @@ namespace OpenRA
var nextLogic = RunTime;
var nextRender = RunTime;
var forcedNextRender = RunTime;
var renderBeforeNextTick = false;
while (state == RunStatus.Running)
{
@@ -770,9 +810,9 @@ namespace OpenRA
var nextUpdate = Math.Min(nextLogic, nextRender);
if (now >= nextUpdate)
{
var forceRender = now >= forcedNextRender;
var forceRender = renderBeforeNextTick || now >= forcedNextRender;
if (now >= nextLogic)
if (now >= nextLogic && !renderBeforeNextTick)
{
nextLogic += logicInterval;
@@ -780,7 +820,7 @@ namespace OpenRA
// Force at least one render per tick during regular gameplay
if (OrderManager.World != null && !OrderManager.World.IsLoadingGameSave && !OrderManager.World.IsReplay)
forceRender = true;
renderBeforeNextTick = true;
}
var haveSomeTimeUntilNextLogic = now < nextLogic;
@@ -799,6 +839,7 @@ namespace OpenRA
forcedNextRender = now + maxRenderInterval;
RenderTick();
renderBeforeNextTick = false;
}
}
else
@@ -821,12 +862,10 @@ namespace OpenRA
finally
{
// Ensure that the active replay is properly saved
if (OrderManager != null)
OrderManager.Dispose();
OrderManager?.Dispose();
}
if (worldRenderer != null)
worldRenderer.Dispose();
worldRenderer?.Dispose();
ModData.Dispose();
ChromeProvider.Deinitialize();
@@ -843,6 +882,11 @@ namespace OpenRA
state = RunStatus.Success;
}
public static void AddSystemLine(string text)
{
AddSystemLine("Battlefield Control", text);
}
public static void AddSystemLine(string name, string text)
{
OrderManager.AddChatLine(name, systemMessageColor, text, systemMessageColor);
@@ -860,8 +904,7 @@ namespace OpenRA
public static void Disconnect()
{
if (OrderManager.World != null)
OrderManager.World.TraitDict.PrintReport();
OrderManager.World?.TraitDict.PrintReport();
OrderManager.Dispose();
CloseServer();
@@ -870,8 +913,7 @@ namespace OpenRA
public static void CloseServer()
{
if (server != null)
server.Shutdown();
server?.Shutdown();
}
public static T CreateObject<T>(string name)
@@ -879,12 +921,19 @@ namespace OpenRA
return ModData.ObjectCreator.CreateObject<T>(name);
}
public static void CreateServer(ServerSettings settings)
public static ConnectionTarget CreateServer(ServerSettings settings)
{
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, false);
var endpoints = new List<IPEndPoint>
{
new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort),
new IPEndPoint(IPAddress.Any, settings.ListenPort)
};
server = new Server.Server(endpoints, settings, ModData, ServerType.Multiplayer);
return server.GetEndpointForLocalConnection();
}
public static int CreateLocalServer(string map)
public static ConnectionTarget CreateLocalServer(string map)
{
var settings = new ServerSettings()
{
@@ -893,9 +942,16 @@ namespace OpenRA
AdvertiseOnline = false
};
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, false);
// Always connect to local games using the same loopback connection
// Exposing multiple endpoints introduces a race condition on the client's PlayerIndex (sometimes 0, sometimes 1)
// This would break the Restart button, which relies on the PlayerIndex always being the same for local servers
var endpoints = new List<IPEndPoint>
{
new IPEndPoint(IPAddress.Loopback, 0)
};
server = new Server.Server(endpoints, settings, ModData, ServerType.Local);
return server.Port;
return server.GetEndpointForLocalConnection();
}
public static bool IsCurrentWorld(World world)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -35,6 +35,7 @@ namespace OpenRA
/// <summary>Gets the game's duration, from the time the game started until the replay recording stopped.</summary>
public TimeSpan Duration { get { return EndTimeUtc > StartTimeUtc ? EndTimeUtc - StartTimeUtc : TimeSpan.Zero; } }
public IList<Player> Players { get; private set; }
public HashSet<int> DisabledSpawnPoints = new HashSet<int>();
public MapPreview MapPreview { get { return Game.ModData.MapCache[MapUid]; } }
public IEnumerable<Player> HumanPlayers { get { return Players.Where(p => p.IsHuman); } }
public bool IsSinglePlayer { get { return HumanPlayers.Count() == 1; } }
@@ -118,11 +119,13 @@ namespace OpenRA
IsBot = runtimePlayer.IsBot,
FactionName = runtimePlayer.Faction.Name,
FactionId = runtimePlayer.Faction.InternalName,
DisplayFactionName = runtimePlayer.DisplayFaction.Name,
DisplayFactionId = runtimePlayer.DisplayFaction.InternalName,
Color = runtimePlayer.Color,
Team = client.Team,
SpawnPoint = runtimePlayer.SpawnPoint,
IsRandomFaction = runtimePlayer.Faction.InternalName != client.Faction,
IsRandomSpawnPoint = runtimePlayer.SpawnPoint != client.SpawnPoint,
IsRandomSpawnPoint = runtimePlayer.DisplaySpawnPoint == 0,
Fingerprint = client.Fingerprint
};
@@ -133,9 +136,7 @@ namespace OpenRA
/// <summary>Gets the player information for the specified runtime player instance.</summary>
public Player GetPlayer(OpenRA.Player runtimePlayer)
{
Player player;
playersByRuntime.TryGetValue(runtimePlayer, out player);
playersByRuntime.TryGetValue(runtimePlayer, out var player);
return player;
}
@@ -158,6 +159,10 @@ namespace OpenRA
public string FactionId;
public Color Color;
/// <summary>The faction (including Random, etc.) that was selected in the lobby.</summary>
public string DisplayFactionName;
public string DisplayFactionId;
/// <summary>The team ID on start-up, or 0 if the player is not part of a team.</summary>
public int Team;
public int SpawnPoint;
@@ -181,6 +186,9 @@ namespace OpenRA
/// <summary>The time when this player won or lost the game.</summary>
public DateTime OutcomeTimestampUtc;
/// <summary>The frame at which this player disconnected.</summary>
public int DisconnectFrame;
#endregion
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -23,6 +23,7 @@ namespace OpenRA
public class ActorInfo
{
public const string AbstractActorPrefix = "^";
public const char TraitInstanceSeparator = '@';
/// <summary>
/// The actor name can be anything, but the sprites used in the Render*: traits default to this one.
@@ -32,7 +33,7 @@ namespace OpenRA
/// </summary>
public readonly string Name;
readonly TypeDictionary traits = new TypeDictionary();
List<ITraitInfo> constructOrderCache = null;
List<TraitInfo> constructOrderCache = null;
public ActorInfo(ObjectCreator creator, string name, MiniYaml node)
{
@@ -44,7 +45,11 @@ namespace OpenRA
{
try
{
traits.Add(LoadTraitInfo(creator, t.Key.Split('@')[0], t.Value));
// HACK: The linter does not want to crash when a trait doesn't exist but only print an error instead
// LoadTraitInfo will only return null to signal us to abort here if the linter is running
var trait = LoadTraitInfo(creator, t.Key, t.Value);
if (trait != null)
traits.Add(trait);
}
catch (FieldLoader.MissingFieldsException e)
{
@@ -60,7 +65,7 @@ namespace OpenRA
}
}
public ActorInfo(string name, params ITraitInfo[] traitInfos)
public ActorInfo(string name, params TraitInfo[] traitInfos)
{
Name = name;
foreach (var t in traitInfos)
@@ -68,14 +73,24 @@ namespace OpenRA
traits.TrimExcess();
}
static ITraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my)
static TraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my)
{
if (!string.IsNullOrEmpty(my.Value))
throw new YamlException("Junk value `{0}` on trait node {1}"
.F(my.Value, traitName));
var info = creator.CreateObject<ITraitInfo>(traitName + "Info");
// HACK: The linter does not want to crash when a trait doesn't exist but only print an error instead
// ObjectCreator will only return null to signal us to abort here if the linter is running
var traitInstance = traitName.Split(TraitInstanceSeparator);
var info = creator.CreateObject<TraitInfo>(traitInstance[0] + "Info");
if (info == null)
return null;
try
{
if (traitInstance.Length > 1)
info.GetType().GetField("InstanceName").SetValue(info, traitInstance[1]);
FieldLoader.Load(info, my);
}
catch (FieldLoader.MissingFieldsException e)
@@ -87,12 +102,12 @@ namespace OpenRA
return info;
}
public IEnumerable<ITraitInfo> TraitsInConstructOrder()
public IEnumerable<TraitInfo> TraitsInConstructOrder()
{
if (constructOrderCache != null)
return constructOrderCache;
var source = traits.WithInterface<ITraitInfo>().Select(i => new
var source = traits.WithInterface<TraitInfo>().Select(i => new
{
Trait = i,
Type = i.GetType(),
@@ -138,7 +153,7 @@ namespace OpenRA
return constructOrderCache;
}
public static IEnumerable<Type> PrerequisitesOf(ITraitInfo info)
public static IEnumerable<Type> PrerequisitesOf(TraitInfo info)
{
return info
.GetType()

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -41,8 +41,7 @@ namespace OpenRA.GameRules
public void Load(IReadOnlyFileSystem fileSystem)
{
Stream stream;
if (!fileSystem.TryOpen(Filename, out stream))
if (!fileSystem.TryOpen(Filename, out var stream))
return;
try
@@ -50,8 +49,7 @@ namespace OpenRA.GameRules
Exists = true;
foreach (var loader in Game.ModData.SoundLoaders)
{
ISoundFormat soundFormat;
if (loader.TryParseSound(stream, out soundFormat))
if (loader.TryParseSound(stream, out var soundFormat))
{
Length = (int)soundFormat.LengthInSeconds;
soundFormat.Dispose();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -208,7 +208,7 @@ namespace OpenRA
// TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object
var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] :
new SequenceProvider(fileSystem, modData, ts, mapSequences);
new SequenceProvider(fileSystem, modData, tileSet, mapSequences);
var modelSequences = dr.ModelSequences;
if (mapModelSequences != null)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -24,8 +24,8 @@ namespace OpenRA.GameRules
public int[] DamageModifiers;
public int[] InaccuracyModifiers;
public int[] RangeModifiers;
public int Facing;
public Func<int> CurrentMuzzleFacing;
public WAngle Facing;
public Func<WAngle> CurrentMuzzleFacing;
public WPos Source;
public Func<WPos> CurrentSource;
public Actor SourceActor;
@@ -33,6 +33,40 @@ namespace OpenRA.GameRules
public Target GuidedTarget;
}
public class WarheadArgs
{
public WeaponInfo Weapon;
public int[] DamageModifiers = { };
public WPos? Source;
public WRot ImpactOrientation;
public WPos ImpactPosition;
public Actor SourceActor;
public Target WeaponTarget;
public WarheadArgs(ProjectileArgs args)
{
Weapon = args.Weapon;
DamageModifiers = args.DamageModifiers;
ImpactPosition = args.PassiveTarget;
Source = args.Source;
SourceActor = args.SourceActor;
WeaponTarget = args.GuidedTarget;
}
// For places that only want to update some of the fields (usually DamageModifiers)
public WarheadArgs(WarheadArgs args)
{
Weapon = args.Weapon;
DamageModifiers = args.DamageModifiers;
Source = args.Source;
SourceActor = args.SourceActor;
WeaponTarget = args.WeaponTarget;
}
// Default empty constructor for callers that want to initialize fields themselves
public WarheadArgs() { }
}
public interface IProjectile : IEffect { }
public interface IProjectileInfo { IProjectile Create(ProjectileArgs args); }
@@ -71,6 +105,12 @@ namespace OpenRA.GameRules
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
public readonly BitSet<TargetableType> InvalidTargets;
static readonly BitSet<TargetableType> TargetTypeAir = new BitSet<TargetableType>("Air");
[Desc("If weapon is not directly targeting an actor and targeted position is above this altitude,",
"the weapon will ignore terrain target types and only check TargetTypeAir for validity.")]
public readonly WDist AirThreshold = new WDist(128);
[Desc("Delay in ticks between firing shots from the same ammo magazine. If one entry, it will be used for all bursts.",
"If multiple entries, their number needs to match Burst - 1.")]
public readonly int[] BurstDelays = { 5 };
@@ -97,8 +137,7 @@ namespace OpenRA.GameRules
static object LoadProjectile(MiniYaml yaml)
{
MiniYaml proj;
if (!yaml.ToDictionary().TryGetValue("Projectile", out proj))
if (!yaml.ToDictionary().TryGetValue("Projectile", out var proj))
return null;
var ret = Game.CreateObject<IProjectileInfo>(proj.Value + "Info");
FieldLoader.Load(ret, proj);
@@ -124,7 +163,7 @@ namespace OpenRA.GameRules
}
/// <summary>Checks if the weapon is valid against (can target) the target.</summary>
public bool IsValidAgainst(Target target, World world, Actor firedBy)
public bool IsValidAgainst(in Target target, World world, Actor firedBy)
{
if (target.Type == TargetType.Actor)
return IsValidAgainst(target.Actor, firedBy);
@@ -134,6 +173,10 @@ namespace OpenRA.GameRules
if (target.Type == TargetType.Terrain)
{
var dat = world.Map.DistanceAboveTerrain(target.CenterPosition);
if (dat > AirThreshold)
return IsValidTarget(TargetTypeAir);
var cell = world.Map.CellContaining(target.CenterPosition);
if (!world.Map.Contains(cell))
return false;
@@ -177,17 +220,37 @@ namespace OpenRA.GameRules
}
/// <summary>Applies all the weapon's warheads to the target.</summary>
public void Impact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
public void Impact(in Target target, WarheadArgs args)
{
var world = args.SourceActor.World;
foreach (var warhead in Warheads)
{
var wh = warhead; // force the closure to bind to the current warhead
if (wh.Delay > 0)
firedBy.World.AddFrameEndTask(w => w.Add(new DelayedImpact(wh.Delay, wh, target, firedBy, damageModifiers)));
if (warhead.Delay > 0)
{
// Lambdas can't use 'in' variables, so capture a copy for later
var delayedTarget = target;
world.AddFrameEndTask(w => w.Add(new DelayedImpact(warhead.Delay, warhead, delayedTarget, args)));
}
else
wh.DoImpact(target, firedBy, damageModifiers);
warhead.DoImpact(target, args);
}
}
/// <summary>Applies all the weapon's warheads to the target. Only use for projectile-less, special-case impacts.</summary>
public void Impact(in Target target, Actor firedBy)
{
// The impact will happen immediately at target.CenterPosition.
var args = new WarheadArgs
{
Weapon = this,
SourceActor = firedBy,
WeaponTarget = target
};
if (firedBy.OccupiesSpace != null)
args.Source = firedBy.CenterPosition;
Impact(target, args);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -23,7 +23,7 @@ namespace OpenRA.Graphics
public bool IsDecoration { get; set; }
readonly SequenceProvider sequenceProvider;
readonly Func<int> facingFunc;
readonly Func<WAngle> facingFunc;
readonly Func<bool> paused;
int frame;
@@ -33,15 +33,15 @@ namespace OpenRA.Graphics
Action tickFunc = () => { };
public Animation(World world, string name)
: this(world, name, () => 0) { }
: this(world, name, () => WAngle.Zero) { }
public Animation(World world, string name, Func<int> facingFunc)
public Animation(World world, string name, Func<WAngle> facingFunc)
: this(world, name, facingFunc, null) { }
public Animation(World world, string name, Func<bool> paused)
: this(world, name, () => 0, paused) { }
: this(world, name, () => WAngle.Zero, paused) { }
public Animation(World world, string name, Func<int> facingFunc, Func<bool> paused)
public Animation(World world, string name, Func<WAngle> facingFunc, Func<bool> paused)
{
sequenceProvider = world.Map.Rules.Sequences;
Name = name.ToLowerInvariant();
@@ -54,12 +54,29 @@ namespace OpenRA.Graphics
public IRenderable[] Render(WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale)
{
var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration);
var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration, CurrentSequence.IgnoreWorldTint);
if (CurrentSequence.ShadowStart >= 0)
{
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true);
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true, CurrentSequence.IgnoreWorldTint);
return new IRenderable[] { shadowRenderable, imageRenderable };
}
return new IRenderable[] { imageRenderable };
}
public IRenderable[] RenderUI(WorldRenderer wr, int2 pos, WVec offset, int zOffset, PaletteReference palette, float scale)
{
var screenOffset = (scale * wr.ScreenVectorComponents(offset)).XY.ToInt2();
var imagePos = pos + screenOffset - new int2((int)(scale * Image.Size.X / 2), (int)(scale * Image.Size.Y / 2));
var imageRenderable = new UISpriteRenderable(Image, WPos.Zero + offset, imagePos, CurrentSequence.ZOffset + zOffset, palette, scale);
if (CurrentSequence.ShadowStart >= 0)
{
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
var shadowPos = pos - new int2((int)(scale * shadow.Size.X / 2), (int)(scale * shadow.Size.Y / 2));
var shadowRenderable = new UISpriteRenderable(shadow, WPos.Zero + offset, shadowPos, CurrentSequence.ShadowZOffset + zOffset, palette, scale);
return new IRenderable[] { shadowRenderable, imageRenderable };
}
@@ -139,7 +156,7 @@ namespace OpenRA.Graphics
{
frame = CurrentSequence.Length - 1;
tickFunc = () => { };
if (after != null) after();
after?.Invoke();
}
};
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -9,81 +9,140 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
[Flags]
public enum PanelSides
{
Left = 1,
Top = 2,
Right = 4,
Bottom = 8,
Center = 16,
Edges = Left | Top | Right | Bottom,
All = Edges | Center,
}
public static class PanelSidesExts
{
public static bool HasSide(this PanelSides self, PanelSides m)
{
// PERF: Enum.HasFlag is slower and requires allocations.
return (self & m) == m;
}
}
public static class ChromeProvider
{
struct Collection
public class Collection
{
public string Src;
public Dictionary<string, MappedImage> Regions;
public readonly string Image = null;
public readonly string Image2x = null;
public readonly string Image3x = null;
public readonly int[] PanelRegion = null;
public readonly PanelSides PanelSides = PanelSides.All;
public readonly Dictionary<string, Rectangle> Regions = new Dictionary<string, Rectangle>();
}
public static IReadOnlyDictionary<string, Collection> Collections { get; private set; }
static Dictionary<string, Collection> collections;
static Dictionary<string, Sheet> cachedSheets;
static Dictionary<string, (Sheet Sheet, int Density)> cachedSheets;
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
static Dictionary<string, Sprite[]> cachedPanelSprites;
static Dictionary<Collection, (Sheet Sheet, int)> cachedCollectionSheets;
static IReadOnlyFileSystem fileSystem;
static float dpiScale = 1;
public static void Initialize(ModData modData)
{
Deinitialize();
// Load higher resolution images if available on HiDPI displays
if (Game.Renderer != null)
dpiScale = Game.Renderer.WindowScale;
fileSystem = modData.DefaultFileSystem;
collections = new Dictionary<string, Collection>();
cachedSheets = new Dictionary<string, Sheet>();
cachedSheets = new Dictionary<string, (Sheet, int)>();
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
cachedPanelSprites = new Dictionary<string, Sprite[]>();
cachedCollectionSheets = new Dictionary<Collection, (Sheet, int)>();
Collections = new ReadOnlyDictionary<string, Collection>(collections);
var chrome = MiniYaml.Merge(modData.Manifest.Chrome
.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s)));
foreach (var c in chrome)
LoadCollection(c.Key, c.Value);
if (!c.Key.StartsWith("^", StringComparison.Ordinal))
LoadCollection(c.Key, c.Value);
}
public static void Deinitialize()
{
if (cachedSheets != null)
foreach (var sheet in cachedSheets.Values)
sheet.Dispose();
sheet.Sheet.Dispose();
collections = null;
cachedSheets = null;
cachedSprites = null;
}
public static void Save(string file)
{
var root = new List<MiniYamlNode>();
foreach (var kv in collections)
root.Add(new MiniYamlNode(kv.Key, SaveCollection(kv.Value)));
root.WriteToFile(file);
}
static MiniYaml SaveCollection(Collection collection)
{
var root = new List<MiniYamlNode>();
foreach (var kv in collection.Regions)
root.Add(new MiniYamlNode(kv.Key, kv.Value.Save(collection.Src)));
return new MiniYaml(collection.Src, root);
cachedPanelSprites = null;
cachedCollectionSheets = null;
}
static void LoadCollection(string name, MiniYaml yaml)
{
if (Game.ModData.LoadScreen != null)
Game.ModData.LoadScreen.Display();
var collection = new Collection()
{
Src = yaml.Value,
Regions = yaml.Nodes.ToDictionary(n => n.Key, n => new MappedImage(yaml.Value, n.Value))
};
collections.Add(name, collection);
collections.Add(name, FieldLoader.Load<Collection>(yaml));
}
static (Sheet Sheet, int Density) SheetForCollection(Collection c)
{
// Outer cache avoids recalculating image names
if (!cachedCollectionSheets.TryGetValue(c, out (Sheet, int) sheetDensity))
{
var image = c.Image;
var density = 1;
if (dpiScale > 2 && !string.IsNullOrEmpty(c.Image3x))
{
image = c.Image3x;
density = 3;
}
else if (dpiScale > 1 && !string.IsNullOrEmpty(c.Image2x))
{
image = c.Image2x;
density = 2;
}
// Inner cache makes sure we share sheets between collections
if (!cachedSheets.TryGetValue(image, out sheetDensity))
{
Sheet sheet;
using (var stream = fileSystem.Open(image))
sheet = new Sheet(SheetType.BGRA, stream);
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
sheetDensity = (sheet, density);
cachedSheets.Add(image, sheetDensity);
}
cachedCollectionSheets.Add(c, sheetDensity);
}
return sheetDensity;
}
public static Sprite GetImage(string collectionName, string imageName)
@@ -92,45 +151,135 @@ namespace OpenRA.Graphics
return null;
// Cached sprite
Dictionary<string, Sprite> cachedCollection;
Sprite sprite;
if (cachedSprites.TryGetValue(collectionName, out cachedCollection) && cachedCollection.TryGetValue(imageName, out sprite))
if (cachedSprites.TryGetValue(collectionName, out var cachedCollection) && cachedCollection.TryGetValue(imageName, out var sprite))
return sprite;
Collection collection;
if (!collections.TryGetValue(collectionName, out collection))
if (!collections.TryGetValue(collectionName, out var collection))
{
Log.Write("debug", "Could not find collection '{0}'", collectionName);
return null;
}
MappedImage mi;
if (!collection.Regions.TryGetValue(imageName, out mi))
if (!collection.Regions.TryGetValue(imageName, out var mi))
return null;
// Cached sheet
Sheet sheet;
if (cachedSheets.ContainsKey(mi.Src))
sheet = cachedSheets[mi.Src];
else
{
using (var stream = fileSystem.Open(mi.Src))
sheet = new Sheet(SheetType.BGRA, stream);
cachedSheets.Add(mi.Src, sheet);
}
// Cache the sprite
var sheetDensity = SheetForCollection(collection);
if (cachedCollection == null)
{
cachedCollection = new Dictionary<string, Sprite>();
cachedSprites.Add(collectionName, cachedCollection);
}
var image = mi.GetImage(sheet);
var image = new Sprite(sheetDensity.Sheet, sheetDensity.Density * mi, TextureChannel.RGBA, 1f / sheetDensity.Density);
cachedCollection.Add(imageName, image);
return image;
}
public static Sprite[] GetPanelImages(string collectionName)
{
if (string.IsNullOrEmpty(collectionName))
return null;
// Cached sprite
if (cachedPanelSprites.TryGetValue(collectionName, out var cachedSprites))
return cachedSprites;
if (!collections.TryGetValue(collectionName, out var collection))
{
Log.Write("debug", "Could not find collection '{0}'", collectionName);
return null;
}
Sprite[] sprites;
if (collection.PanelRegion != null)
{
if (collection.PanelRegion.Length != 8)
{
Log.Write("debug", "Collection '{0}' does not define a valid PanelRegion", collectionName);
return null;
}
// Cache the sprites
var sheetDensity = SheetForCollection(collection);
var pr = collection.PanelRegion;
var ps = collection.PanelSides;
var sides = new (PanelSides PanelSides, Rectangle Bounds)[]
{
(PanelSides.Top | PanelSides.Left, new Rectangle(pr[0], pr[1], pr[2], pr[3])),
(PanelSides.Top, new Rectangle(pr[0] + pr[2], pr[1], pr[4], pr[3])),
(PanelSides.Top | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1], pr[6], pr[3])),
(PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3], pr[2], pr[5])),
(PanelSides.Center, new Rectangle(pr[0] + pr[2], pr[1] + pr[3], pr[4], pr[5])),
(PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3], pr[6], pr[5])),
(PanelSides.Bottom | PanelSides.Left, new Rectangle(pr[0], pr[1] + pr[3] + pr[5], pr[2], pr[7])),
(PanelSides.Bottom, new Rectangle(pr[0] + pr[2], pr[1] + pr[3] + pr[5], pr[4], pr[7])),
(PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7]))
};
sprites = sides.Select(x => ps.HasSide(x.PanelSides) ? new Sprite(sheetDensity.Sheet, sheetDensity.Density * x.Bounds, TextureChannel.RGBA, 1f / sheetDensity.Density) : null)
.ToArray();
}
else
{
// Support manual definitions for unusual dialog layouts
sprites = new[]
{
GetImage(collectionName, "corner-tl"),
GetImage(collectionName, "border-t"),
GetImage(collectionName, "corner-tr"),
GetImage(collectionName, "border-l"),
GetImage(collectionName, "background"),
GetImage(collectionName, "border-r"),
GetImage(collectionName, "corner-bl"),
GetImage(collectionName, "border-b"),
GetImage(collectionName, "corner-br")
};
}
cachedPanelSprites.Add(collectionName, sprites);
return sprites;
}
public static Size GetMinimumPanelSize(string collectionName)
{
if (string.IsNullOrEmpty(collectionName))
return new Size(0, 0);
if (!collections.TryGetValue(collectionName, out var collection))
{
Log.Write("debug", "Could not find collection '{0}'", collectionName);
return new Size(0, 0);
}
if (collection.PanelRegion == null || collection.PanelRegion.Length != 8)
{
Log.Write("debug", "Collection '{0}' does not define a valid PanelRegion", collectionName);
return new Size(0, 0);
}
var pr = collection.PanelRegion;
return new Size(pr[2] + pr[6], pr[3] + pr[7]);
}
public static void SetDPIScale(float scale)
{
if (dpiScale == scale)
return;
dpiScale = scale;
// Clear the sprite caches so the new artwork can be loaded
// Sheets are not cleared: we assume that the extra memory overhead
// of having the same sheet in memory in multiple DPIs is better than
// the overhead of having to dispose and reload everything.
// Changing the DPI scale is rare, but if it does happen then there
// is a reasonable chance that it may happen again this session.
cachedSprites.Clear();
cachedPanelSprites.Clear();
cachedCollectionSheets.Clear();
}
}
}

View File

@@ -0,0 +1,298 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public sealed class CursorManager
{
class Cursor
{
public string Name;
public int2 PaddedSize;
public Rectangle Bounds;
public int Length;
public Sprite[] Sprites;
public IHardwareCursor[] Cursors;
}
readonly Dictionary<string, Cursor> cursors = new Dictionary<string, Cursor>();
readonly SheetBuilder sheetBuilder;
readonly GraphicSettings graphicSettings;
Cursor cursor;
bool isLocked = false;
int2 lockedPosition;
bool hardwareCursorsDisabled = false;
bool hardwareCursorsDoubled = false;
public CursorManager(CursorProvider cursorProvider)
{
hardwareCursorsDisabled = Game.Settings.Graphics.DisableHardwareCursors;
graphicSettings = Game.Settings.Graphics;
sheetBuilder = new SheetBuilder(SheetType.BGRA);
foreach (var kv in cursorProvider.Cursors)
{
var frames = kv.Value.Frames;
var palette = !string.IsNullOrEmpty(kv.Value.Palette) ? cursorProvider.Palettes[kv.Value.Palette] : null;
var c = new Cursor
{
Name = kv.Key,
Bounds = Rectangle.FromLTRB(0, 0, 1, 1),
Length = 0,
Sprites = new Sprite[frames.Length],
Cursors = new IHardwareCursor[frames.Length]
};
// Hardware cursors have a number of odd platform-specific bugs/limitations.
// Reduce the number of edge cases by padding the individual frames such that:
// - the hotspot is inside the frame bounds (enforced by SDL)
// - all frames within a sequence have the same size (needed for macOS 10.15)
// - the frame size is a multiple of 8 (needed for Windows)
foreach (var f in frames)
{
// Hotspot is specified relative to the center of the frame
var hotspot = f.Offset.ToInt2() - kv.Value.Hotspot - new int2(f.Size) / 2;
// SheetBuilder expects data in BGRA
var data = FrameToBGRA(kv.Key, f, palette);
c.Sprites[c.Length++] = sheetBuilder.Add(data, f.Size, 0, hotspot);
// Bounds relative to the hotspot
c.Bounds = Rectangle.Union(c.Bounds, new Rectangle(hotspot, f.Size));
}
// Pad bottom-right edge to make the frame size a multiple of 8
c.PaddedSize = 8 * new int2((c.Bounds.Width + 7) / 8, (c.Bounds.Height + 7) / 8);
cursors.Add(kv.Key, c);
}
CreateOrUpdateHardwareCursors();
foreach (var s in sheetBuilder.AllSheets)
s.ReleaseBuffer();
Update();
}
void CreateOrUpdateHardwareCursors()
{
if (hardwareCursorsDisabled)
return;
// Dispose any existing cursors to avoid leaking native resources
ClearHardwareCursors();
try
{
foreach (var kv in cursors)
{
var template = kv.Value;
for (var i = 0; i < template.Sprites.Length; i++)
{
if (template.Cursors[i] != null)
template.Cursors[i].Dispose();
// Calculate the padding to position the frame within sequenceBounds
var paddingTL = -(template.Bounds.Location - template.Sprites[i].Offset.XY.ToInt2());
var paddingBR = template.PaddedSize - new int2(template.Sprites[i].Bounds.Size) - paddingTL;
template.Cursors[i] = CreateHardwareCursor(kv.Key, template.Sprites[i], paddingTL, paddingBR, -template.Bounds.Location);
}
}
}
catch (Exception e)
{
Log.Write("debug", "Failed to initialize hardware cursors. Falling back to software cursors.");
Log.Write("debug", "Error was: " + e.Message);
Console.WriteLine("Failed to initialize hardware cursors. Falling back to software cursors.");
Console.WriteLine("Error was: " + e.Message);
ClearHardwareCursors();
}
hardwareCursorsDoubled = graphicSettings.CursorDouble;
}
public void SetCursor(string cursorName)
{
if ((cursorName == null && cursor == null) || (cursor != null && cursorName == cursor.Name))
return;
if (cursorName == null || !cursors.TryGetValue(cursorName, out cursor))
cursor = null;
Update();
}
int frame;
int ticks;
public void Tick()
{
if (hardwareCursorsDoubled != graphicSettings.CursorDouble)
{
CreateOrUpdateHardwareCursors();
Update();
}
if (cursor == null || cursor.Cursors.Length == 1)
return;
if (++ticks > 2)
{
ticks -= 2;
frame++;
Update();
}
}
void Update()
{
if (cursor != null && frame >= cursor.Cursors.Length)
frame %= cursor.Cursors.Length;
if (cursor == null || isLocked)
Game.Renderer.Window.SetHardwareCursor(null);
else
Game.Renderer.Window.SetHardwareCursor(cursor.Cursors[frame]);
}
public void Render(Renderer renderer)
{
// Cursor is hidden
if (cursor == null)
return;
// Hardware cursor is enabled
if (!isLocked && cursor.Cursors[frame % cursor.Length] != null)
return;
// Render cursor in software
var doubleCursor = graphicSettings.CursorDouble;
var cursorSprite = cursor.Sprites[frame % cursor.Length];
var cursorSize = doubleCursor ? 2.0f * cursorSprite.Size : cursorSprite.Size;
// Cursor is rendered in native window coordinates
// Apply same scaling rules as hardware cursors
if (Game.Renderer.NativeWindowScale > 1.5f)
cursorSize = 2 * cursorSize;
var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos;
renderer.RgbaSpriteRenderer.DrawSprite(cursorSprite,
mousePos,
cursorSize / Game.Renderer.WindowScale);
}
public void Lock()
{
lockedPosition = Viewport.LastMousePos;
Game.Renderer.Window.SetRelativeMouseMode(true);
isLocked = true;
Update();
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
Update();
}
public static byte[] FrameToBGRA(string name, ISpriteFrame frame, ImmutablePalette palette)
{
// Data is already in BGRA format
if (frame.Type == SpriteFrameType.BGRA)
return frame.Data;
// Cursors may be either native BGRA or Indexed.
// Indexed sprites are converted to BGRA using the referenced palette.
// All palettes must be explicitly referenced, even if they are embedded in the sprite.
if (frame.Type == SpriteFrameType.Indexed && palette == null)
throw new InvalidOperationException("Cursor sequence `{0}` attempted to load an indexed sprite but does not define Palette".F(name));
var width = frame.Size.Width;
var height = frame.Size.Height;
var data = new byte[4 * width * height];
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++)
{
var rgba = palette[frame.Data[j * width + i]];
var k = 4 * (j * width + i);
// Convert RGBA to BGRA
data[k] = (byte)(rgba >> 16);
data[k + 1] = (byte)(rgba >> 8);
data[k + 2] = (byte)(rgba >> 0);
data[k + 3] = (byte)(rgba >> 24);
}
}
return data;
}
IHardwareCursor CreateHardwareCursor(string name, Sprite data, int2 paddingTL, int2 paddingBR, int2 hotspot)
{
var size = data.Bounds.Size;
var srcStride = data.Sheet.Size.Width;
var srcData = data.Sheet.GetData();
var newWidth = paddingTL.X + size.Width + paddingBR.X;
var newHeight = paddingTL.Y + size.Height + paddingBR.Y;
var rgbaData = new byte[4 * newWidth * newHeight];
for (var j = 0; j < size.Height; j++)
{
for (var i = 0; i < size.Width; i++)
{
var src = 4 * ((j + data.Bounds.Top) * srcStride + data.Bounds.Left + i);
var dest = 4 * ((j + paddingTL.Y) * newWidth + i + paddingTL.X);
Array.Copy(srcData, src, rgbaData, dest, 4);
}
}
return Game.Renderer.Window.CreateHardwareCursor(name, new Size(newWidth, newHeight), rgbaData, hotspot, graphicSettings.CursorDouble);
}
void ClearHardwareCursors()
{
foreach (var c in cursors.Values)
{
for (var i = 0; i < c.Cursors.Length; i++)
{
if (c.Cursors[i] != null)
{
c.Cursors[i].Dispose();
c.Cursors[i] = null;
}
}
}
}
public void Dispose()
{
ClearHardwareCursors();
cursors.Clear();
sheetBuilder.Dispose();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -36,6 +36,7 @@ namespace OpenRA.Graphics
pals[p.Palette] = p;
Palettes = nodesDict["Cursors"].Nodes.Select(n => n.Value.Value)
.Where(p => p != null)
.Distinct()
.ToDictionary(p => p, p => pals[p].ReadPalette(modData.DefaultFileSystem))
.AsReadOnly();
@@ -49,8 +50,6 @@ namespace OpenRA.Graphics
Cursors = cursors.AsReadOnly();
}
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
public bool HasCursorSequence(string cursor)
{
return Cursors.ContainsKey(cursor);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -31,8 +31,10 @@ namespace OpenRA.Graphics
Palette = palette;
Name = name;
Frames = cache[cursorSrc].Skip(Start).ToArray();
if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*"))
Length = Frames.Length - Start;
Length = Frames.Length;
else if (d.ContainsKey("Length"))
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
else if (d.ContainsKey("End"))
@@ -40,22 +42,17 @@ namespace OpenRA.Graphics
else
Length = 1;
Frames = cache[cursorSrc]
.Skip(Start)
.Take(Length)
.ToArray();
Frames = Frames.Take(Length).ToArray();
if (d.ContainsKey("X"))
{
int x;
Exts.TryParseIntegerInvariant(d["X"].Value, out x);
Exts.TryParseIntegerInvariant(d["X"].Value, out var x);
Hotspot = Hotspot.WithX(x);
}
if (d.ContainsKey("Y"))
{
int y;
Exts.TryParseIntegerInvariant(d["Y"].Value, out y);
Exts.TryParseIntegerInvariant(d["Y"].Value, out var y);
Hotspot = Hotspot.WithY(y);
}
}

View File

@@ -1,192 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public sealed class HardwareCursor : ICursor
{
readonly Dictionary<string, IHardwareCursor[]> hardwareCursors = new Dictionary<string, IHardwareCursor[]>();
readonly CursorProvider cursorProvider;
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
readonly SheetBuilder sheetBuilder;
readonly HardwarePalette hardwarePalette = new HardwarePalette();
readonly Cache<string, PaletteReference> paletteReferences;
CursorSequence cursor;
bool isLocked = false;
int2 lockedPosition;
public HardwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var p in cursorProvider.Palettes)
hardwarePalette.AddPalette(p.Key, p.Value, false);
hardwarePalette.Initialize();
sheetBuilder = new SheetBuilder(SheetType.Indexed);
foreach (var kv in cursorProvider.Cursors)
{
var palette = cursorProvider.Palettes[kv.Value.Palette];
var hc = kv.Value.Frames
.Select(f => CreateCursor(f, palette, kv.Key, kv.Value))
.ToArray();
hardwareCursors.Add(kv.Key, hc);
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
sprites.Add(kv.Key, s);
}
sheetBuilder.Current.ReleaseBuffer();
Update();
}
PaletteReference CreatePaletteReference(string name)
{
var pal = hardwarePalette.GetPalette(name);
return new PaletteReference(name, hardwarePalette.GetPaletteIndex(name), pal, hardwarePalette);
}
IHardwareCursor CreateCursor(ISpriteFrame f, ImmutablePalette palette, string name, CursorSequence sequence)
{
var hotspot = sequence.Hotspot - f.Offset.ToInt2() + new int2(f.Size) / 2;
// Expand the frame if required to include the hotspot
var frameWidth = f.Size.Width;
var dataWidth = f.Size.Width;
var dataX = 0;
if (hotspot.X < 0)
{
dataX = -hotspot.X;
dataWidth += dataX;
hotspot = hotspot.WithX(0);
}
else if (hotspot.X >= frameWidth)
dataWidth = hotspot.X + 1;
var frameHeight = f.Size.Height;
var dataHeight = f.Size.Height;
var dataY = 0;
if (hotspot.Y < 0)
{
dataY = -hotspot.Y;
dataHeight += dataY;
hotspot = hotspot.WithY(0);
}
else if (hotspot.Y >= frameHeight)
dataHeight = hotspot.Y + 1;
var data = new byte[4 * dataWidth * dataHeight];
for (var j = 0; j < frameHeight; j++)
{
for (var i = 0; i < frameWidth; i++)
{
var bytes = BitConverter.GetBytes(palette[f.Data[j * frameWidth + i]]);
var start = 4 * ((j + dataY) * dataWidth + dataX + i);
for (var k = 0; k < 4; k++)
data[start + k] = bytes[k];
}
}
return Game.Renderer.Window.CreateHardwareCursor(name, new Size(dataWidth, dataHeight), data, hotspot);
}
public void SetCursor(string cursorName)
{
if ((cursorName == null && cursor == null) || (cursor != null && cursorName == cursor.Name))
return;
if (cursorName == null || !cursorProvider.Cursors.TryGetValue(cursorName, out cursor))
cursor = null;
Update();
}
int frame;
int ticks;
public void Tick()
{
if (cursor == null || cursor.Length == 1)
return;
if (++ticks > 2)
{
ticks -= 2;
frame++;
Update();
}
}
void Update()
{
if (cursor != null && frame >= cursor.Length)
frame %= cursor.Length;
if (cursor == null || isLocked)
Game.Renderer.Window.SetHardwareCursor(null);
else
Game.Renderer.Window.SetHardwareCursor(hardwareCursors[cursor.Name][frame]);
}
public void Render(Renderer renderer)
{
if (cursor.Name == null || !isLocked)
return;
var cursorSequence = cursorProvider.GetCursorSequence(cursor.Name);
var cursorSprite = sprites[cursor.Name][frame];
var cursorOffset = cursorSequence.Hotspot + (0.5f * cursorSprite.Size.XY).ToInt2();
renderer.SetPalette(hardwarePalette);
renderer.SpriteRenderer.DrawSprite(cursorSprite,
lockedPosition - cursorOffset,
paletteReferences[cursorSequence.Palette],
cursorSprite.Size);
}
public void Lock()
{
lockedPosition = Viewport.LastMousePos;
Game.Renderer.Window.SetRelativeMouseMode(true);
isLocked = true;
Update();
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
Update();
}
public void Dispose()
{
foreach (var cursors in hardwareCursors)
foreach (var cursor in cursors.Value)
cursor.Dispose();
sheetBuilder.Dispose();
hardwareCursors.Clear();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -38,19 +38,16 @@ namespace OpenRA.Graphics
public IPalette GetPalette(string name)
{
MutablePalette mutable;
if (modifiablePalettes.TryGetValue(name, out mutable))
if (modifiablePalettes.TryGetValue(name, out var mutable))
return mutable.AsReadOnly();
ImmutablePalette immutable;
if (palettes.TryGetValue(name, out immutable))
if (palettes.TryGetValue(name, out var immutable))
return immutable;
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
}
public int GetPaletteIndex(string name)
{
int ret;
if (!indices.TryGetValue(name, out ret))
if (!indices.TryGetValue(name, out var ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}

View File

@@ -1,44 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
class MappedImage
{
readonly Rectangle rect = Rectangle.Empty;
public readonly string Src;
public MappedImage(string defaultSrc, MiniYaml info)
{
FieldLoader.LoadField(this, "rect", info.Value);
FieldLoader.Load(this, info);
if (Src == null)
Src = defaultSrc;
}
public Sprite GetImage(Sheet s)
{
return new Sprite(s, rect, TextureChannel.RGBA);
}
public MiniYaml Save(string defaultSrc)
{
var root = new List<MiniYamlNode>();
if (defaultSrc != Src)
root.Add(new MiniYamlNode("Src", Src));
return new MiniYaml(FieldSaver.FormatValue(this, GetType().GetField("rect")), root);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -10,7 +10,6 @@
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Primitives;
namespace OpenRA.Graphics
@@ -19,12 +18,12 @@ namespace OpenRA.Graphics
{
public readonly IModel Model;
public readonly Func<WVec> OffsetFunc;
public readonly Func<IEnumerable<WRot>> RotationFunc;
public readonly Func<WRot> RotationFunc;
public readonly Func<bool> DisableFunc;
public readonly Func<uint> FrameFunc;
public readonly bool ShowShadow;
public ModelAnimation(IModel model, Func<WVec> offset, Func<IEnumerable<WRot>> rotation, Func<bool> disable, Func<uint> frame, bool showshadow)
public ModelAnimation(IModel model, Func<WVec> offset, Func<WRot> rotation, Func<bool> disable, Func<uint> frame, bool showshadow)
{
Model = model;
OffsetFunc = offset;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -48,7 +48,7 @@ namespace OpenRA.Graphics
readonly Dictionary<Sheet, IFrameBuffer> mappedBuffers = new Dictionary<Sheet, IFrameBuffer>();
readonly Stack<KeyValuePair<Sheet, IFrameBuffer>> unmappedBuffers = new Stack<KeyValuePair<Sheet, IFrameBuffer>>();
readonly List<Pair<Sheet, Action>> doRender = new List<Pair<Sheet, Action>>();
readonly List<(Sheet Sheet, Action Func)> doRender = new List<(Sheet, Action)>();
SheetBuilder sheetBuilderForFrame;
bool isInFrame;
@@ -64,10 +64,10 @@ namespace OpenRA.Graphics
shader.SetTexture("Palette", palette);
}
public void SetViewportParams(Size screen, float zoom, int2 scroll)
public void SetViewportParams(Size screen, int2 scroll)
{
var a = 2f / renderer.SheetSize;
var view = new float[]
var view = new[]
{
a, 0, 0, 0,
0, -a, 0, 0,
@@ -79,8 +79,8 @@ namespace OpenRA.Graphics
}
public ModelRenderProxy RenderAsync(
WorldRenderer wr, IEnumerable<ModelAnimation> models, WRot camera, float scale,
float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
WorldRenderer wr, IEnumerable<ModelAnimation> models, in WRot camera, float scale,
float[] groundNormal, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadowPalette)
{
if (!isInFrame)
@@ -114,8 +114,7 @@ namespace OpenRA.Graphics
var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc()));
var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]);
var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(),
(x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x));
var worldTransform = Util.MakeFloatMatrix(m.RotationFunc().AsMatrix());
worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform);
worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform);
@@ -161,10 +160,8 @@ namespace OpenRA.Graphics
}
// Shadows are rendered at twice the resolution to reduce artifacts
Size spriteSize, shadowSpriteSize;
int2 spriteOffset, shadowSpriteOffset;
CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset);
CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset);
CalculateSpriteGeometry(tl, br, 1, out var spriteSize, out var spriteOffset);
CalculateSpriteGeometry(stl, sbr, 2, out var shadowSpriteSize, out var shadowSpriteOffset);
if (sheetBuilderForFrame == null)
sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet);
@@ -181,7 +178,7 @@ namespace OpenRA.Graphics
var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx);
var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx);
doRender.Add(Pair.New<Sheet, Action>(sprite.Sheet, () =>
doRender.Add((sprite.Sheet, () =>
{
foreach (var m in models)
{
@@ -189,8 +186,7 @@ namespace OpenRA.Graphics
var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc()));
var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]);
var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(),
(x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x));
var rotations = Util.MakeFloatMatrix(m.RotationFunc().AsMatrix());
var worldTransform = Util.MatrixMultiply(scaleTransform, rotations);
worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform);
@@ -326,16 +322,16 @@ namespace OpenRA.Graphics
foreach (var v in doRender)
{
// Change sheet
if (v.First != currentSheet)
if (v.Sheet != currentSheet)
{
if (fbo != null)
DisableFrameBuffer(fbo);
currentSheet = v.First;
currentSheet = v.Sheet;
fbo = EnableFrameBuffer(currentSheet);
}
v.Second();
v.Func();
}
if (fbo != null)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -15,9 +15,18 @@ using OpenRA.Primitives;
namespace OpenRA
{
public enum GLProfile
{
Automatic,
ANGLE,
Modern,
Embedded,
Legacy
}
public interface IPlatform
{
IPlatformWindow CreateWindow(Size size, WindowMode windowMode, int batchSize);
IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize, int videoDisplay, GLProfile profile, bool enableLegacyGL);
ISoundEngine CreateSound(string device);
IFont CreateFont(byte[] data);
}
@@ -32,16 +41,26 @@ namespace OpenRA
Subtractive,
Multiply,
Multiplicative,
DoubleMultiplicative
DoubleMultiplicative,
LowAdditive,
Screen,
Translucent
}
public interface IPlatformWindow : IDisposable
{
IGraphicsContext Context { get; }
Size WindowSize { get; }
float WindowScale { get; }
event Action<float, float> OnWindowScaleChanged;
Size NativeWindowSize { get; }
Size EffectiveWindowSize { get; }
float NativeWindowScale { get; }
float EffectiveWindowScale { get; }
Size SurfaceSize { get; }
int DisplayCount { get; }
int CurrentDisplay { get; }
bool HasInputFocus { get; }
event Action<float, float, float, float> OnWindowScaleChanged;
void PumpInput(IInputHandler inputHandler);
string GetClipboardText();
@@ -50,9 +69,14 @@ namespace OpenRA
void GrabWindowMouseFocus();
void ReleaseWindowMouseFocus();
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot);
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot, bool pixelDouble);
void SetHardwareCursor(IHardwareCursor cursor);
void SetRelativeMouseMode(bool mode);
void SetScaleModifier(float scale);
GLProfile GLProfile { get; }
GLProfile[] SupportedGLProfiles { get; }
}
public interface IGraphicsContext : IDisposable
@@ -60,10 +84,10 @@ namespace OpenRA
IVertexBuffer<Vertex> CreateVertexBuffer(int size);
ITexture CreateTexture();
IFrameBuffer CreateFrameBuffer(Size s);
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
IShader CreateShader(string name);
void EnableScissor(int left, int top, int width, int height);
void EnableScissor(int x, int y, int width, int height);
void DisableScissor();
void SaveScreenshot(string path);
void Present();
void DrawPrimitives(PrimitiveType pt, int firstVertex, int numVertices);
void Clear();
@@ -71,6 +95,7 @@ namespace OpenRA
void DisableDepthBuffer();
void ClearDepthBuffer();
void SetBlendMode(BlendMode mode);
void SetVSyncEnabled(bool enabled);
string GLVersion { get; }
}
@@ -78,8 +103,7 @@ namespace OpenRA
{
void Bind();
void SetData(T[] vertices, int length);
void SetData(T[] vertices, int start, int length);
void SetData(IntPtr data, int start, int length);
void SetData(T[] vertices, int offset, int start, int length);
}
public interface IShader
@@ -109,6 +133,8 @@ namespace OpenRA
{
void Bind();
void Unbind();
void EnableScissor(Rectangle rect);
void DisableScissor();
ITexture Texture { get; }
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -47,14 +47,13 @@ namespace OpenRA.Graphics
remapRamp = ramp.Select(r => r - ramp[rampMaxIndex]);
}
remapColors = remapRamp.Select((x, i) => Pair.New(baseIndex + i, Exts.ColorLerp(x / (float)ramp.Length, c1, c2)))
.ToDictionary(u => u.First, u => u.Second);
remapColors = remapRamp.Select((x, i) => (baseIndex + i, Exts.ColorLerp(x / (float)ramp.Length, c1, c2)))
.ToDictionary(u => u.Item1, u => u.Item2);
}
public Color GetRemappedColor(Color original, int index)
{
Color c;
return remapColors.TryGetValue(index, out c)
return remapColors.TryGetValue(index, out var c)
? c : original;
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -28,6 +28,11 @@ namespace OpenRA.Graphics
IFinalizedRenderable PrepareRender(WorldRenderer wr);
}
public interface ITintableRenderable
{
IRenderable WithTint(in float3 newTint);
}
public interface IFinalizedRenderable
{
void Render(WorldRenderer wr);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -28,7 +28,7 @@ namespace OpenRA.Graphics
this.parent = parent;
}
public void DrawLine(float3 start, float3 end, float width, Color startColor, Color endColor)
public void DrawLine(in float3 start, in float3 end, float width, Color startColor, Color endColor)
{
var delta = (end - start) / (end - start).XY.Length;
var corner = width / 2 * new float3(-delta.Y, delta.X, delta.Z);
@@ -55,7 +55,7 @@ namespace OpenRA.Graphics
parent.DrawRGBAVertices(vertices);
}
public void DrawLine(float3 start, float3 end, float width, Color color)
public void DrawLine(in float3 start, in float3 end, float width, Color color)
{
var delta = (end - start) / (end - start).XY.Length;
var corner = width / 2 * new float2(-delta.Y, delta.X);
@@ -80,7 +80,7 @@ namespace OpenRA.Graphics
/// Will behave badly if the lines are parallel.
/// Z position is the average of a and b (ignores actual intersection point if it exists)
/// </summary>
float3 IntersectionOf(float3 a, float3 da, float3 b, float3 db)
float3 IntersectionOf(in float3 a, in float3 da, in float3 b, in float3 db)
{
var crossA = a.X * (a.Y + da.Y) - a.Y * (a.X + da.X);
var crossB = b.X * (b.Y + db.Y) - b.Y * (b.X + db.X);
@@ -153,8 +153,8 @@ namespace OpenRA.Graphics
var nextCorner = width / 2 * new float3(-nextDir.Y, nextDir.X, nextDir.Z);
// Vertices for the corners joining start-end to end-next
var cc = closed || i < limit ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner;
var cd = closed || i < limit ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner;
var cc = closed || i < limit - 1 ? IntersectionOf(end + corner, dir, end + nextCorner, nextDir) : end + corner;
var cd = closed || i < limit - 1 ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner;
// Fill segment
vertices[0] = new Vertex(ca + Offset, r, g, b, a, 0, 0);
@@ -193,14 +193,14 @@ namespace OpenRA.Graphics
DrawConnectedLine(vertices.Select(v => new float3(v, 0)).ToArray(), width, color, true);
}
public void DrawRect(float3 tl, float3 br, float width, Color color)
public void DrawRect(in float3 tl, in float3 br, float width, Color color)
{
var tr = new float3(br.X, tl.Y, tl.Z);
var bl = new float3(tl.X, br.Y, br.Z);
DrawPolygon(new[] { tl, tr, br, bl }, width, color);
}
public void FillTriangle(float3 a, float3 b, float3 c, Color color)
public void FillTriangle(in float3 a, in float3 b, in float3 c, Color color)
{
color = Util.PremultiplyAlpha(color);
var cr = color.R / 255.0f;
@@ -214,14 +214,14 @@ namespace OpenRA.Graphics
parent.DrawRGBAVertices(vertices);
}
public void FillRect(float3 tl, float3 br, Color color)
public void FillRect(in float3 tl, in float3 br, Color color)
{
var tr = new float3(br.X, tl.Y, tl.Z);
var bl = new float3(tl.X, br.Y, br.Z);
FillRect(tl, tr, br, bl, color);
}
public void FillRect(float3 a, float3 b, float3 c, float3 d, Color color)
public void FillRect(in float3 a, in float3 b, in float3 c, in float3 d, Color color)
{
color = Util.PremultiplyAlpha(color);
var cr = color.R / 255.0f;
@@ -238,7 +238,7 @@ namespace OpenRA.Graphics
parent.DrawRGBAVertices(vertices);
}
public void FillRect(float3 a, float3 b, float3 c, float3 d, Color topLeftColor, Color topRightColor, Color bottomRightColor, Color bottomLeftColor)
public void FillRect(in float3 a, in float3 b, in float3 c, in float3 d, Color topLeftColor, Color topRightColor, Color bottomRightColor, Color bottomLeftColor)
{
vertices[0] = VertexWithColor(a + Offset, topLeftColor);
vertices[1] = VertexWithColor(b + Offset, topRightColor);
@@ -250,7 +250,7 @@ namespace OpenRA.Graphics
parent.DrawRGBAVertices(vertices);
}
static Vertex VertexWithColor(float3 xyz, Color color)
static Vertex VertexWithColor(in float3 xyz, Color color)
{
color = Util.PremultiplyAlpha(color);
var cr = color.R / 255.0f;
@@ -261,7 +261,7 @@ namespace OpenRA.Graphics
return new Vertex(xyz, cr, cg, cb, ca, 0, 0);
}
public void FillEllipse(float3 tl, float3 br, Color color, int vertices = 32)
public void FillEllipse(in float3 tl, in float3 br, Color color, int vertices = 32)
{
// TODO: Create an ellipse polygon instead
var a = (br.X - tl.X) / 2;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -22,7 +22,7 @@ namespace OpenRA.Graphics
this.parent = parent;
}
public void DrawSprite(Sprite s, float3 location, float3 size)
public void DrawSprite(Sprite s, in float3 location, in float3 size)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");
@@ -30,7 +30,7 @@ namespace OpenRA.Graphics
parent.DrawSprite(s, location, 0, size);
}
public void DrawSprite(Sprite s, float3 location)
public void DrawSprite(Sprite s, in float3 location)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");
@@ -38,12 +38,28 @@ namespace OpenRA.Graphics
parent.DrawSprite(s, location, 0, s.Size);
}
public void DrawSprite(Sprite s, float3 a, float3 b, float3 c, float3 d)
public void DrawSprite(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");
parent.DrawSprite(s, a, b, c, d);
}
public void DrawSpriteWithTint(Sprite s, in float3 location, in float3 size, in float3 tint)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");
parent.DrawSpriteWithTint(s, location, 0, size, tint);
}
public void DrawSpriteWithTint(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");
parent.DrawSpriteWithTint(s, a, b, c, d, tint);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -32,29 +32,29 @@ namespace OpenRA.Graphics
int ShadowZOffset { get; }
int[] Frames { get; }
Rectangle Bounds { get; }
bool IgnoreWorldTint { get; }
Sprite GetSprite(int frame);
Sprite GetSprite(int frame, int facing);
Sprite GetShadow(int frame, int facing);
Sprite GetSprite(int frame, WAngle facing);
Sprite GetShadow(int frame, WAngle facing);
}
public interface ISpriteSequenceLoader
{
Action<string> OnMissingSpriteError { get; set; }
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node);
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node);
}
public class SequenceProvider : IDisposable
{
readonly ModData modData;
readonly TileSet tileSet;
readonly string tileSet;
readonly Lazy<Sequences> sequences;
readonly Lazy<SpriteCache> spriteCache;
public SpriteCache SpriteCache { get { return spriteCache.Value; } }
readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>();
public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, MiniYaml additionalSequences)
public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, string tileSet, MiniYaml additionalSequences)
{
this.modData = modData;
this.tileSet = tileSet;
@@ -64,22 +64,22 @@ namespace OpenRA.Graphics
return Load(fileSystem, additionalSequences);
});
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders));
}
public ISpriteSequence GetSequence(string unitName, string sequenceName)
{
UnitSequences unitSeq;
if (!sequences.Value.TryGetValue(unitName, out unitSeq))
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName));
ISpriteSequence seq;
if (!unitSeq.Value.TryGetValue(sequenceName, out seq))
if (!unitSeq.Value.TryGetValue(sequenceName, out var seq))
throw new InvalidOperationException("Unit `{0}` does not have a sequence named `{1}`".F(unitName, sequenceName));
return seq;
}
public IEnumerable<string> Images { get { return sequences.Value.Keys; } }
public bool HasSequence(string unitName)
{
return sequences.Value.ContainsKey(unitName);
@@ -87,8 +87,7 @@ namespace OpenRA.Graphics
public bool HasSequence(string unitName, string sequenceName)
{
UnitSequences unitSeq;
if (!sequences.Value.TryGetValue(unitName, out unitSeq))
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName));
return unitSeq.Value.ContainsKey(sequenceName);
@@ -96,8 +95,7 @@ namespace OpenRA.Graphics
public IEnumerable<string> Sequences(string unitName)
{
UnitSequences unitSeq;
if (!sequences.Value.TryGetValue(unitName, out unitSeq))
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName));
return unitSeq.Value.Keys;
@@ -107,15 +105,15 @@ namespace OpenRA.Graphics
{
var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences);
var items = new Dictionary<string, UnitSequences>();
foreach (var n in nodes)
foreach (var node in nodes)
{
// Work around the loop closure issue in older versions of C#
var node = n;
// Nodes starting with ^ are inheritable but never loaded directly
if (node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal))
continue;
var key = node.Value.ToLines(node.Key).JoinWith("|");
UnitSequences t;
if (sequenceCache.TryGetValue(key, out t))
if (sequenceCache.TryGetValue(key, out var t))
items.Add(node.Key, t);
else
{
@@ -130,16 +128,21 @@ namespace OpenRA.Graphics
public void Preload()
{
SpriteCache.SheetBuilder.Current.CreateBuffer();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Current.CreateBuffer();
foreach (var unitSeq in sequences.Value.Values)
foreach (var seq in unitSeq.Value.Values) { }
SpriteCache.SheetBuilder.Current.ReleaseBuffer();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Current.ReleaseBuffer();
}
public void Dispose()
{
if (spriteCache.IsValueCreated)
spriteCache.Value.SheetBuilder.Dispose();
foreach (var sb in SpriteCache.SheetBuilders.Values)
sb.Dispose();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -79,7 +79,17 @@ namespace OpenRA.Graphics
public Png AsPng()
{
return new Png(GetData(), Size.Width, Size.Height);
var data = GetData();
// Convert BGRA to RGBA
for (var i = 0; i < Size.Width * Size.Height; i++)
{
var temp = data[i * 4];
data[i * 4] = data[i * 4 + 2];
data[i * 4 + 2] = temp;
}
return new Png(data, Size.Width, Size.Height);
}
public Png AsPng(TextureChannel channel, IPalette pal)
@@ -136,8 +146,7 @@ namespace OpenRA.Graphics
public void Dispose()
{
if (texture != null)
texture.Dispose();
texture?.Dispose();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -36,6 +36,7 @@ namespace OpenRA.Graphics
public readonly SheetType Type;
readonly List<Sheet> sheets = new List<Sheet>();
readonly Func<Sheet> allocateSheet;
readonly int margin;
Sheet current;
TextureChannel channel;
@@ -47,24 +48,35 @@ namespace OpenRA.Graphics
return new Sheet(type, new Size(sheetSize, sheetSize));
}
public static SheetType FrameTypeToSheetType(SpriteFrameType t)
{
switch (t)
{
case SpriteFrameType.Indexed: return SheetType.Indexed;
case SpriteFrameType.BGRA: return SheetType.BGRA;
default: throw new NotImplementedException("Unknown SpriteFrameType {0}".F(t));
}
}
public SheetBuilder(SheetType t)
: this(t, Game.Settings.Graphics.SheetSize) { }
public SheetBuilder(SheetType t, int sheetSize)
: this(t, () => AllocateSheet(t, sheetSize)) { }
public SheetBuilder(SheetType t, int sheetSize, int margin = 1)
: this(t, () => AllocateSheet(t, sheetSize), margin) { }
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet, int margin = 1)
{
channel = t == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
Type = t;
current = allocateSheet();
sheets.Add(current);
this.allocateSheet = allocateSheet;
this.margin = margin;
}
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, 0, frame.Offset); }
public Sprite Add(byte[] src, Size size) { return Add(src, size, 0, float3.Zero); }
public Sprite Add(byte[] src, Size size, float zRamp, float3 spriteOffset)
public Sprite Add(byte[] src, Size size, float zRamp, in float3 spriteOffset)
{
// Don't bother allocating empty sprites
if (size.Width == 0 || size.Height == 0)
@@ -76,9 +88,9 @@ namespace OpenRA.Graphics
return rect;
}
public Sprite Add(Png src)
public Sprite Add(Png src, float scale = 1f)
{
var rect = Allocate(new Size(src.Width, src.Height));
var rect = Allocate(new Size(src.Width, src.Height), scale);
Util.FastCopyIntoSprite(rect, src);
current.CommitBufferedData();
return rect;
@@ -102,19 +114,19 @@ namespace OpenRA.Graphics
return (TextureChannel)nextChannel;
}
public Sprite Allocate(Size imageSize) { return Allocate(imageSize, 0, float3.Zero); }
public Sprite Allocate(Size imageSize, float zRamp, float3 spriteOffset)
public Sprite Allocate(Size imageSize, float scale = 1f) { return Allocate(imageSize, 0, float3.Zero, scale); }
public Sprite Allocate(Size imageSize, float zRamp, in float3 spriteOffset, float scale = 1f)
{
if (imageSize.Width + p.X > current.Size.Width)
if (imageSize.Width + p.X + margin > current.Size.Width)
{
p = new int2(0, p.Y + rowHeight);
p = new int2(0, p.Y + rowHeight + margin);
rowHeight = imageSize.Height;
}
if (imageSize.Height > rowHeight)
rowHeight = imageSize.Height;
if (p.Y + imageSize.Height > current.Size.Height)
if (p.Y + imageSize.Height + margin > current.Size.Height)
{
var next = NextChannel(channel);
if (next == null)
@@ -131,8 +143,8 @@ namespace OpenRA.Graphics
p = int2.Zero;
}
var rect = new Sprite(current, new Rectangle(p.X, p.Y, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha);
p += new int2(imageSize.Width, 0);
var rect = new Sprite(current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha, scale);
p += new int2(imageSize.Width + margin, 0);
return rect;
}

View File

@@ -1,119 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public interface ICursor : IDisposable
{
void Render(Renderer renderer);
void SetCursor(string cursor);
void Tick();
void Lock();
void Unlock();
}
public sealed class SoftwareCursor : ICursor
{
readonly HardwarePalette palette = new HardwarePalette();
readonly Cache<string, PaletteReference> paletteReferences;
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
readonly CursorProvider cursorProvider;
readonly SheetBuilder sheetBuilder;
bool isLocked = false;
int2 lockedPosition;
public SoftwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var p in cursorProvider.Palettes)
palette.AddPalette(p.Key, p.Value, false);
palette.Initialize();
sheetBuilder = new SheetBuilder(SheetType.Indexed);
foreach (var kv in cursorProvider.Cursors)
{
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
sprites.Add(kv.Key, s);
}
sheetBuilder.Current.ReleaseBuffer();
Game.Renderer.Window.SetHardwareCursor(null);
}
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal, palette);
}
string cursorName;
public void SetCursor(string cursor)
{
cursorName = cursor;
}
float cursorFrame;
public void Tick()
{
cursorFrame += 0.5f;
}
public void Render(Renderer renderer)
{
if (cursorName == null)
return;
var cursorSequence = cursorProvider.GetCursorSequence(cursorName);
var cursorSprite = sprites[cursorName][(int)cursorFrame % cursorSequence.Length];
var cursorSize = CursorProvider.CursorViewportZoomed ? 2.0f * cursorSprite.Size : cursorSprite.Size;
var cursorOffset = CursorProvider.CursorViewportZoomed ?
(2 * cursorSequence.Hotspot) + cursorSprite.Size.XY.ToInt2() :
cursorSequence.Hotspot + (0.5f * cursorSprite.Size.XY).ToInt2();
renderer.SetPalette(palette);
var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos;
renderer.SpriteRenderer.DrawSprite(cursorSprite,
mousePos - cursorOffset,
paletteReferences[cursorSequence.Palette],
cursorSize);
}
public void Lock()
{
Game.Renderer.Window.SetRelativeMouseMode(true);
lockedPosition = Viewport.LastMousePos;
isLocked = true;
}
public void Unlock()
{
Game.Renderer.Window.SetRelativeMouseMode(false);
isLocked = false;
}
public void Dispose()
{
palette.Dispose();
sheetBuilder.Dispose();
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -26,17 +26,17 @@ namespace OpenRA.Graphics
public readonly float3 FractionalOffset;
public readonly float Top, Left, Bottom, Right;
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
: this(sheet, bounds, 0, float2.Zero, channel) { }
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel, float scale = 1)
: this(sheet, bounds, 0, float2.Zero, channel, BlendMode.Alpha, scale) { }
public Sprite(Sheet sheet, Rectangle bounds, float zRamp, float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha)
public Sprite(Sheet sheet, Rectangle bounds, float zRamp, in float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha, float scale = 1f)
{
Sheet = sheet;
Bounds = bounds;
Offset = offset;
ZRamp = zRamp;
Channel = channel;
Size = new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
Size = scale * new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
BlendMode = blendMode;
FractionalOffset = Size.Z != 0 ? offset / Size :
new float3(offset.X / Size.X, offset.Y / Size.Y, 0);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -13,7 +13,6 @@ using System;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Widgets;
namespace OpenRA.Graphics
{
@@ -24,7 +23,9 @@ namespace OpenRA.Graphics
readonly SheetBuilder builder;
readonly Func<string, float> lineWidth;
readonly IFont font;
readonly Cache<Pair<char, Color>, GlyphInfo> glyphs;
readonly Cache<char, GlyphInfo> glyphs;
readonly Cache<(char C, int Radius), Sprite> contrastGlyphs;
readonly Cache<int, float[]> dilationElements;
float deviceScale;
@@ -38,15 +39,20 @@ namespace OpenRA.Graphics
this.builder = builder;
font = Game.Renderer.CreateFont(data);
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char, Color>.EqualityComparer);
glyphs = new Cache<char, GlyphInfo>(CreateGlyph);
contrastGlyphs = new Cache<(char, int), Sprite>(CreateContrastGlyph);
dilationElements = new Cache<int, float[]>(CreateCircularWeightMap);
// PERF: Cache these delegates for Measure calls.
Func<char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance;
Func<char, float> characterWidth = character => glyphs[character].Advance;
lineWidth = line => line.Sum(characterWidth) / deviceScale;
// Pre-cache small font sizes so glyphs are immediately available when we need them
if (size <= 24)
PrecacheColor(Color.White, name);
using (new PerfTimer("Precache {0} {1}px".F(name, size)))
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[n] == null)
throw new InvalidOperationException();
TopOffset = size - ascender;
}
@@ -55,14 +61,42 @@ namespace OpenRA.Graphics
{
deviceScale = scale;
glyphs.Clear();
contrastGlyphs.Clear();
}
void PrecacheColor(Color c, string name)
void DrawTextContrast(string text, float2 location, Color contrastColor, int contrastOffset)
{
using (new PerfTimer("PrecacheColor {0} {1}px {2}".F(name, size, c)))
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[Pair.New(n, c)] == null)
throw new InvalidOperationException();
// Offset from the baseline position to the top-left of the glyph for rendering
location += new float2(0, size);
// Calculate positions in screen pixel coordinates
var screenContrast = (int)(contrastOffset * deviceScale);
var screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
var contrastVector = new float2(screenContrast, screenContrast);
var tint = new float3(contrastColor.R / 255f, contrastColor.G / 255f, contrastColor.B / 255f);
foreach (var s in text)
{
if (s == '\n')
{
location += new float2(0, size);
screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
continue;
}
var g = glyphs[s];
// Convert screen coordinates back to UI coordinates for drawing
if (g.Sprite != null)
{
var contrastSprite = contrastGlyphs[(s, screenContrast)];
Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(contrastSprite,
(screen + g.Offset - contrastVector) / deviceScale,
contrastSprite.Size / deviceScale,
tint);
}
screen += new int2((int)(g.Advance + 0.5f), 0);
}
}
public void DrawText(string text, float2 location, Color c)
@@ -70,42 +104,46 @@ namespace OpenRA.Graphics
// Offset from the baseline position to the top-left of the glyph for rendering
location += new float2(0, size);
var p = location;
// Calculate positions in screen pixel coordinates
var screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
var tint = new float3(c.R / 255f, c.G / 255f, c.B / 255f);
foreach (var s in text)
{
if (s == '\n')
{
location += new float2(0, size);
p = location;
screen = new int2((int)(location.X * deviceScale + 0.5f), (int)(location.Y * deviceScale + 0.5f));
continue;
}
var g = glyphs[Pair.New(s, c)];
if (g.Sprite != null)
Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X * deviceScale + g.Offset.X, 0) / deviceScale,
p.Y + g.Offset.Y / deviceScale),
g.Sprite.Size / deviceScale);
var g = glyphs[s];
p += new float2(g.Advance / deviceScale, 0);
// Convert screen coordinates back to UI coordinates for drawing
if (g.Sprite != null)
Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(g.Sprite,
(screen + g.Offset).ToFloat2() / deviceScale,
g.Sprite.Size / deviceScale,
tint);
screen += new int2((int)(g.Advance + 0.5f), 0);
}
}
float3 Rotate(float3 v, float sina, float cosa, float2 offset)
float2 Rotate(float2 v, float sina, float cosa, float2 offset)
{
return new float3(
return new float2(
v.X * cosa - v.Y * sina + offset.X,
v.X * sina + v.Y * cosa + offset.Y,
0);
v.X * sina + v.Y * cosa + offset.Y);
}
public void DrawText(string text, float2 location, Color c, float angle)
{
// Offset from the baseline position to the top-left of the glyph for rendering
// All positions are calculated in UI coordinates
var offset = new float2(0, size);
var cosa = (float)Math.Cos(-angle);
var sina = (float)Math.Sin(-angle);
var tint = new float3(c.R / 255f, c.G / 255f, c.B / 255f);
var p = offset;
foreach (var s in text)
@@ -117,21 +155,29 @@ namespace OpenRA.Graphics
continue;
}
var g = glyphs[Pair.New(s, c)];
var g = glyphs[s];
if (g.Sprite != null)
{
var tl = new float3(
(int)Math.Round(p.X * deviceScale + g.Offset.X, 0) / deviceScale,
p.Y + g.Offset.Y / deviceScale, 0);
var br = tl + g.Sprite.Size / deviceScale;
var tr = new float3(br.X, tl.Y, 0);
var bl = new float3(tl.X, br.Y, 0);
var tl = new float2(
p.X + g.Offset.X / deviceScale,
p.Y + g.Offset.Y / deviceScale);
var br = tl + g.Sprite.Size.XY / deviceScale;
var tr = new float2(br.X, tl.Y);
var bl = new float2(tl.X, br.Y);
Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
Rotate(tl, sina, cosa, location),
Rotate(tr, sina, cosa, location),
Rotate(br, sina, cosa, location),
Rotate(bl, sina, cosa, location));
var ra = Rotate(tl, sina, cosa, location);
var rb = Rotate(tr, sina, cosa, location);
var rc = Rotate(br, sina, cosa, location);
var rd = Rotate(bl, sina, cosa, location);
// Offset rotated glyph to align the top-left corner with the screen pixel grid
var screenOffset = new float2((int)(ra.X * deviceScale + 0.5f), (int)(ra.Y * deviceScale + 0.5f)) / deviceScale - ra;
Game.Renderer.RgbaSpriteRenderer.DrawSpriteWithTint(g.Sprite,
ra + screenOffset,
rb + screenOffset,
rc + screenOffset,
rd + screenOffset,
tint);
}
p += new float2(g.Advance / deviceScale, 0);
@@ -141,12 +187,7 @@ namespace OpenRA.Graphics
public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset > 0)
{
DrawText(text, location + new float2(-offset / deviceScale, 0), bg);
DrawText(text, location + new float2(offset / deviceScale, 0), bg);
DrawText(text, location + new float2(0, -offset / deviceScale), bg);
DrawText(text, location + new float2(0, offset / deviceScale), bg);
}
DrawTextContrast(text, location, bg, offset);
DrawText(text, location, fg);
}
@@ -159,7 +200,12 @@ namespace OpenRA.Graphics
public void DrawTextWithShadow(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset != 0)
DrawText(text, location + new float2(offset, offset), bg);
{
// Shadow offsets are rounded to an integer number of screen pixels.
// This makes sure the shadow will be positioned consistently everywhere on the screen.
var screenOffset = (int)(offset * deviceScale) / deviceScale;
DrawText(text, location + new float2(screenOffset, screenOffset), bg);
}
DrawText(text, location, fg);
}
@@ -172,7 +218,12 @@ namespace OpenRA.Graphics
public void DrawTextWithShadow(string text, float2 location, Color fg, Color bg, int offset, float angle)
{
if (offset != 0)
DrawText(text, location + new float2(offset, offset), bg, angle);
{
// Shadow offsets are rounded to an integer number of screen pixels.
// This makes sure the shadow will be positioned consistently everywhere on the screen.
var screenOffset = (int)(offset * deviceScale) / deviceScale;
DrawText(text, location + new float2(screenOffset, screenOffset), bg, angle);
}
DrawText(text, location, fg, angle);
}
@@ -188,13 +239,20 @@ namespace OpenRA.Graphics
return new int2(0, size);
var lines = text.Split('\n');
return new int2((int)Math.Ceiling(lines.Max(lineWidth)), lines.Length * size);
return new int2((int)Math.Ceiling(MaxLineWidth(lines, lineWidth)), lines.Length * size);
}
GlyphInfo CreateGlyph(Pair<char, Color> c)
static float MaxLineWidth(string[] lines, Func<string, float> lineWidth)
{
var glyph = font.CreateGlyph(c.First, size, deviceScale);
var maxWidth = 0f;
foreach (var line in lines)
maxWidth = Math.Max(maxWidth, lineWidth(line));
return maxWidth;
}
GlyphInfo CreateGlyph(char c)
{
var glyph = font.CreateGlyph(c, size, deviceScale);
if (glyph.Data == null)
{
return new GlyphInfo
@@ -224,12 +282,10 @@ namespace OpenRA.Graphics
if (p != 0)
{
var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left);
var pmc = Util.PremultiplyAlpha(Color.FromArgb(p, c.Second));
dest[q] = pmc.B;
dest[q + 1] = pmc.G;
dest[q + 2] = pmc.R;
dest[q + 3] = pmc.A;
dest[q] = p;
dest[q + 1] = p;
dest[q + 2] = p;
dest[q + 3] = p;
}
}
}
@@ -239,6 +295,123 @@ namespace OpenRA.Graphics
return g;
}
float[] CreateCircularWeightMap(int r)
{
// Create circular weight maps that are used by CreateContrastGlyph for
// both the structuring element and to weight the resulting pixel value.
// The output is a 2 * r + 1 square array giving the pixel intersection
// with a circle of radius (r + 0.5).
//
// Example output for r=1:
// 0.60 1.00 0.60
// 1.00 1.00 1.00
// 0.60 1.00 0.60
//
// Example output for r=3:
// 0.00 0.44 0.80 1.00 0.80 0.44 0.00
// 0.44 1.00 1.00 1.00 1.00 1.00 0.44
// 0.80 1.00 1.00 1.00 1.00 1.00 0.80
// 1.00 1.00 1.00 1.00 1.00 1.00 1.00
// 0.80 1.00 1.00 1.00 1.00 1.00 0.80
// 0.44 1.00 1.00 1.00 1.00 1.00 0.44
// 0.00 0.44 0.80 1.00 0.80 0.44 0.00
var stride = 2 * r + 1;
var elem = new float[stride * stride];
for (var j = 0; j <= 2 * r; j++)
{
for (var i = 0; i <= 2 * r; i++)
{
var di = i - r;
var dj = j - r;
// No intersection with circle
if (di * di + dj * dj > (r + 1) * (r + 1))
continue;
// Fully contained within circle
if (di * di + dj * dj < (r - 1) * (r - 1))
{
elem[j * stride + i] = 1;
continue;
}
// Approximate sub-pixel intersection using a 5x5 grid
for (var jj = 0; jj < 5; jj++)
{
for (var ii = 0; ii < 5; ii++)
{
var si = di - (float)Math.Sign(di) * ii / 5;
var sj = dj - (float)Math.Sign(dj) * jj / 5;
if (si * si + sj * sj <= r * r)
elem[j * stride + i] += 0.04f;
}
}
}
}
return elem;
}
Sprite CreateContrastGlyph((char C, int Radius) c)
{
var glyph = glyphs[c.C];
var r = c.Radius;
var s = builder.Allocate(new Size(glyph.Sprite.Bounds.Width + 2 * r, glyph.Sprite.Bounds.Height + 2 * r));
var dest = s.Sheet.GetData();
var destStride = s.Sheet.Size.Width * 4;
var glyphData = glyph.Sprite.Sheet.GetData();
var glyphStride = glyph.Sprite.Sheet.Size.Width * 4;
var glyphBounds = glyph.Sprite.Bounds;
var elem = dilationElements[r];
var elemStride = 2 * r + 1;
// Expand the glyph by applying the greyscale dilation operator to the source glyph's alpha channel
for (var j = 0; j < s.Size.Y; j++)
{
for (var i = 0; i < s.Size.X; i++)
{
// Apply the weight map to the source glyph and find the largest weighted alpha
var first = true;
var alpha = (byte)0;
for (var wj = 0; wj <= 2 * r; wj++)
{
for (var wi = 0; wi <= 2 * r; wi++)
{
// Ignore pixels that are outside the source glyph bounds
var ii = i + wi - 2 * r;
var jj = j + wj - 2 * r;
if (ii < 0 || ii >= glyphBounds.Width || jj < 0 || jj >= glyphBounds.Height)
continue;
// Weighted alpha for this pixel
var weighted = (byte)(elem[wj * elemStride + wi] * glyphData[glyphStride * (jj + glyphBounds.Top) + 4 * (ii + glyphBounds.Left) + 3]);
if (first || weighted > alpha)
{
alpha = weighted;
first = false;
}
}
}
if (alpha > 0)
{
var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left);
dest[q] = alpha;
dest[q + 1] = alpha;
dest[q + 2] = alpha;
dest[q + 3] = alpha;
}
}
}
s.Sheet.CommitBufferedData();
return s;
}
static Color GetContrastColor(Color fgColor, Color bgDark, Color bgLight)
{
return fgColor == Color.White || fgColor.GetBrightness() > 0.33 ? bgDark : bgLight;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -18,6 +18,8 @@ using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public enum SpriteFrameType { Indexed, BGRA }
public interface ISpriteLoader
{
bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata);
@@ -25,6 +27,8 @@ namespace OpenRA.Graphics
public interface ISpriteFrame
{
SpriteFrameType Type { get; }
/// <summary>
/// Size of the frame's `Data`.
/// </summary>
@@ -43,7 +47,7 @@ namespace OpenRA.Graphics
public class SpriteCache
{
public readonly SheetBuilder SheetBuilder;
public readonly Cache<SpriteFrameType, SheetBuilder> SheetBuilders;
readonly ISpriteLoader[] loaders;
readonly IReadOnlyFileSystem fileSystem;
@@ -51,9 +55,10 @@ namespace OpenRA.Graphics
readonly Dictionary<string, ISpriteFrame[]> unloadedFrames = new Dictionary<string, ISpriteFrame[]>();
readonly Dictionary<string, TypeDictionary> metadata = new Dictionary<string, TypeDictionary>();
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
{
SheetBuilder = sheetBuilder;
SheetBuilders = new Cache<SpriteFrameType, SheetBuilder>(t => new SheetBuilder(SheetBuilder.FrameTypeToSheetType(t)));
this.fileSystem = fileSystem;
this.loaders = loaders;
}
@@ -71,8 +76,7 @@ namespace OpenRA.Graphics
var allSprites = sprites.GetOrAdd(filename);
var sprite = allSprites.FirstOrDefault();
ISpriteFrame[] unloaded;
if (!unloadedFrames.TryGetValue(filename, out unloaded))
if (!unloadedFrames.TryGetValue(filename, out var unloaded))
unloaded = null;
// This is the first time that the file has been requested
@@ -80,8 +84,7 @@ namespace OpenRA.Graphics
// the loaded cache (initially empty)
if (sprite == null)
{
TypeDictionary fileMetadata = null;
unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out fileMetadata);
unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out var fileMetadata);
unloadedFrames[filename] = unloaded;
metadata[filename] = fileMetadata;
@@ -89,7 +92,7 @@ namespace OpenRA.Graphics
allSprites.Add(sprite);
}
// HACK: The sequency code relies on side-effects from getUsedFrames
// HACK: The sequence code relies on side-effects from getUsedFrames
var indices = getUsedFrames != null ? getUsedFrames(sprite.Length) :
Enumerable.Range(0, sprite.Length);
@@ -100,7 +103,7 @@ namespace OpenRA.Graphics
{
if (unloaded[i] != null)
{
sprite[i] = SheetBuilder.Add(unloaded[i]);
sprite[i] = SheetBuilders[unloaded[i].Type].Add(unloaded[i]);
unloaded[i] = null;
}
}
@@ -120,8 +123,7 @@ namespace OpenRA.Graphics
/// </summary>
public TypeDictionary FrameMetadata(string filename)
{
TypeDictionary fileMetadata;
if (!metadata.TryGetValue(filename, out fileMetadata))
if (!metadata.TryGetValue(filename, out var fileMetadata))
{
FrameLoader.GetFrames(fileSystem, filename, loaders, out fileMetadata);
metadata[filename] = fileMetadata;
@@ -137,8 +139,7 @@ namespace OpenRA.Graphics
public FrameCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
{
TypeDictionary metadata;
frames = new Cache<string, ISpriteFrame[]>(filename => FrameLoader.GetFrames(fileSystem, filename, loaders, out metadata));
frames = new Cache<string, ISpriteFrame[]>(filename => FrameLoader.GetFrames(fileSystem, filename, loaders, out _));
}
public ISpriteFrame[] this[string filename] { get { return frames[filename]; } }
@@ -160,11 +161,10 @@ namespace OpenRA.Graphics
public static ISpriteFrame[] GetFrames(Stream stream, ISpriteLoader[] loaders, out TypeDictionary metadata)
{
ISpriteFrame[] frames;
metadata = null;
foreach (var loader in loaders)
if (loader.TryParseSprite(stream, out frames, out metadata))
if (loader.TryParseSprite(stream, out var frames, out metadata))
return frames;
return null;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -14,7 +14,7 @@ using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public struct SpriteRenderable : IRenderable, IFinalizedRenderable
public struct SpriteRenderable : IRenderable, ITintableRenderable, IFinalizedRenderable
{
public static readonly IEnumerable<IRenderable> None = new IRenderable[0];
@@ -24,9 +24,17 @@ namespace OpenRA.Graphics
readonly int zOffset;
readonly PaletteReference palette;
readonly float scale;
readonly float3 tint;
readonly bool isDecoration;
readonly bool ignoreWorldTint;
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, bool isDecoration)
: this(sprite, pos, offset, zOffset, palette, scale, float3.Ones, isDecoration, false) { }
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, bool isDecoration, bool ignoreWorldTint)
: this(sprite, pos, offset, zOffset, palette, scale, float3.Ones, isDecoration, ignoreWorldTint) { }
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float3 tint, bool isDecoration, bool ignoreWorldTint)
{
this.sprite = sprite;
this.pos = pos;
@@ -34,7 +42,9 @@ namespace OpenRA.Graphics
this.zOffset = zOffset;
this.palette = palette;
this.scale = scale;
this.tint = tint;
this.isDecoration = isDecoration;
this.ignoreWorldTint = ignoreWorldTint;
}
public WPos Pos { get { return pos + offset; } }
@@ -43,10 +53,12 @@ namespace OpenRA.Graphics
public int ZOffset { get { return zOffset; } }
public bool IsDecoration { get { return isDecoration; } }
public IRenderable WithPalette(PaletteReference newPalette) { return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, isDecoration); }
public IRenderable WithZOffset(int newOffset) { return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, isDecoration); }
public IRenderable OffsetBy(WVec vec) { return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, isDecoration); }
public IRenderable AsDecoration() { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, true); }
public IRenderable WithPalette(PaletteReference newPalette) { return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, tint, isDecoration, ignoreWorldTint); }
public IRenderable WithZOffset(int newOffset) { return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, tint, isDecoration, ignoreWorldTint); }
public IRenderable OffsetBy(WVec vec) { return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, tint, isDecoration, ignoreWorldTint); }
public IRenderable AsDecoration() { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, tint, true, ignoreWorldTint); }
public IRenderable WithTint(in float3 newTint) { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, newTint, isDecoration, ignoreWorldTint); }
float3 ScreenPosition(WorldRenderer wr)
{
@@ -59,13 +71,25 @@ namespace OpenRA.Graphics
public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
public void Render(WorldRenderer wr)
{
Game.Renderer.WorldSpriteRenderer.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size);
var wsr = Game.Renderer.WorldSpriteRenderer;
if (ignoreWorldTint)
wsr.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size);
else
{
var t = tint;
if (wr.TerrainLighting != null)
t *= wr.TerrainLighting.TintAt(pos);
wsr.DrawSpriteWithTint(sprite, ScreenPosition(wr), palette, scale * sprite.Size, t);
}
}
public void RenderDebugGeometry(WorldRenderer wr)
{
var screenOffset = ScreenPosition(wr) + sprite.Offset;
Game.Renderer.WorldRgbaColorRenderer.DrawRect(screenOffset, screenOffset + sprite.Size, 1 / wr.Viewport.Zoom, Color.Red);
var pos = ScreenPosition(wr) + sprite.Offset;
var tl = wr.Viewport.WorldToViewPx(pos);
var br = wr.Viewport.WorldToViewPx(pos + sprite.Size);
Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.Red);
}
public Rectangle ScreenBounds(WorldRenderer wr)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -10,17 +10,21 @@
#endregion
using System;
using System.Linq;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public class SpriteRenderer : Renderer.IBatchRenderer
{
const int SheetCount = 7;
static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => "Texture{0}".F(i));
readonly Renderer renderer;
readonly IShader shader;
readonly Vertex[] vertices;
readonly Sheet[] sheets = new Sheet[7];
readonly Sheet[] sheets = new Sheet[SheetCount];
BlendMode currentBlend = BlendMode.Alpha;
int nv = 0;
@@ -39,7 +43,7 @@ namespace OpenRA.Graphics
{
for (var i = 0; i < ns; i++)
{
shader.SetTexture("Texture{0}".F(i), sheets[i].GetTexture());
shader.SetTexture(SheetIndexToTextureName[i], sheets[i].GetTexture());
sheets[i] = null;
}
@@ -104,27 +108,46 @@ namespace OpenRA.Graphics
return new int2(sheetIndex, secondarySheetIndex);
}
internal void DrawSprite(Sprite s, float3 location, float paletteTextureIndex, float3 size)
internal void DrawSprite(Sprite s, in float3 location, float paletteTextureIndex, in float3 size)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size);
Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size, float3.Ones);
nv += 6;
}
public void DrawSprite(Sprite s, float3 location, PaletteReference pal)
public void DrawSprite(Sprite s, in float3 location, PaletteReference pal)
{
DrawSprite(s, location, pal.TextureIndex, s.Size);
}
public void DrawSprite(Sprite s, float3 location, PaletteReference pal, float3 size)
public void DrawSprite(Sprite s, in float3 location, PaletteReference pal, float3 size)
{
DrawSprite(s, location, pal.TextureIndex, size);
}
public void DrawSprite(Sprite s, float3 a, float3 b, float3 c, float3 d)
public void DrawSprite(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, nv);
Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, float3.Ones, nv);
nv += 6;
}
internal void DrawSpriteWithTint(Sprite s, in float3 location, float paletteTextureIndex, in float3 size, in float3 tint)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, location + s.FractionalOffset * size, s, samplers, paletteTextureIndex, nv, size, tint);
nv += 6;
}
public void DrawSpriteWithTint(Sprite s, in float3 location, PaletteReference pal, in float3 size, in float3 tint)
{
DrawSpriteWithTint(s, location, pal.TextureIndex, size, tint);
}
public void DrawSpriteWithTint(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, a, b, c, d, s, samplers, 0, tint, nv);
nv += 6;
}
@@ -155,22 +178,27 @@ namespace OpenRA.Graphics
shader.SetTexture("Palette", palette);
}
public void SetViewportParams(Size screen, float depthScale, float depthOffset, float zoom, int2 scroll)
public void SetViewportParams(Size screen, float depthScale, float depthOffset, int2 scroll)
{
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
shader.SetVec("r1",
zoom * 2f / screen.Width,
-zoom * 2f / screen.Height,
-depthScale * zoom / screen.Height);
shader.SetVec("r2", -1, 1, 1 - depthOffset);
2f / screen.Width,
2f / screen.Height,
-depthScale / screen.Height);
shader.SetVec("r2", -1, -1, 1 - depthOffset);
// Texture index is sampled as a float, so convert to pixels then scale
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
shader.SetVec("DepthTextureScale", 128 * depthScale / screen.Height);
}
public void SetDepthPreviewEnabled(bool enabled)
{
shader.SetBool("EnableDepthPreview", enabled);
}
public void SetAntialiasingPixelsPerTexel(float pxPerTx)
{
shader.SetVec("AntialiasPixelsPerTexel", pxPerTx);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -46,12 +46,11 @@ namespace OpenRA.Graphics
if (!waypoints.Any())
return;
var sw = width / wr.Viewport.Zoom;
var first = wr.Screen3DPosition(waypoints.First());
var first = wr.Viewport.WorldToViewPx(wr.Screen3DPosition(waypoints.First()));
var a = first;
foreach (var b in waypoints.Skip(1).Select(pos => wr.Screen3DPosition(pos)))
foreach (var b in waypoints.Skip(1).Select(pos => wr.Viewport.WorldToViewPx(wr.Screen3DPosition(pos))))
{
Game.Renderer.WorldRgbaColorRenderer.DrawLine(a, b, sw, color);
Game.Renderer.RgbaColorRenderer.DrawLine(a, b, width, color);
DrawTargetMarker(wr, color, b, markerSize);
a = b;
}
@@ -59,13 +58,12 @@ namespace OpenRA.Graphics
DrawTargetMarker(wr, color, first);
}
public static void DrawTargetMarker(WorldRenderer wr, Color color, float3 location, int size = 1)
public static void DrawTargetMarker(WorldRenderer wr, Color color, int2 screenPos, int size = 1)
{
var sw = size / wr.Viewport.Zoom;
var offset = new float2(sw, sw);
var tl = location - offset;
var br = location + offset;
Game.Renderer.WorldRgbaColorRenderer.FillRect(tl, br, color);
var offset = new int2(size, size);
var tl = screenPos - offset;
var br = screenPos + offset;
Game.Renderer.RgbaColorRenderer.FillRect(tl, br, color);
}
public void RenderDebugGeometry(WorldRenderer wr) { }

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -18,6 +18,8 @@ namespace OpenRA.Graphics
{
public sealed class TerrainSpriteLayer : IDisposable
{
static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 };
public readonly Sheet Sheet;
public readonly BlendMode BlendMode;
@@ -25,6 +27,7 @@ namespace OpenRA.Graphics
readonly IVertexBuffer<Vertex> vertexBuffer;
readonly Vertex[] vertices;
readonly bool[] ignoreTint;
readonly HashSet<int> dirtyRows = new HashSet<int>();
readonly int rowStride;
readonly bool restrictToBounds;
@@ -50,6 +53,12 @@ namespace OpenRA.Graphics
emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
wr.PaletteInvalidated += UpdatePaletteIndices;
if (wr.TerrainLighting != null)
{
ignoreTint = new bool[rowStride * map.MapSize.Y];
wr.TerrainLighting.CellChanged += UpdateTint;
}
}
void UpdatePaletteIndices()
@@ -59,22 +68,76 @@ namespace OpenRA.Graphics
for (var i = 0; i < vertices.Length; i++)
{
var v = vertices[i];
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C);
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, v.R, v.G, v.B);
}
for (var row = 0; row < map.MapSize.Y; row++)
dirtyRows.Add(row);
}
public void Update(CPos cell, Sprite sprite)
public void Clear(CPos cell)
{
var xyz = sprite == null ? float3.Zero :
worldRenderer.Screen3DPosition(map.CenterOfCell(cell)) + sprite.Offset - 0.5f * sprite.Size;
Update(cell.ToMPos(map.Grid.Type), sprite, xyz);
Update(cell, null, true);
}
public void Update(MPos uv, Sprite sprite, float3 pos)
public void Update(CPos cell, ISpriteSequence sequence, int frame)
{
Update(cell, sequence.GetSprite(frame), sequence.IgnoreWorldTint);
}
public void Update(CPos cell, Sprite sprite, bool ignoreTint)
{
var xyz = float3.Zero;
if (sprite != null)
{
var cellOrigin = map.CenterOfCell(cell) - new WVec(0, 0, map.Grid.Ramps[map.Ramp[cell]].CenterHeightOffset);
xyz = worldRenderer.Screen3DPosition(cellOrigin) + sprite.Offset - 0.5f * sprite.Size;
}
Update(cell.ToMPos(map.Grid.Type), sprite, xyz, ignoreTint);
}
void UpdateTint(MPos uv)
{
var offset = rowStride * uv.V + 6 * uv.U;
if (ignoreTint[offset])
{
var noTint = float3.Ones;
for (var i = 0; i < 6; i++)
{
var v = vertices[offset + i];
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, noTint);
}
return;
}
// Allow the terrain tint to vary linearly across the cell to smooth out the staircase effect
// This is done by sampling the lighting the corners of the sprite, even though those pixels are
// transparent for isometric tiles
var tl = worldRenderer.TerrainLighting;
var pos = map.CenterOfCell(uv.ToCPos(map));
var step = map.Grid.Type == MapGridType.RectangularIsometric ? 724 : 512;
var weights = new[]
{
tl.TintAt(pos + new WVec(-step, -step, 0)),
tl.TintAt(pos + new WVec(step, -step, 0)),
tl.TintAt(pos + new WVec(step, step, 0)),
tl.TintAt(pos + new WVec(-step, step, 0))
};
// Apply tint directly to the underlying vertices
// This saves us from having to re-query the sprite information, which has not changed
for (var i = 0; i < 6; i++)
{
var v = vertices[offset + i];
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, weights[CornerVertexMap[i]]);
}
dirtyRows.Add(uv.V);
}
public void Update(MPos uv, Sprite sprite, in float3 pos, bool ignoreTint)
{
if (sprite != null)
{
@@ -92,7 +155,13 @@ namespace OpenRA.Graphics
return;
var offset = rowStride * uv.V + 6 * uv.U;
Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size);
Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size, float3.Ones);
if (worldRenderer.TerrainLighting != null)
{
this.ignoreTint[offset] = ignoreTint;
UpdateTint(uv);
}
dirtyRows.Add(uv.V);
}
@@ -114,15 +183,7 @@ namespace OpenRA.Graphics
continue;
var rowOffset = rowStride * row;
unsafe
{
// The compiler / language spec won't let us calculate a pointer to
// an offset inside a generic array T[], and so we are forced to
// calculate the start-of-row pointer here to pass in to SetData.
fixed (Vertex* vPtr = &vertices[0])
vertexBuffer.SetData((IntPtr)(vPtr + rowOffset), rowOffset, rowStride);
}
vertexBuffer.SetData(vertices, rowOffset, rowOffset, rowStride);
}
Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
@@ -135,6 +196,9 @@ namespace OpenRA.Graphics
public void Dispose()
{
worldRenderer.PaletteInvalidated -= UpdatePaletteIndices;
if (worldRenderer.TerrainLighting != null)
worldRenderer.TerrainLighting.CellChanged -= UpdateTint;
vertexBuffer.Dispose();
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -34,12 +35,12 @@ namespace OpenRA.Graphics
public sealed class Theater : IDisposable
{
readonly Dictionary<ushort, TheaterTemplate> templates = new Dictionary<ushort, TheaterTemplate>();
readonly SheetBuilder sheetBuilder;
SheetBuilder sheetBuilder;
readonly Sprite missingTile;
readonly MersenneTwister random;
TileSet tileset;
public Theater(TileSet tileset)
public Theater(TileSet tileset, Action<uint, string> onMissingImage = null)
{
this.tileset = tileset;
var allocated = false;
@@ -53,7 +54,6 @@ namespace OpenRA.Graphics
return new Sheet(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize));
};
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
random = new MersenneTwister();
var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);
@@ -63,9 +63,31 @@ namespace OpenRA.Graphics
foreach (var i in t.Value.Images)
{
var allFrames = frameCache[i];
ISpriteFrame[] allFrames;
if (onMissingImage != null)
{
try
{
allFrames = frameCache[i];
}
catch (FileNotFoundException)
{
onMissingImage(t.Key, i);
continue;
}
}
else
allFrames = frameCache[i];
var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length;
var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount);
var indices = t.Value.Frames != null ? t.Value.Frames : Exts.MakeArray(t.Value.TilesCount, j => j);
var start = indices.Min();
var end = indices.Max();
if (start < 0 || end >= frameCount)
throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist"
.F(t.Key, start, end, i, frameCount - 1));
variants.Add(indices.Select(j =>
{
var f = allFrames[j];
@@ -75,6 +97,15 @@ namespace OpenRA.Graphics
var zOffset = tile != null ? -tile.ZOffset : 0;
var zRamp = tile != null ? tile.ZRamp : 1f;
var offset = new float3(f.Offset, zOffset);
var type = SheetBuilder.FrameTypeToSheetType(f.Type);
// Defer SheetBuilder creation until we know what type of frames we are loading!
// TODO: Support mixed indexed and BGRA frames
if (sheetBuilder == null)
sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate);
else if (type != sheetBuilder.Type)
throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA.");
var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
Util.FastCopyIntoChannel(s, f.Data);
@@ -98,19 +129,26 @@ namespace OpenRA.Graphics
if (tileset.IgnoreTileSpriteOffsets)
allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode));
if (onMissingImage != null && !variants.Any())
continue;
templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length));
}
// 1x1px transparent tile
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1));
Sheet.ReleaseBuffer();
}
public bool HasTileSprite(TerrainTile r, int? variant = null)
{
return TileSprite(r, variant) != missingTile;
}
public Sprite TileSprite(TerrainTile r, int? variant = null)
{
TheaterTemplate template;
if (!templates.TryGetValue(r.Type, out template))
if (!templates.TryGetValue(r.Type, out var template))
return missingTile;
if (r.Index >= template.Stride)
@@ -130,10 +168,7 @@ namespace OpenRA.Graphics
for (var x = 0; x < template.Size.X; x++)
{
var tile = new TerrainTile(template.Id, (byte)(i++));
var tileInfo = tileset.GetTileInfo(tile);
// Empty tile
if (tileInfo == null)
if (!tileset.TryGetTileInfo(tile, out var tileInfo))
continue;
var sprite = TileSprite(tile);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -20,15 +20,18 @@ namespace OpenRA.Graphics
// yes, our channel order is nuts.
static readonly int[] ChannelMasks = { 2, 1, 0, 3 };
public static void FastCreateQuad(Vertex[] vertices, float3 o, Sprite r, int2 samplers, float paletteTextureIndex, int nv, float3 size)
public static void FastCreateQuad(Vertex[] vertices, in float3 o, Sprite r, int2 samplers, float paletteTextureIndex, int nv, in float3 size, in float3 tint)
{
var b = new float3(o.X + size.X, o.Y, o.Z);
var c = new float3(o.X + size.X, o.Y + size.Y, o.Z + size.Z);
var d = new float3(o.X, o.Y + size.Y, o.Z + size.Z);
FastCreateQuad(vertices, o, b, c, d, r, samplers, paletteTextureIndex, nv);
FastCreateQuad(vertices, o, b, c, d, r, samplers, paletteTextureIndex, tint, nv);
}
public static void FastCreateQuad(Vertex[] vertices, float3 a, float3 b, float3 c, float3 d, Sprite r, int2 samplers, float paletteTextureIndex, int nv)
public static void FastCreateQuad(Vertex[] vertices,
in float3 a, in float3 b, in float3 c, in float3 d,
Sprite r, int2 samplers, float paletteTextureIndex,
in float3 tint, int nv)
{
float sl = 0;
float st = 0;
@@ -51,33 +54,66 @@ namespace OpenRA.Graphics
}
var fAttribC = (float)attribC;
vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC);
vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC);
vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC);
vertices[nv + 3] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC);
vertices[nv + 4] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC);
vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC);
vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint);
vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC, tint);
vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint);
vertices[nv + 3] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint);
vertices[nv + 4] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC, tint);
vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint);
}
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var data = dest.Sheet.GetData();
var srcStride = dest.Bounds.Width;
var destStride = dest.Sheet.Size.Width * 4;
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
var destSkip = destStride - 4 * srcStride;
var destData = dest.Sheet.GetData();
var width = dest.Bounds.Width;
var height = dest.Bounds.Height;
var srcOffset = 0;
for (var j = 0; j < height; j++)
if (dest.Channel == TextureChannel.RGBA)
{
for (var i = 0; i < srcStride; i++, srcOffset++)
var destStride = dest.Sheet.Size.Width;
unsafe
{
data[destOffset] = src[srcOffset];
destOffset += 4;
}
// Cast the data to an int array so we can copy the src data directly
fixed (byte* bd = &destData[0])
{
var data = (int*)bd;
var x = dest.Bounds.Left;
var y = dest.Bounds.Top;
destOffset += destSkip;
var k = 0;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++)
{
var r = src[k++];
var g = src[k++];
var b = src[k++];
var a = src[k++];
var cc = Color.FromArgb(a, r, g, b);
data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
}
}
}
}
}
else
{
var destStride = dest.Sheet.Size.Width * 4;
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
var destSkip = destStride - 4 * width;
var srcOffset = 0;
for (var j = 0; j < height; j++)
{
for (var i = 0; i < width; i++, srcOffset++)
{
destData[destOffset] = src[srcOffset];
destOffset += 4;
}
destOffset += destSkip;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -16,17 +16,34 @@ namespace OpenRA.Graphics
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public readonly float X, Y, Z, S, T, U, V, P, C;
// 3d position
public readonly float X, Y, Z;
public Vertex(float3 xyz, float s, float t, float u, float v, float p, float c)
: this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c) { }
// Primary and secondary texture coordinates or RGBA color
public readonly float S, T, U, V;
public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c)
// Palette and channel flags
public readonly float P, C;
// Color tint
public readonly float R, G, B;
public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c)
: this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, float3.Ones) { }
public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c, in float3 tint)
: this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z) { }
public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, in float3 tint)
: this(x, y, z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z) { }
public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, float r, float g, float b)
{
X = x; Y = y; Z = z;
S = s; T = t;
U = u; V = v;
P = p; C = c;
R = r; G = g; B = b;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -19,6 +19,11 @@ namespace OpenRA.Graphics
[Flags]
public enum ScrollDirection { None = 0, Up = 1, Left = 2, Down = 4, Right = 8 }
public interface INotifyViewportZoomExtentsChanged
{
void ViewportZoomExtentsChanged(float minZoom, float maxZoom);
}
public static class ViewportExts
{
public static bool Includes(this ScrollDirection d, ScrollDirection s)
@@ -36,6 +41,8 @@ namespace OpenRA.Graphics
public class Viewport
{
readonly WorldRenderer worldRenderer;
readonly WorldViewportSizes viewportSizes;
readonly GraphicSettings graphicSettings;
// Map bounds (world-px)
readonly Rectangle mapBounds;
@@ -46,6 +53,7 @@ namespace OpenRA.Graphics
public WPos CenterPosition { get { return worldRenderer.ProjectedPosition(CenterLocation); } }
public Rectangle Rectangle { get { return new Rectangle(TopLeft, new Size(viewportSize.X, viewportSize.Y)); } }
public int2 TopLeft { get { return CenterLocation - viewportSize / 2; } }
public int2 BottomRight { get { return CenterLocation + viewportSize / 2; } }
int2 viewportSize;
@@ -54,14 +62,16 @@ namespace OpenRA.Graphics
ProjectedCellRegion allCells;
bool allCellsDirty = true;
readonly float[] availableZoomSteps = new[] { 2f, 1f, 0.5f, 0.25f };
WorldViewport lastViewportDistance;
float zoom = 1f;
float minZoom = 1f;
float maxZoom = 2f;
public float[] AvailableZoomSteps
{
get { return availableZoomSteps; }
}
bool unlockMinZoom;
float unlockedMinZoomScale;
float unlockedMinZoom = 1f;
public float Zoom
{
@@ -70,16 +80,47 @@ namespace OpenRA.Graphics
return zoom;
}
set
private set
{
var newValue = ClosestTo(AvailableZoomSteps, value);
zoom = newValue;
viewportSize = (1f / zoom * new float2(Game.Renderer.Resolution)).ToInt2();
zoom = value;
viewportSize = (1f / zoom * new float2(Game.Renderer.NativeResolution)).ToInt2();
cellsDirty = true;
allCellsDirty = true;
}
}
public float MinZoom { get { return minZoom; } }
public void AdjustZoom(float dz)
{
// Exponential ensures that equal positive and negative steps have the same effect
Zoom = (zoom * (float)Math.Exp(dz)).Clamp(unlockMinZoom ? unlockedMinZoom : minZoom, maxZoom);
}
public void AdjustZoom(float dz, int2 center)
{
var oldCenter = worldRenderer.Viewport.ViewToWorldPx(center);
AdjustZoom(dz);
var newCenter = worldRenderer.Viewport.ViewToWorldPx(center);
CenterLocation += oldCenter - newCenter;
}
public void ToggleZoom()
{
// Unlocked zooms always reset to the default zoom
if (zoom < minZoom)
Zoom = minZoom;
else
Zoom = zoom > minZoom ? minZoom : maxZoom;
}
public void UnlockMinimumZoom(float scale)
{
unlockMinZoom = true;
unlockedMinZoomScale = scale;
UpdateViewportZooms(false);
}
public static long LastMoveRunTime = 0;
public static int2 LastMousePos;
@@ -119,6 +160,8 @@ namespace OpenRA.Graphics
{
worldRenderer = wr;
var grid = Game.ModData.Manifest.Get<MapGrid>();
viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>();
graphicSettings = Game.Settings.Graphics;
// Calculate map bounds in world-px
if (wr.World.Type == WorldType.Editor)
@@ -140,8 +183,78 @@ namespace OpenRA.Graphics
CenterLocation = (tl + br) / 2;
}
Zoom = Game.Settings.Graphics.PixelDouble ? 2 : 1;
tileSize = grid.TileSize;
UpdateViewportZooms();
}
public void Tick()
{
if (lastViewportDistance != graphicSettings.ViewportDistance)
UpdateViewportZooms();
}
float CalculateMinimumZoom(float minHeight, float maxHeight)
{
var h = Game.Renderer.NativeResolution.Height;
// Check the easy case: the native resolution is within the maximum limit
// Also catches the case where the user may force a resolution smaller than the minimum window size
if (h <= maxHeight)
return 1;
// Find a clean fraction that brings us within the desired range to reduce aliasing
var step = 1f;
while (true)
{
var testZoom = 1f;
while (true)
{
var nextZoom = testZoom + step;
if (h < minHeight * nextZoom)
break;
testZoom = nextZoom;
}
if (h < maxHeight * testZoom)
return testZoom;
step /= 2;
}
}
void UpdateViewportZooms(bool resetCurrentZoom = true)
{
lastViewportDistance = graphicSettings.ViewportDistance;
var vd = graphicSettings.ViewportDistance;
if (viewportSizes.AllowNativeZoom && vd == WorldViewport.Native)
minZoom = 1;
else
{
var range = viewportSizes.GetSizeRange(vd);
minZoom = CalculateMinimumZoom(range.X, range.Y);
}
maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * 1f / viewportSizes.MaxZoomWindowHeight);
if (unlockMinZoom)
{
// Specators and the map editor support zooming out by an extra factor of two.
// TODO: Allow zooming out until the full map is visible
// We need to improve our viewport scroll handling to center the map as we zoom out
// before this will work well enough to enable
unlockedMinZoom = minZoom * unlockedMinZoomScale;
}
if (resetCurrentZoom)
Zoom = minZoom;
else
Zoom = Zoom.Clamp(minZoom, maxZoom);
foreach (var t in worldRenderer.World.WorldActor.TraitsImplementing<INotifyViewportZoomExtentsChanged>())
t.ViewportZoomExtentsChanged(minZoom, maxZoom);
}
public CPos ViewToWorld(int2 view)
@@ -149,7 +262,6 @@ namespace OpenRA.Graphics
var world = worldRenderer.Viewport.ViewToWorldPx(view);
var map = worldRenderer.World.Map;
var candidates = CandidateMouseoverCells(world).ToList();
var tileSet = worldRenderer.World.Map.Rules.TileSet;
foreach (var uv in candidates)
{
@@ -158,18 +270,9 @@ namespace OpenRA.Graphics
var s = worldRenderer.ScreenPxPosition(p);
if (Math.Abs(s.X - world.X) <= tileSize.Width && Math.Abs(s.Y - world.Y) <= tileSize.Height)
{
var ramp = 0;
if (map.Contains(uv))
{
var ti = tileSet.GetTileInfo(map.Tiles[uv]);
if (ti != null)
ramp = ti.RampType;
}
var corners = map.Grid.CellCorners[ramp];
var pos = map.CenterOfCell(uv.ToCPos(map));
var screen = corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray();
var ramp = map.Grid.Ramps[map.Ramp.Contains(uv) ? map.Ramp[uv] : 0];
var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, ramp.CenterHeightOffset);
var screen = ramp.Corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray();
if (screen.PolygonContains(world))
return uv.ToCPos(map);
}
@@ -179,7 +282,7 @@ namespace OpenRA.Graphics
// Try and find the closest cell
if (candidates.Count > 0)
{
return candidates.OrderBy(uv =>
return candidates.MinBy(uv =>
{
var p = map.CenterOfCell(uv.ToCPos(map.Grid.Type));
var s = worldRenderer.ScreenPxPosition(p);
@@ -187,7 +290,7 @@ namespace OpenRA.Graphics
var dy = Math.Abs(s.Y - world.Y);
return dx * dx + dy * dy;
}).First().ToCPos(map);
}).ToCPos(map);
}
// Something is very wrong, but lets return something that isn't completely bogus and hope the caller can recover
@@ -209,8 +312,9 @@ namespace OpenRA.Graphics
yield return new MPos(u, v);
}
public int2 ViewToWorldPx(int2 view) { return (1f / Zoom * view.ToFloat2()).ToInt2() + TopLeft; }
public int2 WorldToViewPx(int2 world) { return (Zoom * (world - TopLeft).ToFloat2()).ToInt2(); }
public int2 ViewToWorldPx(int2 view) { return (graphicSettings.UIScale / Zoom * view.ToFloat2()).ToInt2() + TopLeft; }
public int2 WorldToViewPx(int2 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).ToFloat2()).ToInt2(); }
public int2 WorldToViewPx(in float3 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).XY).ToInt2(); }
public void Center(IEnumerable<Actor> actors)
{
@@ -239,7 +343,6 @@ namespace OpenRA.Graphics
}
// Rectangle (in viewport coords) that contains things to be drawn
static readonly Rectangle ScreenClip = Rectangle.FromLTRB(0, 0, Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height);
public Rectangle GetScissorBounds(bool insideBounds)
{
// Visible rectangle in world coordinates (expanded to the corners of the cells)
@@ -249,12 +352,12 @@ namespace OpenRA.Graphics
var cbr = map.CenterOfCell(((MPos)bounds.BottomRight).ToCPos(map)) + new WVec(512, 512, 0);
// Convert to screen coordinates
var tl = WorldToViewPx(worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z))).Clamp(ScreenClip);
var br = WorldToViewPx(worldRenderer.ScreenPxPosition(cbr - new WVec(0, 0, cbr.Z))).Clamp(ScreenClip);
var tl = worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z)) - TopLeft;
var br = worldRenderer.ScreenPxPosition(cbr - new WVec(0, 0, cbr.Z)) - TopLeft;
// Add an extra one cell fudge in each direction for safety
return Rectangle.FromLTRB(tl.X - tileSize.Width, tl.Y - tileSize.Height,
br.X + tileSize.Width, br.Y + tileSize.Height);
// Add an extra half-cell fudge to avoid clipping isometric tiles
return Rectangle.FromLTRB(tl.X - tileSize.Width / 2, tl.Y - tileSize.Height / 2,
br.X + tileSize.Width / 2, br.Y + tileSize.Height / 2);
}
ProjectedCellRegion CalculateVisibleCells(bool insideBounds)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -20,7 +20,7 @@ namespace OpenRA.Graphics
{
public sealed class WorldRenderer : IDisposable
{
public static readonly Func<IRenderable, int> RenderableScreenZPositionComparisonKey =
public static readonly Func<IRenderable, int> RenderableZPositionComparisonKey =
r => ZPosition(r.Pos, r.ZOffset);
public readonly Size TileSize;
@@ -28,6 +28,7 @@ namespace OpenRA.Graphics
public readonly World World;
public readonly Theater Theater;
public Viewport Viewport { get; private set; }
public readonly ITerrainLighting TerrainLighting;
public event Action PaletteInvalidated = null;
@@ -39,6 +40,12 @@ namespace OpenRA.Graphics
readonly Func<string, PaletteReference> createPaletteReference;
readonly bool enableDepthBuffer;
readonly List<IFinalizedRenderable> preparedRenderables = new List<IFinalizedRenderable>();
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new List<IFinalizedRenderable>();
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new List<IFinalizedRenderable>();
readonly List<IRenderable> renderablesBuffer = new List<IRenderable>();
bool lastDepthPreviewEnabled;
internal WorldRenderer(ModData modData, World world)
@@ -62,6 +69,7 @@ namespace OpenRA.Graphics
palette.Initialize();
Theater = new Theater(world.Map.Rules.TileSet);
TerrainLighting = world.WorldActor.TraitOrDefault<ITerrainLighting>();
terrainRenderer = world.WorldActor.TraitOrDefault<IRenderTerrain>();
debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault<DebugVisualizations>());
@@ -89,8 +97,8 @@ namespace OpenRA.Graphics
var oldHeight = palette.Height;
palette.AddPalette(name, pal, allowModifiers);
if (oldHeight != palette.Height && PaletteInvalidated != null)
PaletteInvalidated();
if (oldHeight != palette.Height)
PaletteInvalidated?.Invoke();
}
}
@@ -103,61 +111,135 @@ namespace OpenRA.Graphics
palettes[name].Palette = pal;
}
List<IFinalizedRenderable> GenerateRenderables()
// PERF: Avoid LINQ.
void GenerateRenderables()
{
var actors = onScreenActors.Append(World.WorldActor);
if (World.RenderPlayer != null)
actors = actors.Append(World.RenderPlayer.PlayerActor);
foreach (var actor in onScreenActors)
renderablesBuffer.AddRange(actor.Render(this));
renderablesBuffer.AddRange(World.WorldActor.Render(this));
if (World.RenderPlayer != null)
renderablesBuffer.AddRange(World.RenderPlayer.PlayerActor.Render(this));
var worldRenderables = actors.SelectMany(a => a.Render(this));
if (World.OrderGenerator != null)
worldRenderables = worldRenderables.Concat(World.OrderGenerator.Render(this, World));
renderablesBuffer.AddRange(World.OrderGenerator.Render(this, World));
// Unpartitioned effects
worldRenderables = worldRenderables.Concat(World.UnpartitionedEffects.SelectMany(e => e.Render(this)));
foreach (var e in World.UnpartitionedEffects)
renderablesBuffer.AddRange(e.Render(this));
// Partitioned, currently on-screen effects
var effectRenderables = World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight);
worldRenderables = worldRenderables.Concat(effectRenderables.SelectMany(e => e.Render(this)));
foreach (var e in World.ScreenMap.RenderableEffectsInBox(Viewport.TopLeft, Viewport.BottomRight))
renderablesBuffer.AddRange(e.Render(this));
worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey);
// Renderables must be ordered using a stable sorting algorithm to avoid flickering artefacts
foreach (var renderable in renderablesBuffer.OrderBy(RenderableZPositionComparisonKey))
preparedRenderables.Add(renderable.PrepareRender(this));
Game.Renderer.WorldModelRenderer.BeginFrame();
var renderables = worldRenderables.Select(r => r.PrepareRender(this)).ToList();
Game.Renderer.WorldModelRenderer.EndFrame();
return renderables;
// PERF: Reuse collection to avoid allocations.
renderablesBuffer.Clear();
}
List<IFinalizedRenderable> GenerateOverlayRenderables()
// PERF: Avoid LINQ.
void GenerateOverlayRenderables()
{
var aboveShroud = World.ActorsWithTrait<IRenderAboveShroud>()
.Where(a => a.Actor.IsInWorld && !a.Actor.Disposed && (!a.Trait.SpatiallyPartitionable || onScreenActors.Contains(a.Actor)))
.SelectMany(a => a.Trait.RenderAboveShroud(a.Actor, this));
foreach (var a in World.ActorsWithTrait<IRenderAboveShroud>())
{
if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor)))
continue;
var aboveShroudSelected = World.Selection.Actors.Where(a => a.IsInWorld && !a.Disposed)
.SelectMany(a => a.TraitsImplementing<IRenderAboveShroudWhenSelected>()
.Where(t => !t.SpatiallyPartitionable || onScreenActors.Contains(a))
.SelectMany(t => t.RenderAboveShroud(a, this)));
foreach (var renderable in a.Trait.RenderAboveShroud(a.Actor, this))
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
}
var aboveShroudEffects = World.Effects.Select(e => e as IEffectAboveShroud)
.Where(e => e != null)
.SelectMany(e => e.RenderAboveShroud(this));
foreach (var a in World.Selection.Actors)
{
if (!a.IsInWorld || a.Disposed)
continue;
foreach (var t in a.TraitsImplementing<IRenderAboveShroudWhenSelected>())
{
if (t.SpatiallyPartitionable && !onScreenActors.Contains(a))
continue;
foreach (var renderable in t.RenderAboveShroud(a, this))
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
}
}
foreach (var e in World.Effects)
{
var ea = e as IEffectAboveShroud;
if (ea == null)
continue;
foreach (var renderable in ea.RenderAboveShroud(this))
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
}
var aboveShroudOrderGenerator = SpriteRenderable.None;
if (World.OrderGenerator != null)
aboveShroudOrderGenerator = World.OrderGenerator.RenderAboveShroud(this, World);
foreach (var renderable in World.OrderGenerator.RenderAboveShroud(this, World))
preparedOverlayRenderables.Add(renderable.PrepareRender(this));
}
var overlayRenderables = aboveShroud
.Concat(aboveShroudSelected)
.Concat(aboveShroudEffects)
.Concat(aboveShroudOrderGenerator);
// PERF: Avoid LINQ.
void GenerateAnnotationRenderables()
{
foreach (var a in World.ActorsWithTrait<IRenderAnnotations>())
{
if (!a.Actor.IsInWorld || a.Actor.Disposed || (a.Trait.SpatiallyPartitionable && !onScreenActors.Contains(a.Actor)))
continue;
Game.Renderer.WorldModelRenderer.BeginFrame();
var finalOverlayRenderables = overlayRenderables.Select(r => r.PrepareRender(this)).ToList();
Game.Renderer.WorldModelRenderer.EndFrame();
foreach (var renderAnnotation in a.Trait.RenderAnnotations(a.Actor, this))
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
}
return finalOverlayRenderables;
foreach (var a in World.Selection.Actors)
{
if (!a.IsInWorld || a.Disposed)
continue;
foreach (var t in a.TraitsImplementing<IRenderAnnotationsWhenSelected>())
{
if (t.SpatiallyPartitionable && !onScreenActors.Contains(a))
continue;
foreach (var renderAnnotation in t.RenderAnnotations(a, this))
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
}
}
foreach (var e in World.Effects)
{
var ea = e as IEffectAnnotation;
if (ea == null)
continue;
foreach (var renderAnnotation in ea.RenderAnnotation(this))
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
}
if (World.OrderGenerator != null)
foreach (var renderAnnotation in World.OrderGenerator.RenderAnnotations(this, World))
preparedAnnotationRenderables.Add(renderAnnotation.PrepareRender(this));
}
public void PrepareRenderables()
{
if (World.WorldActor.Disposed)
return;
RefreshPalette();
// PERF: Reuse collection to avoid allocations.
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
GenerateRenderables();
GenerateOverlayRenderables();
GenerateAnnotationRenderables();
onScreenActors.Clear();
}
public void Draw()
@@ -171,23 +253,18 @@ namespace OpenRA.Graphics
Game.Renderer.WorldSpriteRenderer.SetDepthPreviewEnabled(lastDepthPreviewEnabled);
}
RefreshPalette();
onScreenActors.UnionWith(World.ScreenMap.RenderableActorsInBox(Viewport.TopLeft, Viewport.BottomRight));
var renderables = GenerateRenderables();
var bounds = Viewport.GetScissorBounds(World.Type != WorldType.Editor);
Game.Renderer.EnableScissor(bounds);
if (enableDepthBuffer)
Game.Renderer.Context.EnableDepthBuffer();
if (terrainRenderer != null)
terrainRenderer.RenderTerrain(this, Viewport);
terrainRenderer?.RenderTerrain(this, Viewport);
Game.Renderer.Flush();
for (var i = 0; i < renderables.Count; i++)
renderables[i].Render(this);
for (var i = 0; i < preparedRenderables.Count; i++)
preparedRenderables[i].Render(this);
if (enableDepthBuffer)
Game.Renderer.ClearDepthBuffer();
@@ -196,56 +273,73 @@ namespace OpenRA.Graphics
if (a.Actor.IsInWorld && !a.Actor.Disposed)
a.Trait.RenderAboveWorld(a.Actor, this);
var renderShroud = World.RenderPlayer != null ? World.RenderPlayer.Shroud : null;
if (enableDepthBuffer)
Game.Renderer.ClearDepthBuffer();
foreach (var a in World.ActorsWithTrait<IRenderShroud>())
a.Trait.RenderShroud(renderShroud, this);
a.Trait.RenderShroud(this);
if (enableDepthBuffer)
Game.Renderer.Context.DisableDepthBuffer();
Game.Renderer.DisableScissor();
var finalOverlayRenderables = GenerateOverlayRenderables();
// HACK: Keep old grouping behaviour
var groupedOverlayRenderables = finalOverlayRenderables.GroupBy(prs => prs.GetType());
var groupedOverlayRenderables = preparedOverlayRenderables.GroupBy(prs => prs.GetType());
foreach (var g in groupedOverlayRenderables)
foreach (var r in g)
r.Render(this);
Game.Renderer.Flush();
}
public void DrawAnnotations()
{
Game.Renderer.EnableAntialiasingFilter();
for (var i = 0; i < preparedAnnotationRenderables.Count; i++)
preparedAnnotationRenderables[i].Render(this);
Game.Renderer.DisableAntialiasingFilter();
// Engine debugging overlays
if (debugVis.Value != null && debugVis.Value.RenderGeometry)
{
for (var i = 0; i < renderables.Count; i++)
renderables[i].RenderDebugGeometry(this);
for (var i = 0; i < preparedRenderables.Count; i++)
preparedRenderables[i].RenderDebugGeometry(this);
foreach (var g in groupedOverlayRenderables)
foreach (var r in g)
r.RenderDebugGeometry(this);
for (var i = 0; i < preparedOverlayRenderables.Count; i++)
preparedOverlayRenderables[i].RenderDebugGeometry(this);
for (var i = 0; i < preparedAnnotationRenderables.Count; i++)
preparedAnnotationRenderables[i].RenderDebugGeometry(this);
}
if (debugVis.Value != null && debugVis.Value.ScreenMap)
{
foreach (var r in World.ScreenMap.RenderBounds(World.RenderPlayer))
Game.Renderer.WorldRgbaColorRenderer.DrawRect(
new float3(r.Left, r.Top, r.Bottom),
new float3(r.Right, r.Bottom, r.Bottom),
1 / Viewport.Zoom, Color.MediumSpringGreen);
{
var tl = Viewport.WorldToViewPx(new float2(r.Left, r.Top));
var br = Viewport.WorldToViewPx(new float2(r.Right, r.Bottom));
Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.MediumSpringGreen);
}
foreach (var r in World.ScreenMap.MouseBounds(World.RenderPlayer))
Game.Renderer.WorldRgbaColorRenderer.DrawRect(
new float3(r.Left, r.Top, r.Bottom),
new float3(r.Right, r.Bottom, r.Bottom),
1 / Viewport.Zoom, Color.OrangeRed);
foreach (var b in World.ScreenMap.MouseBounds(World.RenderPlayer))
{
var points = new float2[b.Vertices.Length];
for (var index = 0; index < b.Vertices.Length; index++)
{
var vertex = b.Vertices[index];
points[index] = Viewport.WorldToViewPx(vertex).ToFloat2();
}
Game.Renderer.RgbaColorRenderer.DrawPolygon(points, 1, Color.OrangeRed);
}
}
Game.Renderer.Flush();
// PERF: Reuse collection to avoid allocations.
onScreenActors.Clear();
preparedRenderables.Clear();
preparedOverlayRenderables.Clear();
preparedAnnotationRenderables.Clear();
}
public void RefreshPalette()

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -20,6 +20,7 @@ namespace OpenRA
public readonly Hotkey Default = Hotkey.Invalid;
public readonly string Description = "";
public readonly HashSet<string> Types = new HashSet<string>();
public bool HasDuplicates { get; internal set; }
public HotkeyDefinition(string name, MiniYaml node)
{

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -38,6 +38,9 @@ namespace OpenRA
if (definitions.ContainsKey(kv.Key))
keys[kv.Key] = kv.Value;
}
foreach (var hd in definitions)
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
}
internal Func<Hotkey> GetHotkeyReference(string name)
@@ -47,8 +50,7 @@ namespace OpenRA
return () => keys[name];
// Try and parse as a hardcoded definition
Hotkey key;
if (!Hotkey.TryParse(name, out key))
if (!Hotkey.TryParse(name, out var key))
key = Hotkey.Invalid;
return () => key;
@@ -56,8 +58,7 @@ namespace OpenRA
public void Set(string name, Hotkey value)
{
HotkeyDefinition definition;
if (!definitions.TryGetValue(name, out definition))
if (!definitions.TryGetValue(name, out var definition))
return;
keys[name] = value;
@@ -65,6 +66,20 @@ namespace OpenRA
settings[name] = value;
else
settings.Remove(name);
var hadDuplicates = definition.HasDuplicates;
definition.HasDuplicates = GetFirstDuplicate(definition.Name, this[definition.Name].GetValue(), definition) != null;
if (hadDuplicates || definition.HasDuplicates)
{
foreach (var hd in definitions)
{
if (hd.Value == definition)
continue;
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
}
}
}
public HotkeyDefinition GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -9,9 +9,11 @@
*/
#endregion
using System;
namespace OpenRA
{
public struct Hotkey
public struct Hotkey : IEquatable<Hotkey>
{
public static Hotkey Invalid = new Hotkey(Keycode.UNKNOWN, Modifiers.None);
public bool IsValid()
@@ -30,11 +32,9 @@ namespace OpenRA
var parts = s.Split(' ');
Keycode key;
if (!Enum<Keycode>.TryParse(parts[0], true, out key))
if (!Enum<Keycode>.TryParse(parts[0], true, out var key))
{
int c;
if (!int.TryParse(parts[0], out c))
if (!int.TryParse(parts[0], out var c))
return false;
key = (Keycode)c;
}
@@ -74,6 +74,11 @@ namespace OpenRA
public override int GetHashCode() { return Key.GetHashCode() ^ Modifiers.GetHashCode(); }
public bool Equals(Hotkey other)
{
return other == this;
}
public override bool Equals(object obj)
{
var o = obj as Hotkey?;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -498,8 +498,7 @@ namespace OpenRA
public static string DisplayString(Keycode k)
{
string ret;
if (!KeyNames.TryGetValue(k, out ret))
if (!KeyNames.TryGetValue(k, out var ret))
return k.ToString();
return ret;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -14,7 +14,6 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Primitives;
@@ -26,22 +25,18 @@ namespace OpenRA
readonly Dictionary<string, Manifest> mods;
readonly SheetBuilder sheetBuilder;
readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>();
public readonly IReadOnlyDictionary<string, Sprite> Icons;
/// <summary>Initializes the collection of locally installed mods.</summary>
/// <param name="searchPaths">Filesystem paths to search for mod packages.</param>
/// <param name="explicitPaths">Filesystem paths to additional mod packages.</param>
public InstalledMods(IEnumerable<string> searchPaths, IEnumerable<string> explicitPaths)
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, 256);
Icons = new ReadOnlyDictionary<string, Sprite>(icons);
mods = GetInstalledMods(searchPaths, explicitPaths);
}
static IEnumerable<Pair<string, string>> GetCandidateMods(IEnumerable<string> searchPaths)
static IEnumerable<(string Id, string Path)> GetCandidateMods(IEnumerable<string> searchPaths)
{
var mods = new List<Pair<string, string>>();
var mods = new List<(string, string)>();
foreach (var path in searchPaths)
{
try
@@ -52,7 +47,7 @@ namespace OpenRA
var directory = new DirectoryInfo(resolved);
foreach (var subdir in directory.EnumerateDirectories())
mods.Add(Pair.New(subdir.Name, subdir.FullName));
mods.Add((subdir.Name, subdir.FullName));
}
catch (Exception e)
{
@@ -76,28 +71,14 @@ namespace OpenRA
package = new Folder(path);
if (package.Contains("mod.yaml"))
{
var manifest = new Manifest(id, package);
if (package.Contains("icon.png"))
{
using (var stream = package.GetStream("icon.png"))
if (stream != null)
icons[id] = sheetBuilder.Add(new Png(stream));
}
else if (!manifest.Metadata.Hidden)
Log.Write("debug", "Mod '{0}' is missing 'icon.png'.".F(path));
return manifest;
}
return new Manifest(id, package);
}
catch (Exception e)
{
Log.Write("debug", "Load mod '{0}': {1}".F(path, e));
}
if (package != null)
package.Dispose();
package?.Dispose();
return null;
}
@@ -106,13 +87,13 @@ namespace OpenRA
{
var ret = new Dictionary<string, Manifest>();
var candidates = GetCandidateMods(searchPaths)
.Concat(explicitPaths.Select(p => Pair.New(Path.GetFileNameWithoutExtension(p), p)));
.Concat(explicitPaths.Select(p => (Id: Path.GetFileNameWithoutExtension(p), Path: p)));
foreach (var pair in candidates)
{
var mod = LoadMod(pair.First, pair.Second);
var mod = LoadMod(pair.Id, pair.Path);
if (mod != null)
ret[pair.First] = mod;
ret[pair.Id] = mod;
}
return ret;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
@@ -80,8 +80,6 @@ namespace OpenRA
{
try
{
innerState = LinkState.Unlinked;
if (i.Error != null)
{
innerState = LinkState.ConnectionFailed;
@@ -100,6 +98,8 @@ namespace OpenRA
else
innerState = LinkState.Linked;
}
else
innerState = LinkState.Unlinked;
}
catch (Exception e)
{
@@ -108,8 +108,7 @@ namespace OpenRA
}
finally
{
if (onComplete != null)
onComplete();
onComplete?.Invoke();
}
};

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of

Some files were not shown because too many files have changed in this diff Show More