mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Compare commits
22 commits
5ef2a5c3f6
...
6b4ecbdc40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b4ecbdc40 | ||
|
|
149baf116b | ||
|
|
57f5b73458 | ||
|
|
518ed74496 | ||
|
|
4259c78150 | ||
|
|
71400e8045 | ||
|
|
43e7dbc6da | ||
|
|
2f2cbb96bf | ||
|
|
a4b580991b | ||
|
|
babe9e5c18 | ||
|
|
cbce748b8c | ||
|
|
1ab55e7f2e | ||
|
|
b4fe426963 | ||
|
|
8cb4f5e4a3 | ||
|
|
9388692a47 | ||
|
|
fa9584fdc0 | ||
|
|
7f4377c086 | ||
|
|
1034b55037 | ||
|
|
b1627f5158 | ||
|
|
917275d6cb | ||
|
|
50e1f51755 | ||
|
|
39b1311fac |
134 changed files with 867 additions and 872 deletions
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1c10d449ac14ca84e468309cfb7c360d694ac2d06dee03f76a32e33e6e2c99e4
|
||||
size 421569
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0eef7e19416045c7c2a5cc7c03ef90a2dff0f667c451cec538ea8aebedd6e042
|
||||
size 469669
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:546104d960caafa6d5b34202d5a61d41576e9063aa2b50427a8f24b20d49fd66
|
||||
size 449456
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:13042e6bbf40855741059c9ee3874f43832a805ca3361ab31b81f0c7f386ee1e
|
||||
size 497581
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4c9691682467622e4a52a1253a20b86ff0b89a9b31c2a12f9fce68e2735e4ebe
|
||||
size 436276
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4f8520c067e68a687dd15c9459e791f5737d6b7457142e58db7b5e86d80b848c
|
||||
size 532484
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f82c6568f4d5e5013e68122a6e042bad37a3098d19b9a9289faac3c08cde880d
|
||||
size 479929
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4563953d9d3f90318fd8526289206fbed2b9fa6c2accb06ac80b2d1983872169
|
||||
size 522691
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c09534c41b36b971e7408ab7613542af0b53f5a3d0b9b1f2a151fc8ff1839781
|
||||
size 457293
|
||||
3
binaries/data/mods/public/art/textures/ui/tips/relic.png
Normal file
3
binaries/data/mods/public/art/textures/ui/tips/relic.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f9660381b55c90597e32f893b88e5347050d83b3dfaf78b950f2bc3024e14afd
|
||||
size 443508
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:85512671818c8fd964c4b6224158480a21d00e4195d0ab6b36f1435151ec1e36
|
||||
size 450454
|
||||
|
|
@ -199,6 +199,7 @@
|
|||
{ "nick": "mattlott", "name": "Matt Lott" },
|
||||
{ "nick": "maveric", "name": "Anton Protko" },
|
||||
{ "nick": "mbusy", "name": "Maxime Busy" },
|
||||
{ "nick": "mehmedarslan", "name": "Mehmed Faheim Arslan/Sai Kaushik" },
|
||||
{ "nick": "Mentula" },
|
||||
{ "nick": "Micnasty", "name": "Travis Gorkin" },
|
||||
{ "name": "Mikołaj \"Bajter\" Korcz" },
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ class StructreePage extends ReferencePage
|
|||
this.CivHistory.caption = this.civData[this.activeCiv].History || "";
|
||||
|
||||
const templateLists = this.TemplateLister.getTemplateLists(this.activeCiv);
|
||||
this.TreeSection.draw(templateLists.structures, this.activeCiv);
|
||||
this.TrainerSection.draw(templateLists.units, this.activeCiv);
|
||||
this.TreeSection.draw(templateLists.structures, this.activeCiv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
ARSENAL
|
||||
Construct Siege Engines, train Champion Infantry Crossbowmen.
|
||||
Research Siege Engine technologies to improve unit capabilities.
|
||||
Garrison Siege Engines to regenerate their health.
|
||||
Available to all civilizations in City Phase.
|
||||
Available to Macedonians in Town Phase, giving early access to Bolt Shooters.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CORRAL
|
||||
Train animals for food.
|
||||
Garrison up to 8 animals to gain a food trickle.
|
||||
Each garrisoned animal adds its full food trickle.
|
||||
Research Stockbreeding to breed domestic animals faster.
|
||||
Available to all civilizations in Village Phase.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
COUNCIL CHAMBER
|
||||
Train Athenian Heroes and research special technologies.
|
||||
Garrison Heroes inside to regenerate their health.
|
||||
Available only to the Athenians.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
GREAT HALL
|
||||
Train Champion Axemen and Log Rams.
|
||||
Available only to the Germans in Town Phase.
|
||||
Use it to strengthen your army before City Phase.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
GYMNASIUM
|
||||
Train Champions, including Athenian Marines.
|
||||
Research Iphicratean Reforms to unlock Athenian Marines at Docks and Triremes.
|
||||
Available only to Athens.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
HOPLITE TRADITION
|
||||
Hoplites -25% training time, -50% promotion experience, and +10% health.
|
||||
Research it at the Civic Center in Town Phase.
|
||||
Available only to the Athenians and Spartans.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
LIBRARY
|
||||
Reduces structure costs by 15%.
|
||||
Reduces structure build time by 15%.
|
||||
Available to the Macedonians, Ptolemies and Seleucids.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
MILITARY COLONY
|
||||
Can be built only in own or neutral territory.
|
||||
Available only to the Ptolemies and Seleucids in Town Phase.
|
||||
Use it to extend your territory without building a full Civic Center.
|
||||
Trains civ-specific Mercenary units for expansion and frontier defense.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
REGICIDE
|
||||
Choose the "Regicide" victory condition in the game setup.
|
||||
You start the match with a Hero from your civilization.
|
||||
Defeat an opponent by killing their Hero.
|
||||
Garrison your Hero inside a structure for protection if "Hero Garrison" is enabled.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
RELICS
|
||||
Relics are catafalques that hold the remains of great leaders.
|
||||
Each Relic provides a military or economic aura bonus to its owner.
|
||||
Enable "Capture the Relic" in the game setup to win by controlling all Relics.
|
||||
Use "Relic Count" and "Relic Duration" to set how many Relics spawn and how long they must be held.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
TEMPLE OF ISIS
|
||||
Train Ptolemaic Heroes and Healers.
|
||||
Research healing technologies and special cult technologies.
|
||||
Research Serapis Cult for a metal trickle.
|
||||
Research Pharaonic Cult to improve hero health regeneration.
|
||||
Available only to the Ptolemies in City Phase.
|
||||
|
|
@ -49,6 +49,12 @@
|
|||
"civic_center.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "corral.txt",
|
||||
"imageFiles": [
|
||||
"corral.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "defense_tower.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -209,6 +215,12 @@
|
|||
"embassies.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "arsenal.txt",
|
||||
"imageFiles": [
|
||||
"arsenal.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "experience.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -228,6 +240,12 @@
|
|||
"formations.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "great_hall.txt",
|
||||
"imageFiles": [
|
||||
"great_hall.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "heroes.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -240,12 +258,24 @@
|
|||
"loot.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "library.txt",
|
||||
"imageFiles": [
|
||||
"library.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "map_flare.txt",
|
||||
"imageFiles": [
|
||||
"map_flare.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "military_colony.txt",
|
||||
"imageFiles": [
|
||||
"military_colony.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "pikemen.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -362,6 +392,12 @@
|
|||
"control_groups.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "council_chamber.txt",
|
||||
"imageFiles": [
|
||||
"council_chamber.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "default_formation.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -392,6 +428,18 @@
|
|||
"freehand_position.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "gymnasium.txt",
|
||||
"imageFiles": [
|
||||
"gymnasium.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "hoplite_tradition.txt",
|
||||
"imageFiles": [
|
||||
"hoplite_tradition.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "lighthouse.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -428,6 +476,18 @@
|
|||
"achaemenid_architecture.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "regicide.txt",
|
||||
"imageFiles": [
|
||||
"regicide.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "relic.txt",
|
||||
"imageFiles": [
|
||||
"relic.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "resource_lost.txt",
|
||||
"imageFiles": [
|
||||
|
|
@ -458,6 +518,12 @@
|
|||
"syntagma.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "temple_of_isis.txt",
|
||||
"imageFiles": [
|
||||
"temple_of_isis.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
"textFile": "whales.txt",
|
||||
"imageFiles": [
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ function determineAction(x, y, fromMiniMap)
|
|||
if (!entState)
|
||||
return undefined;
|
||||
|
||||
if (!selection.every(ownsEntity) &&
|
||||
if (!selection.every(ent => ownsEntity(ent) || isMutualAllyBuilding(ent)) &&
|
||||
!(g_SimState.players[g_ViewedPlayer] &&
|
||||
g_SimState.players[g_ViewedPlayer].controlsAll))
|
||||
return undefined;
|
||||
|
|
@ -318,6 +318,13 @@ function ownsEntity(ent)
|
|||
return entState && entState.player == g_ViewedPlayer;
|
||||
}
|
||||
|
||||
function isMutualAllyBuilding(ent)
|
||||
{
|
||||
const entState = GetEntityState(ent);
|
||||
return entState && entState.rallyPoint &&
|
||||
g_Players[entState.player]?.isMutualAlly[g_ViewedPlayer];
|
||||
}
|
||||
|
||||
function isAttackMovePressed()
|
||||
{
|
||||
return Engine.HotkeyIsPressed("session.attackmove") ||
|
||||
|
|
|
|||
|
|
@ -331,6 +331,8 @@ async function init(initData, hotloadData)
|
|||
resumeGame();
|
||||
});
|
||||
|
||||
g_DiplomacyColors.updateDisplayedPlayerColors();
|
||||
|
||||
const promise = Promise.race([new Promise((_, reject) =>
|
||||
{
|
||||
if (g_IsNetworked)
|
||||
|
|
|
|||
|
|
@ -1125,7 +1125,7 @@ var g_UnitActions =
|
|||
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "set-rallypoint",
|
||||
"entities": selection,
|
||||
"structures": selection,
|
||||
"x": position.x,
|
||||
"z": position.z,
|
||||
"data": action.data,
|
||||
|
|
@ -1355,7 +1355,7 @@ var g_UnitActions =
|
|||
{
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "unset-rallypoint",
|
||||
"entities": selection
|
||||
"structures": selection
|
||||
});
|
||||
|
||||
// Remove displayed rally point
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ export function BaseAI(settings)
|
|||
return;
|
||||
|
||||
this.player = settings.player;
|
||||
|
||||
// played turn, in case you don't want the AI to play every turn.
|
||||
this.turn = 0;
|
||||
}
|
||||
|
||||
/** Return a simple object (using no classes etc) that will be serialized into saved games */
|
||||
|
|
@ -23,7 +20,6 @@ BaseAI.prototype.Serialize = function()
|
|||
*/
|
||||
BaseAI.prototype.Deserialize = function(data, sharedScript)
|
||||
{
|
||||
this.isDeserialized = true;
|
||||
};
|
||||
|
||||
BaseAI.prototype.Init = function(state, playerID, sharedAI)
|
||||
|
|
@ -49,14 +45,7 @@ BaseAI.prototype.CustomInit = function()
|
|||
BaseAI.prototype.HandleMessage = function(state, playerID, sharedAI)
|
||||
{
|
||||
PlayerID = playerID;
|
||||
this.events = sharedAI.events;
|
||||
this.territoryMap = sharedAI.territoryMap;
|
||||
|
||||
if (this.isDeserialized)
|
||||
{
|
||||
this.Init(state, playerID, sharedAI);
|
||||
this.isDeserialized = false;
|
||||
}
|
||||
this.OnUpdate(sharedAI);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -996,13 +996,13 @@ export const Entity = Class({
|
|||
"setRallyPoint": function(target, command)
|
||||
{
|
||||
const data = { "command": command, "target": target.id() };
|
||||
Engine.PostCommand(PlayerID, { "type": "set-rallypoint", "entities": [this.id()], "x": target.position()[0], "z": target.position()[1], "data": data });
|
||||
Engine.PostCommand(PlayerID, { "type": "set-rallypoint", "structures": [this.id()], "x": target.position()[0], "z": target.position()[1], "data": data });
|
||||
return this;
|
||||
},
|
||||
|
||||
"unsetRallyPoint": function()
|
||||
{
|
||||
Engine.PostCommand(PlayerID, { "type": "unset-rallypoint", "entities": [this.id()] });
|
||||
Engine.PostCommand(PlayerID, { "type": "unset-rallypoint", "structures": [this.id()] });
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ export function PetraBot(settings)
|
|||
{
|
||||
BaseAI.call(this, settings);
|
||||
|
||||
// played turn, because Petra doesn't play every turn.
|
||||
this.turn = 0;
|
||||
this.playedTurn = 0;
|
||||
this.elapsedTime = 0;
|
||||
|
||||
|
|
@ -89,17 +91,20 @@ PetraBot.prototype.CustomInit = function(gameState)
|
|||
|
||||
PetraBot.prototype.OnUpdate = function(sharedScript)
|
||||
{
|
||||
if (this.isDeserialized)
|
||||
this.Init(state, playerID, sharedAI);
|
||||
|
||||
if (this.gameFinished || this.gameState.playerData.state == "defeated")
|
||||
return;
|
||||
|
||||
for (const i in this.events)
|
||||
for (const i in sharedScript.events)
|
||||
{
|
||||
if (i == "AIMetadata") // not used inside petra
|
||||
continue;
|
||||
if (this.savedEvents[i] !== undefined)
|
||||
this.savedEvents[i] = this.savedEvents[i].concat(this.events[i]);
|
||||
this.savedEvents[i] = this.savedEvents[i].concat(sharedScript.events[i]);
|
||||
else
|
||||
this.savedEvents[i] = this.events[i];
|
||||
this.savedEvents[i] = sharedScript.events[i];
|
||||
}
|
||||
|
||||
// Run the update every n turns, offset depending on player ID to balance the load
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"name": "Petra Bot",
|
||||
"description": "Petra is the default 0 A.D. AI bot. Please report issues to Wildfire Games.\n\nThe AI has six levels of difficulty: Sandbox, Very Easy, Easy, Medium, Hard, and Very Hard. Besides adjusting its strategy depending on the level, the AI also receives advantages or handycaps for certain rates, such as trade gain and efficiency of resource gathering. The AI can be quite challenging for beginners, so it is recommended to start with Very Easy or Easy until until you feel confident.",
|
||||
"moduleName" : "PETRA",
|
||||
"constructor": "PetraBot",
|
||||
"filename": "_petrabot.js",
|
||||
"useShared": true
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
|||
|
||||
const cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
ret.rallyPoint = { "position": cmpRallyPoint.GetPositions()[0] }; // undefined or {x,z} object
|
||||
ret.rallyPoint = { "position": cmpRallyPoint.GetPositions(player)[0] }; // undefined or {x,z} object
|
||||
|
||||
const cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
|
||||
if (cmpGarrisonHolder)
|
||||
|
|
@ -1035,6 +1035,16 @@ GuiInterface.prototype.GetNonGaiaEntities = function()
|
|||
return Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).GetNonGaiaEntities();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} entity - The entityID to verify.
|
||||
* @param {number} player - The playerID to check against.
|
||||
* @return {boolean}.
|
||||
*/
|
||||
function IsOwnedByPlayerOrMutualAlly(entity, player)
|
||||
{
|
||||
return IsOwnedByPlayer(player, entity) || IsOwnedByMutualAllyOfPlayer(player, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the rally points of a given list of entities (carried in cmd.entities).
|
||||
*
|
||||
|
|
@ -1046,14 +1056,12 @@ GuiInterface.prototype.GetNonGaiaEntities = function()
|
|||
*/
|
||||
GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
|
||||
{
|
||||
const cmpPlayer = QueryPlayerIDInterface(player);
|
||||
|
||||
// If there are some rally points already displayed, first hide them.
|
||||
for (const ent of this.entsRallyPointsDisplayed)
|
||||
for (const { ent } of this.entsRallyPointsDisplayed)
|
||||
{
|
||||
const cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer);
|
||||
if (cmpRallyPointRenderer)
|
||||
cmpRallyPointRenderer.SetDisplayed(false);
|
||||
cmpRallyPointRenderer.Reset();
|
||||
}
|
||||
|
||||
this.entsRallyPointsDisplayed = [];
|
||||
|
|
@ -1071,11 +1079,8 @@ GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
|
|||
if (!cmpRallyPoint)
|
||||
continue;
|
||||
|
||||
// Verify the owner.
|
||||
const cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
if (!(cmpPlayer && cmpPlayer.CanControlAllUnits()))
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() != player)
|
||||
continue;
|
||||
if (!IsOwnedByPlayerOrMutualAlly(ent, player))
|
||||
continue;
|
||||
|
||||
// If the command was passed an explicit position, use that and
|
||||
// override the real rally point position; otherwise use the real position.
|
||||
|
|
@ -1083,8 +1088,8 @@ GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
|
|||
if (cmd.x && cmd.z)
|
||||
pos = cmd;
|
||||
else
|
||||
// May return undefined if no rally point is set.
|
||||
pos = cmpRallyPoint.GetPositions()[0];
|
||||
// may return undefined if no rally point is set.
|
||||
pos = cmpRallyPoint.GetPositions(player)[0];
|
||||
|
||||
if (pos)
|
||||
{
|
||||
|
|
@ -1093,23 +1098,52 @@ GuiInterface.prototype.DisplayRallyPoint = function(player, cmd)
|
|||
if ("queued" in cmd)
|
||||
{
|
||||
if (cmd.queued == true)
|
||||
{
|
||||
// check by re adding all existing positions before appending the new queued one.
|
||||
const existingPositions = cmpRallyPoint.GetPositions(player);
|
||||
for (const posi of existingPositions)
|
||||
cmpRallyPointRenderer.AddPosition(new Vector2D(posi.x, posi.z));
|
||||
cmpRallyPointRenderer.AddPosition(new Vector2D(pos.x, pos.z));
|
||||
}
|
||||
else
|
||||
cmpRallyPointRenderer.SetPosition(new Vector2D(pos.x, pos.z));
|
||||
}
|
||||
else if (!cmpRallyPointRenderer.IsSet())
|
||||
{
|
||||
// Rebuild the renderer when not set (when reading saved game or in case of building update).
|
||||
for (const posi of cmpRallyPoint.GetPositions())
|
||||
const positions = cmpRallyPoint.GetPositions(player);
|
||||
for (const posi of positions)
|
||||
cmpRallyPointRenderer.AddPosition(new Vector2D(posi.x, posi.z));
|
||||
}
|
||||
|
||||
cmpRallyPointRenderer.SetDisplayed(true);
|
||||
|
||||
// Remember which entities have their rally points displayed so we can hide them again.
|
||||
this.entsRallyPointsDisplayed.push(ent);
|
||||
this.entsRallyPointsDisplayed.push({ ent, player });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GuiInterface.prototype.OnUpdate = function()
|
||||
{
|
||||
for (const { ent, player } of this.entsRallyPointsDisplayed)
|
||||
{
|
||||
const cmpRallyPointRenderer = Engine.QueryInterface(ent, IID_RallyPointRenderer);
|
||||
if (!cmpRallyPointRenderer)
|
||||
continue;
|
||||
|
||||
const cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (!cmpRallyPoint)
|
||||
continue;
|
||||
|
||||
const positions = cmpRallyPoint.GetPositions(player);
|
||||
|
||||
// Update renderer positions so the path follows moving targets.
|
||||
for (let i = 0; i < positions.length; i++)
|
||||
cmpRallyPointRenderer.UpdatePosition(i, new Vector2D(positions[i].x, positions[i].z));
|
||||
}
|
||||
};
|
||||
|
||||
GuiInterface.prototype.AddTargetMarker = function(player, cmd)
|
||||
{
|
||||
const ent = Engine.AddLocalEntity(cmd.template);
|
||||
|
|
|
|||
|
|
@ -5,67 +5,68 @@ RallyPoint.prototype.Schema =
|
|||
|
||||
RallyPoint.prototype.Init = function()
|
||||
{
|
||||
this.pos = [];
|
||||
this.data = [];
|
||||
this.perPlayer = {};
|
||||
};
|
||||
|
||||
RallyPoint.prototype.AddPosition = function(x, z)
|
||||
RallyPoint.prototype.GetOwner = function()
|
||||
{
|
||||
this.pos.push({
|
||||
"x": x,
|
||||
"z": z
|
||||
});
|
||||
return Engine.QueryInterface(this.entity, IID_Ownership)?.GetOwner();
|
||||
};
|
||||
|
||||
RallyPoint.prototype.HasPositions = function()
|
||||
RallyPoint.prototype.AddPosition = function(x, z, player = this.GetOwner())
|
||||
{
|
||||
return this.pos.length > 0;
|
||||
if (!this.perPlayer[player])
|
||||
this.perPlayer[player] = { "pos": [], "data": [] };
|
||||
this.perPlayer[player].pos.push({ "x": x, "z": z });
|
||||
};
|
||||
|
||||
RallyPoint.prototype.HasPositions = function(player = this.GetOwner())
|
||||
{
|
||||
return !!this.perPlayer[player]?.pos.length;
|
||||
};
|
||||
|
||||
RallyPoint.prototype.GetFirstPosition = function()
|
||||
{
|
||||
return this.pos.length ? Vector2D.from3D(this.pos[0]) : new Vector2D(-1, -1);
|
||||
const pos = this.perPlayer[this.GetOwner()]?.pos;
|
||||
return pos?.length ? Vector2D.from3D(pos[0]) : new Vector2D(-1, -1);
|
||||
};
|
||||
|
||||
RallyPoint.prototype.GetPositions = function()
|
||||
RallyPoint.prototype.GetPositions = function(player = this.GetOwner())
|
||||
{
|
||||
// Update positions for moving target entities
|
||||
const playerEntry = this.perPlayer[player];
|
||||
if (!playerEntry)
|
||||
return [];
|
||||
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
const cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
|
||||
// We must not affect the simulation state here (modifications of the
|
||||
// RallyPointRenderer are allowed though), so copy the state
|
||||
var ret = [];
|
||||
for (var i = 0; i < this.pos.length; i++)
|
||||
// We must not affect the simulation state here, so copy the state
|
||||
const ret = [];
|
||||
for (let i = 0; i < playerEntry.pos.length; i++)
|
||||
{
|
||||
ret.push(this.pos[i]);
|
||||
ret.push(playerEntry.pos[i]);
|
||||
|
||||
// Update the rallypoint coordinates if the target is alive
|
||||
if (!this.data[i] || !this.data[i].target || !this.TargetIsAlive(this.data[i].target))
|
||||
if (!playerEntry.data[i]?.target || !this.TargetIsAlive(playerEntry.data[i].target))
|
||||
continue;
|
||||
|
||||
// and visible
|
||||
if (cmpRangeManager && cmpOwnership &&
|
||||
cmpRangeManager.GetLosVisibility(this.data[i].target, cmpOwnership.GetOwner()) != "visible")
|
||||
// and visible to the player who set this rally point
|
||||
if (cmpRangeManager &&
|
||||
cmpRangeManager.GetLosVisibility(playerEntry.data[i].target, player) != "visible")
|
||||
continue;
|
||||
|
||||
// Get the actual position of the target entity
|
||||
var cmpPosition = Engine.QueryInterface(this.data[i].target, IID_Position);
|
||||
if (!cmpPosition || !cmpPosition.IsInWorld())
|
||||
const cmpPosition = Engine.QueryInterface(playerEntry.data[i].target, IID_Position);
|
||||
if (!cmpPosition?.IsInWorld())
|
||||
continue;
|
||||
|
||||
var targetPosition = cmpPosition.GetPosition2D();
|
||||
const targetPosition = cmpPosition.GetPosition2D();
|
||||
if (!targetPosition)
|
||||
continue;
|
||||
|
||||
if (this.pos[i].x == targetPosition.x && this.pos[i].z == targetPosition.y)
|
||||
if (playerEntry.pos[i].x == targetPosition.x && playerEntry.pos[i].z == targetPosition.y)
|
||||
continue;
|
||||
|
||||
ret[i] = { "x": targetPosition.x, "z": targetPosition.y };
|
||||
var cmpRallyPointRenderer = Engine.QueryInterface(this.entity, IID_RallyPointRenderer);
|
||||
if (cmpRallyPointRenderer)
|
||||
cmpRallyPointRenderer.UpdatePosition(i, targetPosition);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -73,31 +74,24 @@ RallyPoint.prototype.GetPositions = function()
|
|||
|
||||
// Extra data for the rally point, should have a command property and then helpful data for that command
|
||||
// See getActionInfo in gui/input.js
|
||||
RallyPoint.prototype.AddData = function(data)
|
||||
RallyPoint.prototype.AddData = function(data, player = this.GetOwner())
|
||||
{
|
||||
this.data.push(data);
|
||||
if (!this.perPlayer[player])
|
||||
this.perPlayer[player] = { "pos": [], "data": [] };
|
||||
this.perPlayer[player].data.push(data);
|
||||
};
|
||||
|
||||
// Returns an array with the data associated with this rally point. Each element has the structure:
|
||||
// {"type": "walk/gather/garrison/...", "target": targetEntityId, "resourceType": "tree/fruit/ore/..."} where target
|
||||
// and resourceType (specific resource type) are optional, also target may be an invalid entity, check for existence.
|
||||
RallyPoint.prototype.GetData = function()
|
||||
RallyPoint.prototype.GetData = function(player = this.GetOwner())
|
||||
{
|
||||
return this.data;
|
||||
return this.perPlayer[player]?.data ?? [];
|
||||
};
|
||||
|
||||
RallyPoint.prototype.Unset = function()
|
||||
RallyPoint.prototype.Unset = function(player = this.GetOwner())
|
||||
{
|
||||
this.pos = [];
|
||||
this.data = [];
|
||||
};
|
||||
|
||||
RallyPoint.prototype.Reset = function()
|
||||
{
|
||||
this.Unset();
|
||||
var cmpRallyPointRenderer = Engine.QueryInterface(this.entity, IID_RallyPointRenderer);
|
||||
if (cmpRallyPointRenderer)
|
||||
cmpRallyPointRenderer.Reset();
|
||||
delete this.perPlayer[player];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -107,50 +101,49 @@ RallyPoint.prototype.Reset = function()
|
|||
*/
|
||||
RallyPoint.prototype.OrderToRallyPoint = function(entity, ignore = [])
|
||||
{
|
||||
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership)
|
||||
return;
|
||||
const owner = cmpOwnership.GetOwner();
|
||||
|
||||
const cmpEntOwnership = Engine.QueryInterface(entity, IID_Ownership);
|
||||
if (!cmpEntOwnership || cmpEntOwnership.GetOwner() != owner)
|
||||
if (!cmpEntOwnership)
|
||||
return;
|
||||
const entOwner = cmpEntOwnership.GetOwner();
|
||||
|
||||
if (!this.HasPositions(entOwner))
|
||||
return;
|
||||
|
||||
const commands = GetRallyPointCommands(this, [entity]);
|
||||
const playerEntry = this.perPlayer[entOwner];
|
||||
const commands = GetRallyPointCommands(playerEntry.pos, playerEntry.data, [entity]);
|
||||
if (!commands.length ||
|
||||
commands[0].target == this.entity && ignore.includes(commands[0].type))
|
||||
return;
|
||||
|
||||
for (const command of commands)
|
||||
ProcessCommand(owner, command);
|
||||
ProcessCommand(entOwner, command);
|
||||
};
|
||||
|
||||
RallyPoint.prototype.OnGlobalEntityRenamed = function(msg)
|
||||
{
|
||||
for (const data of this.data)
|
||||
{
|
||||
if (!data)
|
||||
continue;
|
||||
if (data.target && data.target == msg.entity)
|
||||
data.target = msg.newentity;
|
||||
if (data.source && data.source == msg.entity)
|
||||
data.source = msg.newentity;
|
||||
}
|
||||
for (const playerEntry of Object.values(this.perPlayer))
|
||||
for (const data of playerEntry.data)
|
||||
{
|
||||
if (data?.target == msg.entity)
|
||||
data.target = msg.newentity;
|
||||
if (data?.source == msg.entity)
|
||||
data.source = msg.newentity;
|
||||
}
|
||||
|
||||
if (msg.entity != this.entity)
|
||||
return;
|
||||
|
||||
const cmpRallyPointNew = Engine.QueryInterface(msg.newentity, IID_RallyPoint);
|
||||
if (cmpRallyPointNew)
|
||||
{
|
||||
const rallyCoords = this.GetPositions();
|
||||
const rallyData = this.GetData();
|
||||
for (let i = 0; i < rallyCoords.length; ++i)
|
||||
for (const player in this.perPlayer)
|
||||
{
|
||||
cmpRallyPointNew.AddPosition(rallyCoords[i].x, rallyCoords[i].z);
|
||||
cmpRallyPointNew.AddData(rallyData[i]);
|
||||
const playerEntry = this.perPlayer[player];
|
||||
for (let i = 0; i < playerEntry.pos.length; ++i)
|
||||
{
|
||||
cmpRallyPointNew.AddPosition(playerEntry.pos[i].x, playerEntry.pos[i].z, +player);
|
||||
cmpRallyPointNew.AddData(playerEntry.data[i], +player);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RallyPoint.prototype.OnOwnershipChanged = function(msg)
|
||||
|
|
@ -159,7 +152,7 @@ RallyPoint.prototype.OnOwnershipChanged = function(msg)
|
|||
if (msg.from == INVALID_PLAYER || msg.to == INVALID_PLAYER)
|
||||
return;
|
||||
|
||||
this.Reset();
|
||||
this.perPlayer = {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ Trainer.prototype.Item.prototype.Spawn = function()
|
|||
const cmpRallyPoint = Engine.QueryInterface(this.trainer, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
{
|
||||
const data = cmpRallyPoint.GetData()[0];
|
||||
const data = cmpRallyPoint.GetData(this.player)[0];
|
||||
if (data?.target && data.target == this.trainer && data.command == "garrison")
|
||||
autoGarrison = true;
|
||||
}
|
||||
|
|
@ -294,7 +294,7 @@ Trainer.prototype.Item.prototype.Spawn = function()
|
|||
}
|
||||
|
||||
if (spawnedEnts.length && cmpRallyPoint)
|
||||
for (const com of GetRallyPointCommands(cmpRallyPoint, spawnedEnts))
|
||||
for (const com of GetRallyPointCommands(cmpRallyPoint.GetPositions(this.player), cmpRallyPoint.GetData(this.player), spawnedEnts))
|
||||
{
|
||||
// Tag this command as coming from a rally point
|
||||
com.fromRallyPoint = true;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ function initialRallyPointTest(test_function)
|
|||
ResetState();
|
||||
|
||||
const entityID = 123;
|
||||
AddMock(entityID, IID_Ownership, { "GetOwner": () => 1 });
|
||||
const cmpRallyPoint = ConstructComponent(entityID, "RallyPoint", {});
|
||||
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetData(), []);
|
||||
|
|
@ -50,12 +51,6 @@ initialRallyPointTest((cmpRallyPoint) =>
|
|||
return true;
|
||||
});
|
||||
|
||||
initialRallyPointTest((cmpRallyPoint) =>
|
||||
{
|
||||
cmpRallyPoint.Reset();
|
||||
return true;
|
||||
});
|
||||
|
||||
// Construction
|
||||
initialRallyPointTest((cmpRallyPoint) =>
|
||||
{
|
||||
|
|
@ -83,3 +78,135 @@ initialRallyPointTest((cmpRallyPoint) =>
|
|||
cmpRallyPoint.OnOwnershipChanged({ "from": 2, "to": 0 });
|
||||
return true;
|
||||
});
|
||||
|
||||
// Per-player rally point tests
|
||||
{
|
||||
ResetState();
|
||||
const entityID = 123;
|
||||
let ownerPlayer = 1;
|
||||
AddMock(entityID, IID_Ownership, { "GetOwner": () => ownerPlayer });
|
||||
const cmpRallyPoint = ConstructComponent(entityID, "RallyPoint", {});
|
||||
const player2 = 2;
|
||||
const player3 = 3;
|
||||
|
||||
// Initially no per-player positions
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2), []);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetData(player2), []);
|
||||
TS_ASSERT(!cmpRallyPoint.HasPositions(player2));
|
||||
|
||||
// Add per-player rally point for player 2
|
||||
cmpRallyPoint.AddPosition(10, 20, player2);
|
||||
cmpRallyPoint.AddData({ "command": "walk" }, player2);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2), [{ "x": 10, "z": 20 }]);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetData(player2), [{ "command": "walk" }]);
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player2));
|
||||
|
||||
// Add a second waypoint for player 2
|
||||
cmpRallyPoint.AddPosition(30, 40, player2);
|
||||
cmpRallyPoint.AddData({ "command": "garrison" }, player2);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2),
|
||||
[{ "x": 10, "z": 20 }, { "x": 30, "z": 40 }]);
|
||||
|
||||
// Player 3 is unaffected
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player3), []);
|
||||
TS_ASSERT(!cmpRallyPoint.HasPositions(player3));
|
||||
|
||||
// Add per-player rally point for player 3
|
||||
cmpRallyPoint.AddPosition(50, 60, player3);
|
||||
cmpRallyPoint.AddData({ "command": "walk" }, player3);
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player3));
|
||||
|
||||
// Unset clears player 2 positions and data
|
||||
cmpRallyPoint.Unset(player2);
|
||||
TS_ASSERT(!cmpRallyPoint.HasPositions(player2));
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2), []);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetData(player2), []);
|
||||
// Player 3 is unaffected
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player3));
|
||||
|
||||
// Unset removes player 3 entry
|
||||
cmpRallyPoint.Unset(player3);
|
||||
TS_ASSERT(!cmpRallyPoint.HasPositions(player3));
|
||||
|
||||
// Per-player data is cleared on ownership change
|
||||
cmpRallyPoint.AddPosition(10, 20, player2);
|
||||
cmpRallyPoint.AddData({ "command": "walk" }, player2);
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player2));
|
||||
cmpRallyPoint.OnOwnershipChanged({ "from": 1, "to": 2 });
|
||||
ownerPlayer = 2;
|
||||
TS_ASSERT(!cmpRallyPoint.HasPositions(player2));
|
||||
|
||||
// The owner's rally point entry does not affect allied players' entries
|
||||
cmpRallyPoint.AddPosition(100, 200);
|
||||
cmpRallyPoint.AddData({ "command": "walk" });
|
||||
cmpRallyPoint.AddPosition(300, 400, player3);
|
||||
cmpRallyPoint.AddData({ "command": "walk" }, player3);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(), [{ "x": 100, "z": 200 }]);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player3), [{ "x": 300, "z": 400 }]);
|
||||
// Unset does not affect per-player data
|
||||
cmpRallyPoint.Unset();
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(), []);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player3), [{ "x": 300, "z": 400 }]);
|
||||
}
|
||||
|
||||
// Ownership change construction/destruction preserves per-player data
|
||||
{
|
||||
ResetState();
|
||||
const entityID = 123;
|
||||
const cmpRallyPoint = ConstructComponent(entityID, "RallyPoint", {});
|
||||
const player2 = 2;
|
||||
|
||||
cmpRallyPoint.AddPosition(10, 20, player2);
|
||||
cmpRallyPoint.AddData({ "command": "walk" }, player2);
|
||||
|
||||
// Construction: from INVALID_PLAYER should not clear per-player data
|
||||
cmpRallyPoint.OnOwnershipChanged({ "from": INVALID_PLAYER, "to": 1 });
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player2));
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2), [{ "x": 10, "z": 20 }]);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetData(player2), [{ "command": "walk" }]);
|
||||
|
||||
// Destruction: to INVALID_PLAYER should not clear per-player data
|
||||
cmpRallyPoint.OnOwnershipChanged({ "from": 1, "to": INVALID_PLAYER });
|
||||
TS_ASSERT(cmpRallyPoint.HasPositions(player2));
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPoint.GetPositions(player2), [{ "x": 10, "z": 20 }]);
|
||||
}
|
||||
|
||||
// OnGlobalEntityRenamed migrates per-player rally point data to the new entity
|
||||
{
|
||||
ResetState();
|
||||
const oldEntityID = 123;
|
||||
const newEntityID = 456;
|
||||
const player2 = 2;
|
||||
const player3 = 3;
|
||||
|
||||
AddMock(oldEntityID, IID_Ownership, { "GetOwner": () => 1 });
|
||||
AddMock(newEntityID, IID_Ownership, { "GetOwner": () => 1 });
|
||||
const cmpRallyPointOld = ConstructComponent(oldEntityID, "RallyPoint", {});
|
||||
const cmpRallyPointNew = ConstructComponent(newEntityID, "RallyPoint", {});
|
||||
|
||||
cmpRallyPointOld.AddPosition(100, 200);
|
||||
cmpRallyPointOld.AddData({ "command": "walk" });
|
||||
cmpRallyPointOld.AddPosition(10, 20, player2);
|
||||
cmpRallyPointOld.AddData({ "command": "walk" }, player2);
|
||||
cmpRallyPointOld.AddPosition(30, 40, player3);
|
||||
cmpRallyPointOld.AddData({ "command": "garrison" }, player3);
|
||||
|
||||
cmpRallyPointOld.OnGlobalEntityRenamed({ "entity": oldEntityID, "newentity": newEntityID });
|
||||
|
||||
// New entity receives owner and per-player rally point data
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPointNew.GetPositions(), [{ "x": 100, "z": 200 }]);
|
||||
TS_ASSERT(cmpRallyPointNew.HasPositions(player2));
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPointNew.GetPositions(player2), [{ "x": 10, "z": 20 }]);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPointNew.GetData(player2), [{ "command": "walk" }]);
|
||||
TS_ASSERT(cmpRallyPointNew.HasPositions(player3));
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPointNew.GetPositions(player3), [{ "x": 30, "z": 40 }]);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpRallyPointNew.GetData(player3), [{ "command": "garrison" }]);
|
||||
|
||||
// Rename for an unrelated entity does not migrate to new entity
|
||||
ResetState();
|
||||
const cmpRP1 = ConstructComponent(oldEntityID, "RallyPoint", {});
|
||||
const cmpRP2 = ConstructComponent(newEntityID, "RallyPoint", {});
|
||||
cmpRP1.AddPosition(10, 20, player2);
|
||||
cmpRP1.OnGlobalEntityRenamed({ "entity": 999, "newentity": newEntityID });
|
||||
TS_ASSERT(!cmpRP2.HasPositions(player2));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,27 +434,31 @@ var g_Commands = {
|
|||
|
||||
"set-rallypoint": function(player, cmd, data)
|
||||
{
|
||||
for (const ent of data.entities)
|
||||
const structures = FilterEntityListWithAllies(cmd.structures || [], player, data.controlAllUnits);
|
||||
for (const structure of structures)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
{
|
||||
if (!cmd.queued)
|
||||
cmpRallyPoint.Unset();
|
||||
const cmpRallyPoint = Engine.QueryInterface(structure, IID_RallyPoint);
|
||||
if (!cmpRallyPoint)
|
||||
continue;
|
||||
|
||||
cmpRallyPoint.AddPosition(cmd.x, cmd.z);
|
||||
cmpRallyPoint.AddData(clone(cmd.data));
|
||||
}
|
||||
if (!cmd.queued)
|
||||
cmpRallyPoint.Unset(player);
|
||||
|
||||
cmpRallyPoint.AddPosition(cmd.x, cmd.z, player);
|
||||
cmpRallyPoint.AddData(clone(cmd.data), player);
|
||||
}
|
||||
},
|
||||
|
||||
"unset-rallypoint": function(player, cmd, data)
|
||||
{
|
||||
for (const ent of data.entities)
|
||||
const structures = FilterEntityListWithAllies(cmd.structures || [], player, data.controlAllUnits);
|
||||
for (const structure of structures)
|
||||
{
|
||||
var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint);
|
||||
if (cmpRallyPoint)
|
||||
cmpRallyPoint.Reset();
|
||||
const cmpRallyPoint = Engine.QueryInterface(structure, IID_RallyPoint);
|
||||
if (!cmpRallyPoint)
|
||||
continue;
|
||||
|
||||
cmpRallyPoint.Unset(player);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
// Returns an array of commands suitable for ProcessCommand() based on the rally point data.
|
||||
// This assumes that the rally point has a valid position.
|
||||
function GetRallyPointCommands(cmpRallyPoint, spawnedEnts)
|
||||
function GetRallyPointCommands(rallyPos, data, spawnedEnts)
|
||||
{
|
||||
const data = cmpRallyPoint.GetData();
|
||||
const rallyPos = cmpRallyPoint.GetPositions();
|
||||
const ret = [];
|
||||
for (let i = 0; i < rallyPos.length; ++i)
|
||||
{
|
||||
// Look and see if there is a command in the rally point data, otherwise just walk there.
|
||||
let command = data[i] && data[i].command ? data[i].command : "walk";
|
||||
let command = data[i]?.command ?? "walk";
|
||||
|
||||
// If a target was set and the target no longer exists, or no longer
|
||||
// has a valid position, then just walk to the rally point.
|
||||
if (data[i] && data[i].target)
|
||||
if (data[i]?.target)
|
||||
{
|
||||
const cmpPosition = Engine.QueryInterface(data[i].target, IID_Position);
|
||||
if (!cmpPosition || !cmpPosition.IsInWorld())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -169,52 +169,52 @@ protected:
|
|||
// BaseProxyHandler interface below
|
||||
|
||||
// Handler for `object.x`
|
||||
virtual bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver, JS::HandleId id, JS::MutableHandleValue vp) const override final;
|
||||
bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver, JS::HandleId id, JS::MutableHandleValue vp) const final;
|
||||
// Handler for `object.x = y;`
|
||||
virtual bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue vp,
|
||||
bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue vp,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult& result) const final;
|
||||
// Handler for `delete object.x;`
|
||||
virtual bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::ObjectOpResult& result) const override final;
|
||||
bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::ObjectOpResult& result) const final;
|
||||
|
||||
// The following methods are not provided by BaseProxyHandler.
|
||||
// We provide defaults that do nothing (some raise JS exceptions).
|
||||
|
||||
virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc) const override final;
|
||||
bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc) const final;
|
||||
|
||||
// Throw an exception is JS code attempts defining a property.
|
||||
virtual bool defineProperty(JSContext*, JS::HandleObject /*proxy*/, JS::HandleId,
|
||||
bool defineProperty(JSContext*, JS::HandleObject /*proxy*/, JS::HandleId,
|
||||
JS::Handle<JS::PropertyDescriptor>, JS::ObjectOpResult& /*result*/) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) const override final;
|
||||
bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) const final;
|
||||
|
||||
// Nothing to enumerate.
|
||||
virtual bool enumerate(JSContext*, JS::HandleObject /*proxy*/,
|
||||
bool enumerate(JSContext*, JS::HandleObject /*proxy*/,
|
||||
JS::MutableHandleIdVector /*props*/) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Throw an exception is JS attempts to query the prototype.
|
||||
virtual bool getPrototypeIfOrdinary(JSContext*, JS::HandleObject /*proxy*/, bool* /*isOrdinary*/,
|
||||
bool getPrototypeIfOrdinary(JSContext*, JS::HandleObject /*proxy*/, bool* /*isOrdinary*/,
|
||||
JS::MutableHandleObject /*protop*/) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Throw an exception - no prototype to set.
|
||||
virtual bool setImmutablePrototype(JSContext*, JS::HandleObject /*proxy*/,
|
||||
bool setImmutablePrototype(JSContext*, JS::HandleObject /*proxy*/,
|
||||
bool* /*succeeded*/) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// We are not extensible.
|
||||
virtual bool preventExtensions(JSContext*, JS::HandleObject /*proxy*/,
|
||||
bool preventExtensions(JSContext*, JS::HandleObject /*proxy*/,
|
||||
JS::ObjectOpResult& /*result*/) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual bool isExtensible(JSContext*, JS::HandleObject /*proxy*/, bool* extensible) const override
|
||||
bool isExtensible(JSContext*, JS::HandleObject /*proxy*/, bool* extensible) const override
|
||||
{
|
||||
*extensible = false;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -87,23 +87,23 @@ class MapCache : public GUIProxyProps
|
|||
public:
|
||||
virtual ~MapCache() {};
|
||||
|
||||
virtual bool has(const std::string& name) const override
|
||||
bool has(const std::string& name) const override
|
||||
{
|
||||
return m_Functions.find(name) != m_Functions.end();
|
||||
}
|
||||
|
||||
virtual JSObject* get(const std::string& name) const override
|
||||
JSObject* get(const std::string& name) const override
|
||||
{
|
||||
return m_Functions.at(name).get();
|
||||
}
|
||||
|
||||
virtual bool setFunction(const ScriptRequest& rq, const std::string& name, JSFunction* function) override
|
||||
bool setFunction(const ScriptRequest& rq, const std::string& name, JSFunction* function) override
|
||||
{
|
||||
m_Functions[name].init(rq.cx, JS_GetFunctionObject(function));
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual std::vector<std::string_view> getPropsNames() const override
|
||||
std::vector<std::string_view> getPropsNames() const override
|
||||
{
|
||||
std::vector<std::string_view> result;
|
||||
result.reserve(m_Functions.size());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -141,7 +141,7 @@ public:
|
|||
return mask;
|
||||
}
|
||||
|
||||
virtual bool IsMouseOver(const CVector2D& mousePos, const CRect& objectSize) const override
|
||||
bool IsMouseOver(const CVector2D& mousePos, const CRect& objectSize) const override
|
||||
{
|
||||
if (m_Data.empty())
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -26,28 +26,23 @@
|
|||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "file_system.h"
|
||||
|
||||
#include "lib/debug.h"
|
||||
#include "lib/file/file_system.h"
|
||||
#include "lib/posix/posix_filesystem.h"
|
||||
#include "lib/sysdep/filesystem.h"
|
||||
#include "lib/sysdep/os.h"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct WDIR;
|
||||
|
||||
bool DirectoryExists(const OsPath& path)
|
||||
{
|
||||
WDIR* dir = wopendir(path);
|
||||
if(dir)
|
||||
try
|
||||
{
|
||||
wclosedir(dir);
|
||||
return true;
|
||||
return std::filesystem::is_directory(path.string());
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("DirectoryExists: failed to check if directory '%s' exists, reason: %s\n", path.string8().c_str(), err.what());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -55,158 +50,152 @@ bool DirectoryExists(const OsPath& path)
|
|||
|
||||
bool FileExists(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
const bool exists = wstat(pathname, &s) == 0;
|
||||
return exists;
|
||||
try
|
||||
{
|
||||
return std::filesystem::is_regular_file(pathname.string());
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("FileExists: failed to check if file '%s' exists, reason: %s\n", pathname.string8().c_str(), err.what());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
u64 FileSize(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
ENSURE(wstat(pathname, &s) == 0);
|
||||
return s.st_size;
|
||||
try
|
||||
{
|
||||
return static_cast<u64>(std::filesystem::file_size(pathname.string()));
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("FileSize: failed to get filesize for '%s', reason: %s\n", pathname.string8().c_str(), err.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Status GetFileInfo(const OsPath& pathname, CFileInfo* pPtrInfo)
|
||||
{
|
||||
errno = 0;
|
||||
struct stat s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if(wstat(pathname, &s) != 0)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
|
||||
*pPtrInfo = CFileInfo(pathname.Filename(), s.st_size, s.st_mtime);
|
||||
try
|
||||
{
|
||||
const std::filesystem::path path{pathname.string()};
|
||||
*pPtrInfo = CFileInfo(path.filename().wstring(), static_cast<u64>(std::filesystem::file_size(path)),
|
||||
static_cast<time_t>(std::chrono::duration_cast<std::chrono::seconds>(std::filesystem::last_write_time(path).time_since_epoch()).count()));
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("GetFileInfo: failed to get file info for '%s', reason: %s\n", pathname.string8().c_str(), err.what());
|
||||
return ERR::EXCEPTION;
|
||||
}
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
struct DirDeleter
|
||||
{
|
||||
void operator()(WDIR* osDir) const
|
||||
{
|
||||
const int ret = wclosedir(osDir);
|
||||
ENSURE(ret == 0);
|
||||
}
|
||||
};
|
||||
|
||||
Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames)
|
||||
{
|
||||
// open directory
|
||||
errno = 0;
|
||||
WDIR* pDir = wopendir(path);
|
||||
if(!pDir)
|
||||
return StatusFromErrno(); // NOWARN
|
||||
std::shared_ptr<WDIR> osDir(pDir, DirDeleter());
|
||||
|
||||
for(;;)
|
||||
try
|
||||
{
|
||||
errno = 0;
|
||||
struct wdirent* osEnt = wreaddir(osDir.get());
|
||||
if(!osEnt)
|
||||
for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(path.string()))
|
||||
{
|
||||
// no error, just no more entries to return
|
||||
if(!errno)
|
||||
return INFO::OK;
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
}
|
||||
|
||||
for(size_t i = 0; osEnt->d_name[i] != '\0'; i++)
|
||||
RETURN_STATUS_IF_ERR(Path::Validate(osEnt->d_name[i]));
|
||||
|
||||
const std::wstring_view name{osEnt->d_name};
|
||||
|
||||
// get file information (mode, size, mtime)
|
||||
struct stat s;
|
||||
#if OS_WIN
|
||||
// .. return wdirent directly (much faster than calling stat).
|
||||
RETURN_STATUS_IF_ERR(wreaddir_stat_np(osDir.get(), &s));
|
||||
#else
|
||||
// .. call regular stat().
|
||||
errno = 0;
|
||||
const OsPath pathname = path / OsPath(osEnt->d_name);
|
||||
if(wstat(pathname, &s) != 0)
|
||||
{
|
||||
if(errno == ENOENT)
|
||||
if (entry.is_directory() && entry.path().filename() != "." && entry.path().filename() != ".." && subdirectoryNames)
|
||||
{
|
||||
// TODO: This should be displayed to the user as a LOGWARNING when this code is
|
||||
// moved to ps/
|
||||
debug_printf("The path \"%s\" cannot be found. It is probably a dangling link "
|
||||
"pointing to a non-existent path.\n", pathname.string8().c_str());
|
||||
continue;
|
||||
subdirectoryNames->emplace_back(entry.path().filename());
|
||||
}
|
||||
else if (entry.is_regular_file() && files)
|
||||
{
|
||||
files->emplace_back(entry.path().filename().wstring(), static_cast<u64>(entry.file_size()),
|
||||
static_cast<time_t>(std::chrono::duration_cast<std::chrono::seconds>(entry.last_write_time().time_since_epoch()).count()));
|
||||
}
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
}
|
||||
#endif
|
||||
|
||||
if(files && S_ISREG(s.st_mode))
|
||||
files->emplace_back(osEnt->d_name, s.st_size, s.st_mtime);
|
||||
else if(subdirectoryNames && S_ISDIR(s.st_mode) && name != L"." && name != L"..")
|
||||
subdirectoryNames->emplace_back(osEnt->d_name);
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("GetDirectoryEntries: failed to get directory entries for'%s', reason: %s\n", path.string8().c_str(), err.what());
|
||||
return ERR::EXCEPTION;
|
||||
}
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::filesystem::perms ModeTToPerms(mode_t mode)
|
||||
{
|
||||
using std::filesystem::perms;
|
||||
perms perm{perms::none};
|
||||
|
||||
if (mode | S_IRUSR)
|
||||
perm |= perms::owner_read;
|
||||
if (mode | S_IWUSR)
|
||||
perm |= perms::owner_write;
|
||||
if (mode | S_IXUSR)
|
||||
perm |= perms::owner_exec;
|
||||
|
||||
if (mode | S_IRGRP)
|
||||
perm |= perms::group_read;
|
||||
if (mode | S_IWGRP)
|
||||
perm |= perms::group_write;
|
||||
if (mode | S_IXGRP)
|
||||
perm |= perms::group_exec;
|
||||
|
||||
if (mode | S_IROTH)
|
||||
perm |= perms::others_read;
|
||||
if (mode | S_IWOTH)
|
||||
perm |= perms::others_write;
|
||||
if (mode | S_IXOTH)
|
||||
perm |= perms::others_exec;
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
Status CreateDirectoriesImpl(const std::filesystem::path& path, const std::filesystem::perms& perms)
|
||||
{
|
||||
if (std::filesystem::exists(path))
|
||||
return ERR::FAIL;
|
||||
|
||||
if (!std::filesystem::is_directory(path.parent_path()))
|
||||
{
|
||||
const Status status = CreateDirectoriesImpl(path.parent_path(), perms);
|
||||
if (status != INFO::OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
std::filesystem::create_directory(path);
|
||||
std::filesystem::permissions(path, perms);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint)
|
||||
{
|
||||
if(path.empty())
|
||||
return INFO::OK;
|
||||
|
||||
struct stat s;
|
||||
if(wstat(path, &s) == 0)
|
||||
try
|
||||
{
|
||||
if(!S_ISDIR(s.st_mode)) // encountered a file
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
return INFO::OK;
|
||||
return CreateDirectoriesImpl(std::filesystem::path(path.string()), ModeTToPerms(mode));
|
||||
}
|
||||
|
||||
// If we were passed a path ending with '/', strip the '/' now so that
|
||||
// we can consistently use Parent to find parent directory names
|
||||
if(path.IsDirectory())
|
||||
return CreateDirectories(path.Parent(), mode, breakpoint);
|
||||
|
||||
RETURN_STATUS_IF_ERR(CreateDirectories(path.Parent(), mode));
|
||||
|
||||
errno = 0;
|
||||
if(wmkdir(path, mode) != 0)
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("CreateDirectories: failed to mkdir %s (mode %d)\n", path.string8().c_str(), mode);
|
||||
debug_printf("CreateDirectories: failed to create directories '%s', reason: %s\n", path.string8().c_str(), err.what());
|
||||
if (breakpoint)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
else
|
||||
return StatusFromErrno();
|
||||
WARN_RETURN(ERR::EXCEPTION);
|
||||
else
|
||||
return ERR::EXCEPTION;
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
Status DeleteDirectory(const OsPath& path)
|
||||
{
|
||||
// note: we have to recursively empty the directory before it can
|
||||
// be deleted (required by Windows and POSIX rmdir()).
|
||||
|
||||
CFileInfos files; DirectoryNames subdirectoryNames;
|
||||
RETURN_STATUS_IF_ERR(GetDirectoryEntries(path, &files, &subdirectoryNames));
|
||||
|
||||
// delete files
|
||||
for(size_t i = 0; i < files.size(); i++)
|
||||
try
|
||||
{
|
||||
const OsPath pathname = path / files[i].Name();
|
||||
errno = 0;
|
||||
if(wunlink(pathname) != 0)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
std::filesystem::remove_all(path.string());
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& err)
|
||||
{
|
||||
debug_printf("DeleteDirectory: failed to delete directory '%s', reason: %s\n", path.string8().c_str(), err.what());
|
||||
return ERR::EXCEPTION;
|
||||
}
|
||||
|
||||
// recurse over subdirectoryNames
|
||||
for(size_t i = 0; i < subdirectoryNames.size(); i++)
|
||||
RETURN_STATUS_IF_ERR(DeleteDirectory(path / subdirectoryNames[i]));
|
||||
|
||||
errno = 0;
|
||||
if(wrmdir(path) != 0)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
#include "lib/posix/posix_aio.h" // LIO_READ, LIO_WRITE
|
||||
#include "lib/posix/posix_types.h"
|
||||
#include "lib/status.h"
|
||||
#include "lib/sysdep/filesystem.h" // wtruncate
|
||||
#include "lib/sysdep/filesystem.h"
|
||||
#include "lib/sysdep/os.h"
|
||||
#include "lib/sysdep/rtl.h"
|
||||
#include "lib/types.h"
|
||||
|
|
@ -47,7 +47,9 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fcntl.h>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace ERR
|
||||
{
|
||||
|
|
@ -332,9 +334,12 @@ static inline Status Store(const OsPath& pathname, const void* data, size_t size
|
|||
|
||||
RETURN_STATUS_IF_ERR(io::Run(op, p, completedHook, issueHook));
|
||||
|
||||
file.Close(); // (required by wtruncate)
|
||||
file.Close(); // (required by resize_file)
|
||||
|
||||
RETURN_STATUS_IF_ERR(wtruncate(pathname, size));
|
||||
std::error_code ec{};
|
||||
std::filesystem::resize_file(pathname.string(), size, ec);
|
||||
if (ec)
|
||||
return StatusFromSystemError(ec);
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -100,6 +100,16 @@ int ErrnoFromStatus(Status status)
|
|||
return EPERM;
|
||||
}
|
||||
|
||||
Status StatusFromSystemError(std::error_code& ec)
|
||||
{
|
||||
if (!ec)
|
||||
return INFO::OK;
|
||||
std::error_condition cond = ec.default_error_condition();
|
||||
if (cond.category() != std::generic_category())
|
||||
return ERR::FAIL;
|
||||
const StatusDefinition* def = DefinitionFromErrno(cond.value());
|
||||
return def ? def->status : ERR::FAIL;
|
||||
}
|
||||
|
||||
Status StatusFromErrno()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -165,6 +165,7 @@ To summarize: +/-1SHHCC (S=subsystem, HH=header, CC=code number)
|
|||
#include "lib/types.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <system_error>
|
||||
|
||||
// an integral type allows defining error codes in separate headers,
|
||||
// but is not as type-safe as an enum. use Lint's 'strong type' checking
|
||||
|
|
@ -246,6 +247,11 @@ extern int ErrnoFromStatus(Status status);
|
|||
**/
|
||||
extern Status StatusFromErrno();
|
||||
|
||||
/**
|
||||
* @return Status equivalent of error_code, or ERR::FAIL if there's no equivalent.
|
||||
*/
|
||||
extern Status StatusFromSystemError(std::error_code& ec);
|
||||
|
||||
// note: other conversion routines (e.g. to/from Win32) are implemented in
|
||||
// the corresponding modules to keep this header portable.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -31,32 +31,6 @@
|
|||
#include "lib/posix/posix_filesystem.h" // mode_t
|
||||
|
||||
|
||||
//
|
||||
// dirent.h
|
||||
//
|
||||
|
||||
struct WDIR;
|
||||
|
||||
struct wdirent
|
||||
{
|
||||
// note: SUSv3 describes this as a "char array" but of unspecified size.
|
||||
// we declare as a pointer to avoid having to copy the string.
|
||||
wchar_t* d_name;
|
||||
};
|
||||
|
||||
extern WDIR* wopendir(const OsPath& path);
|
||||
|
||||
extern wdirent* wreaddir(WDIR*);
|
||||
|
||||
// return status for the file returned by the last successful
|
||||
// wreaddir call from the given directory stream.
|
||||
// currently sets st_size, st_mode, and st_mtime; the rest are zeroed.
|
||||
// non-portable, but considerably faster than stat(). used by dir_ForEachSortedEntry.
|
||||
extern int wreaddir_stat_np(WDIR*, struct stat*);
|
||||
|
||||
extern int wclosedir(WDIR*);
|
||||
|
||||
|
||||
//
|
||||
// fcntl.h
|
||||
//
|
||||
|
|
@ -82,22 +56,6 @@ extern int wopen(const OsPath& pathname, int oflag, mode_t mode);
|
|||
extern int wclose(int fd);
|
||||
|
||||
|
||||
//
|
||||
// unistd.h
|
||||
//
|
||||
|
||||
// waio requires offsets and sizes to be multiples of the sector size.
|
||||
// to allow arbitrarily sized files, we truncate them after I/O.
|
||||
// however, ftruncate cannot be used since it is also subject to the
|
||||
// sector-alignment requirement. instead, the file must be closed and
|
||||
// this function called.
|
||||
int wtruncate(const OsPath& pathname, off_t length);
|
||||
|
||||
int wunlink(const OsPath& pathname);
|
||||
|
||||
int wrmdir(const OsPath& path);
|
||||
|
||||
|
||||
//
|
||||
// stdlib.h
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -42,13 +42,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <string>
|
||||
|
||||
struct WDIR
|
||||
{
|
||||
DIR* d;
|
||||
wchar_t name[PATH_MAX];
|
||||
wdirent ent;
|
||||
};
|
||||
|
||||
#if OS_ANDROID
|
||||
|
||||
// The Crystax NDK seems to do weird things with opendir etc.
|
||||
|
|
@ -84,36 +77,6 @@ void init_libc() { }
|
|||
|
||||
#endif
|
||||
|
||||
WDIR* wopendir(const OsPath& path)
|
||||
{
|
||||
init_libc();
|
||||
DIR* d = opendir(OsString(path).c_str());
|
||||
if(!d)
|
||||
return 0;
|
||||
WDIR* wd = new WDIR;
|
||||
wd->d = d;
|
||||
wd->name[0] = '\0';
|
||||
wd->ent.d_name = wd->name;
|
||||
return wd;
|
||||
}
|
||||
|
||||
struct wdirent* wreaddir(WDIR* wd)
|
||||
{
|
||||
dirent* ent = readdir(wd->d);
|
||||
if(!ent)
|
||||
return 0;
|
||||
wcscpy_s(wd->name, ARRAY_SIZE(wd->name), OsPath(ent->d_name).string().c_str());
|
||||
return &wd->ent;
|
||||
}
|
||||
|
||||
int wclosedir(WDIR* wd)
|
||||
{
|
||||
int ret = closedir(wd->d);
|
||||
delete wd;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wopen(const OsPath& pathname, int oflag)
|
||||
{
|
||||
ENSURE(!(oflag & O_CREAT));
|
||||
|
|
@ -130,22 +93,6 @@ int wclose(int fd)
|
|||
return close(fd);
|
||||
}
|
||||
|
||||
|
||||
int wtruncate(const OsPath& pathname, off_t length)
|
||||
{
|
||||
return truncate(OsString(pathname).c_str(), length);
|
||||
}
|
||||
|
||||
int wunlink(const OsPath& pathname)
|
||||
{
|
||||
return unlink(OsString(pathname).c_str());
|
||||
}
|
||||
|
||||
int wrmdir(const OsPath& path)
|
||||
{
|
||||
return rmdir(OsString(path).c_str());
|
||||
}
|
||||
|
||||
int wrename(const OsPath& pathnameOld, const OsPath& pathnameNew)
|
||||
{
|
||||
return rename(OsString(pathnameOld).c_str(), OsString(pathnameNew).c_str());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -130,7 +130,7 @@ extern Status waio_close(int fd);
|
|||
// @param size is rounded up to a multiple of maxSectorSize (required by
|
||||
// SetEndOfFile; this could be avoided by using the undocumented
|
||||
// NtSetInformationFile or SetFileInformationByHandle on Vista and later).
|
||||
// use wtruncate after I/O is complete to chop off the excess padding.
|
||||
// use truncate after I/O is complete to chop off the excess padding.
|
||||
//
|
||||
// NB: writes that extend a file (i.e. ALL WRITES when creating new files)
|
||||
// are synchronous, which prevents overlapping I/O and other work.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -30,55 +30,6 @@
|
|||
|
||||
#include <atomic>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// WDIR suballocator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// most applications only need a single WDIR at a time. we avoid expensive
|
||||
// heap allocations by reusing a single static instance. if it is already
|
||||
// in use, we allocate further instances dynamically.
|
||||
// NB: this is thread-safe due to CAS.
|
||||
|
||||
struct WDIR // POD
|
||||
{
|
||||
HANDLE hFind;
|
||||
|
||||
WIN32_FIND_DATAW findData; // indeterminate if hFind == INVALID_HANDLE_VALUE
|
||||
|
||||
// wreaddir will return the address of this member.
|
||||
// (must be stored in WDIR to allow multiple independent
|
||||
// wopendir/wreaddir sequences).
|
||||
struct wdirent ent;
|
||||
|
||||
// used by wreaddir to skip the first FindNextFileW. (a counter is
|
||||
// easy to test/update and also provides useful information.)
|
||||
size_t numCalls;
|
||||
};
|
||||
|
||||
static WDIR wdir_storage;
|
||||
static std::atomic<bool> wdir_in_use{ false };
|
||||
|
||||
static inline WDIR* wdir_alloc()
|
||||
{
|
||||
if(!wdir_in_use.exchange(true)) // gained ownership
|
||||
return &wdir_storage;
|
||||
|
||||
// already in use (rare) - allocate from heap
|
||||
return new WDIR;
|
||||
}
|
||||
|
||||
static inline void wdir_free(WDIR* d)
|
||||
{
|
||||
if(d == &wdir_storage)
|
||||
{
|
||||
const bool ok = wdir_in_use.exchange(false); // relinquish ownership
|
||||
ENSURE(ok); // ensure it wasn't double-freed
|
||||
}
|
||||
else // allocated from heap
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// dirent.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -127,112 +78,6 @@ static bool IsValidDirectory(const OsPath& path)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Return owning pointer or nullptr on error.
|
||||
[[nodiscard]] WDIR* wopendir(const OsPath& path)
|
||||
{
|
||||
WinScopedPreserveLastError s;
|
||||
|
||||
if(!IsValidDirectory(path))
|
||||
{
|
||||
errno = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WDIR* d = wdir_alloc();
|
||||
d->numCalls = 0;
|
||||
|
||||
// NB: "c:\\path" only returns information about that directory;
|
||||
// trailing slashes aren't allowed. append "\\*" to retrieve its entries.
|
||||
OsPath searchPath = path/"*";
|
||||
|
||||
// (we don't defer FindFirstFileW until wreaddir because callers
|
||||
// expect us to return 0 if directory reading will/did fail.)
|
||||
d->hFind = FindFirstFileW(OsString(searchPath).c_str(), &d->findData);
|
||||
if(d->hFind != INVALID_HANDLE_VALUE)
|
||||
return d; // success
|
||||
|
||||
const DWORD nativeError{GetLastError()};
|
||||
if(nativeError == ERROR_NO_MORE_FILES)
|
||||
return d; // success, but directory is empty
|
||||
|
||||
Status status = StatusFromWin();
|
||||
|
||||
// release the WDIR allocated above (this is preferable to
|
||||
// always copying the large WDIR or findData from a temporary)
|
||||
wdir_free(d);
|
||||
|
||||
if(nativeError == ERROR_PATH_NOT_FOUND)
|
||||
// TODO: This should be displayed to the user as a LOGWARNING when this code is moved to ps/
|
||||
debug_printf("The path \"%s\" cannot be found. It is probably a dangling link "
|
||||
"pointing to a non-existent path.\n", path.string8().c_str());
|
||||
else
|
||||
WARN_IF_ERR(status);
|
||||
|
||||
errno = ErrnoFromStatus(status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wdirent* wreaddir(WDIR* d)
|
||||
{
|
||||
// directory is empty and d->findData is indeterminate
|
||||
if(d->hFind == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
WinScopedPreserveLastError s;
|
||||
|
||||
// until end of directory or a valid entry was found:
|
||||
for(;;)
|
||||
{
|
||||
if(d->numCalls++ != 0) // (skip first call to FindNextFileW - see wopendir)
|
||||
{
|
||||
if(!FindNextFileW(d->hFind, &d->findData))
|
||||
{
|
||||
if(GetLastError() == ERROR_NO_MORE_FILES)
|
||||
SetLastError(0);
|
||||
else // unexpected error
|
||||
DEBUG_WARN_ERR(StatusFromWin());
|
||||
return 0; // end of directory or error
|
||||
}
|
||||
}
|
||||
|
||||
// only accept non-hidden and non-system entries - otherwise,
|
||||
// callers might encounter errors when attempting to open them.
|
||||
if((d->findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) == 0)
|
||||
{
|
||||
d->ent.d_name = d->findData.cFileName; // (NB: d_name is a pointer)
|
||||
return &d->ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wreaddir_stat_np(WDIR* d, struct stat* s)
|
||||
{
|
||||
// NTFS stores UTC but FAT stores local times, which are incorrectly
|
||||
// translated to UTC based on the _current_ DST settings. we no longer
|
||||
// bother checking the filesystem, since that's either unreliable or
|
||||
// expensive. timestamps may therefore be off after a DST transition,
|
||||
// which means our cached files would be regenerated.
|
||||
FILETIME* filetime = &d->findData.ftLastWriteTime;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->st_size = (off_t)u64_from_u32(d->findData.nFileSizeHigh, d->findData.nFileSizeLow);
|
||||
s->st_mode = (unsigned short)((d->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG);
|
||||
s->st_mtime = wtime_utc_filetime_to_time_t(filetime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wclosedir(WDIR* d)
|
||||
{
|
||||
FindClose(d->hFind);
|
||||
|
||||
wdir_free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fcntl.h
|
||||
|
|
@ -286,33 +131,6 @@ int wclose(int fd)
|
|||
}
|
||||
|
||||
|
||||
|
||||
int wtruncate(const OsPath& pathname, off_t length)
|
||||
{
|
||||
// (re-open the file to avoid the FILE_FLAG_NO_BUFFERING
|
||||
// sector-alignment restriction)
|
||||
HANDLE hFile = CreateFileW(OsString(pathname).c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
ENSURE(hFile != INVALID_HANDLE_VALUE);
|
||||
LARGE_INTEGER ofs; ofs.QuadPart = length;
|
||||
WARN_IF_FALSE(SetFilePointerEx(hFile, ofs, 0, FILE_BEGIN));
|
||||
WARN_IF_FALSE(SetEndOfFile(hFile));
|
||||
WARN_IF_FALSE(CloseHandle(hFile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wunlink(const OsPath& pathname)
|
||||
{
|
||||
return _wunlink(OsString(pathname).c_str());
|
||||
}
|
||||
|
||||
|
||||
int wrmdir(const OsPath& path)
|
||||
{
|
||||
return _wrmdir(OsString(path).c_str());
|
||||
}
|
||||
|
||||
|
||||
OsPath wrealpath(const OsPath& pathname)
|
||||
{
|
||||
wchar_t resolved[PATH_MAX];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -49,6 +49,7 @@
|
|||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fmt/printf.h>
|
||||
#include <initializer_list>
|
||||
#include <js/Array.h>
|
||||
|
|
@ -56,6 +57,7 @@
|
|||
#include <js/RootingAPI.h>
|
||||
#include <js/TypeDecls.h>
|
||||
#include <js/Value.h>
|
||||
#include <system_error>
|
||||
|
||||
class ScriptInterface;
|
||||
|
||||
|
|
@ -545,7 +547,9 @@ bool ModIo::ParseMods(const ScriptInterface& scriptInterface, std::string& err)
|
|||
|
||||
void ModIo::DeleteDownloadedFile()
|
||||
{
|
||||
if (wunlink(m_DownloadFilePath) != 0)
|
||||
std::error_code ec{};
|
||||
std::filesystem::remove(m_DownloadFilePath.string(), ec);
|
||||
if (ec)
|
||||
LOGERROR("Failed to delete temporary file.");
|
||||
m_DownloadFilePath = OsPath();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,10 +51,12 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <js/RootingAPI.h>
|
||||
#include <js/TypeDecls.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
class ScriptInterface;
|
||||
|
|
@ -343,7 +345,9 @@ bool SavedGames::DeleteSavedGame(const std::wstring& name)
|
|||
return false; // Error
|
||||
|
||||
// Delete actual file
|
||||
if (wunlink(realpath) != 0)
|
||||
std::error_code ec{};
|
||||
std::filesystem::remove(realpath.string(), ec);
|
||||
if (ec)
|
||||
return false; // Error
|
||||
|
||||
// Successfully deleted file
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_quit.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <js/Array.h>
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
#include <js/Value.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -110,7 +112,8 @@ bool VisualReplay::ReadCacheFile(const ScriptInterface& scriptInterface, JS::Mut
|
|||
}
|
||||
|
||||
LOGWARNING("The replay cache file is corrupted, it will be deleted");
|
||||
wunlink(GetCacheFilePath());
|
||||
std::error_code ec{};
|
||||
std::filesystem::remove(GetCacheFilePath().string(), ec);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +126,8 @@ void VisualReplay::StoreCacheFile(const ScriptInterface& scriptInterface, JS::Ha
|
|||
cacheStream << Script::StringifyJSON(rq, &replaysRooted);
|
||||
cacheStream.close();
|
||||
|
||||
wunlink(GetCacheFilePath());
|
||||
std::error_code ec{};
|
||||
std::filesystem::remove(GetCacheFilePath().string(), ec);
|
||||
if (RenameFile(GetTempCacheFilePath(), GetCacheFilePath()))
|
||||
LOGERROR("Could not store the replay cache");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fmt/format.h>
|
||||
#include <js/Array.h>
|
||||
#include <js/PropertyAndElement.h>
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
class ScriptInterface;
|
||||
|
||||
|
|
@ -288,11 +290,15 @@ bool DeleteCampaignSave(const CStrW& filePath)
|
|||
OsPath realPath;
|
||||
if (filePath.Left(16) != L"saves/campaigns/" || filePath.Right(12) != L".0adcampaign")
|
||||
return false;
|
||||
|
||||
return VfsFileExists(filePath) &&
|
||||
g_VFS->GetRealPath(filePath, realPath) == INFO::OK &&
|
||||
g_VFS->RemoveFile(filePath) == INFO::OK &&
|
||||
wunlink(realPath) == 0;
|
||||
if (!VfsFileExists(filePath))
|
||||
return false;
|
||||
if (g_VFS->GetRealPath(filePath, realPath) != INFO::OK)
|
||||
return false;
|
||||
if (g_VFS->RemoveFile(filePath) != INFO::OK)
|
||||
return false;
|
||||
std::error_code ec;
|
||||
std::filesystem::remove(realPath.string(), ec);
|
||||
return !ec;
|
||||
}
|
||||
|
||||
void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq,
|
||||
|
|
|
|||
|
|
@ -703,23 +703,6 @@ void ShadowMap::BindTo(
|
|||
}
|
||||
}
|
||||
|
||||
// Depth texture bits
|
||||
int ShadowMap::GetDepthTextureBits() const
|
||||
{
|
||||
return m->DepthTextureBits;
|
||||
}
|
||||
|
||||
void ShadowMap::SetDepthTextureBits(int bits)
|
||||
{
|
||||
if (bits != m->DepthTextureBits)
|
||||
{
|
||||
m->Texture.reset();
|
||||
m->Width = m->Height = 0;
|
||||
|
||||
m->DepthTextureBits = bits;
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowMap::RenderDebugBounds(Renderer::Backend::IDeviceCommandContext& deviceCommandContext)
|
||||
{
|
||||
// Render various shadow bounds:
|
||||
|
|
|
|||
|
|
@ -47,22 +47,6 @@ public:
|
|||
*/
|
||||
void RecreateTexture();
|
||||
|
||||
/**
|
||||
* GetDepthTextureBits: Return the number of bits to use for depth textures when
|
||||
* enabled.
|
||||
*
|
||||
* @return depth texture bit depth
|
||||
*/
|
||||
int GetDepthTextureBits() const;
|
||||
|
||||
/**
|
||||
* SetDepthTextureBits: Sets the number of bits to use for depth textures when enabled.
|
||||
* Possible values are 16, 24, 32 and 0 (= use default)
|
||||
*
|
||||
* @param bits number of bits
|
||||
*/
|
||||
void SetDepthTextureBits(int bits);
|
||||
|
||||
/**
|
||||
* SetupFrame: Configure light space for the given camera and light direction,
|
||||
* create the shadow texture if necessary, etc.
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
|
|
@ -70,6 +71,7 @@
|
|||
#include <optional>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <system_error>
|
||||
|
||||
class CSimulation2Impl
|
||||
{
|
||||
|
|
@ -321,19 +323,26 @@ void CSimulation2Impl::ReportSerializationFailure(
|
|||
const OsPath path = createDateIndexSubdirectory(psLogDir() / "serializationtest");
|
||||
debug_printf("Writing serializationtest-data to %s\n", path.string8().c_str());
|
||||
|
||||
// Clean up obsolete files from previous runs
|
||||
wunlink(path / "hash.before.a");
|
||||
wunlink(path / "hash.before.b");
|
||||
wunlink(path / "debug.before.a");
|
||||
wunlink(path / "debug.before.b");
|
||||
wunlink(path / "state.before.a");
|
||||
wunlink(path / "state.before.b");
|
||||
wunlink(path / "hash.after.a");
|
||||
wunlink(path / "hash.after.b");
|
||||
wunlink(path / "debug.after.a");
|
||||
wunlink(path / "debug.after.b");
|
||||
wunlink(path / "state.after.a");
|
||||
wunlink(path / "state.after.b");
|
||||
// Try to clean up obsolete files from previous runs.
|
||||
constexpr auto namesToRemove{std::to_array<std::string_view>({
|
||||
"hash.before.a",
|
||||
"hash.before.b",
|
||||
"debug.before.a",
|
||||
"debug.before.b",
|
||||
"state.before.a",
|
||||
"state.before.b",
|
||||
"hash.after.a",
|
||||
"hash.after.b",
|
||||
"debug.after.a",
|
||||
"debug.after.b",
|
||||
"state.after.a",
|
||||
"state.after.b",
|
||||
})};
|
||||
|
||||
const std::filesystem::path fspath{path.string()};
|
||||
std::error_code ec{};
|
||||
for (const std::string_view nameToRemove : namesToRemove)
|
||||
std::filesystem::remove(fspath / nameToRemove, ec);
|
||||
|
||||
if (primaryStateBefore)
|
||||
DumpSerializationTestState(*primaryStateBefore, path, L"before.a");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class MockPathfinderTerrMan : public ICmpPathfinder
|
||||
class MockPathfinderTerrManager : public ICmpPathfinder
|
||||
{
|
||||
public:
|
||||
DEFAULT_MOCK_COMPONENT()
|
||||
|
|
@ -64,38 +64,38 @@ public:
|
|||
// Test data
|
||||
Grid<NavcellData> m_PassabilityGrid;
|
||||
|
||||
virtual pass_class_t GetPassabilityClass(const std::string&) const override { return 0; }
|
||||
virtual const Grid<NavcellData>& GetPassabilityGrid() override { return m_PassabilityGrid; }
|
||||
pass_class_t GetPassabilityClass(const std::string&) const override { return 0; }
|
||||
const Grid<NavcellData>& GetPassabilityGrid() override { return m_PassabilityGrid; }
|
||||
|
||||
// Irrelevant part of the mock.
|
||||
virtual void GetPassabilityClasses(std::map<std::string, pass_class_t>&) const override {}
|
||||
virtual void GetPassabilityClasses(std::map<std::string, pass_class_t>&, std::map<std::string, pass_class_t>&) const override {}
|
||||
virtual entity_pos_t GetClearance(pass_class_t) const override { return entity_pos_t::FromInt(1); }
|
||||
virtual entity_pos_t GetMaximumClearance() const override { return entity_pos_t::FromInt(1); }
|
||||
virtual const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const override { static GridUpdateInformation gridInfo; return gridInfo; }
|
||||
virtual void FlushAIPathfinderDirtinessInformation() override {}
|
||||
virtual Grid<u16> ComputeShoreGrid(bool = false) override { return Grid<u16> {}; }
|
||||
virtual u32 ComputePathAsync(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, entity_id_t) override { return 1; }
|
||||
virtual void ComputePathImmediate(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, WaypointPath&) const override {}
|
||||
virtual u32 ComputeShortPathAsync(entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, bool, entity_id_t, entity_id_t) override { return 1; }
|
||||
virtual WaypointPath ComputeShortPathImmediate(const ShortPathRequest&) const override { return WaypointPath(); }
|
||||
virtual void SetDebugPath(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t) override {}
|
||||
virtual bool IsGoalReachable(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t) override { return false; }
|
||||
virtual std::vector<CFixedVector2D> DistributeAround(std::vector<entity_id_t>, entity_pos_t, entity_pos_t) const override { return {}; }
|
||||
virtual bool CheckMovement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, pass_class_t) const override { return false; }
|
||||
virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, pass_class_t, bool = false) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_id_t, pass_class_t) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_id_t, pass_class_t, bool) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
virtual void SetDebugOverlay(bool) override {}
|
||||
virtual void SetHierDebugOverlay(bool) override {}
|
||||
virtual void SendRequestedPaths() override {}
|
||||
virtual void StartProcessingMoves(bool) override {}
|
||||
virtual void UpdateGrid() override {}
|
||||
virtual void GetDebugData(u32&, double&, Grid<u8>&) const override {}
|
||||
virtual void SetAtlasOverlay(bool, pass_class_t = 0) override {}
|
||||
void GetPassabilityClasses(std::map<std::string, pass_class_t>&) const override {}
|
||||
void GetPassabilityClasses(std::map<std::string, pass_class_t>&, std::map<std::string, pass_class_t>&) const override {}
|
||||
entity_pos_t GetClearance(pass_class_t) const override { return entity_pos_t::FromInt(1); }
|
||||
entity_pos_t GetMaximumClearance() const override { return entity_pos_t::FromInt(1); }
|
||||
const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const override { static GridUpdateInformation gridInfo; return gridInfo; }
|
||||
void FlushAIPathfinderDirtinessInformation() override {}
|
||||
Grid<u16> ComputeShoreGrid(bool = false) override { return Grid<u16> {}; }
|
||||
u32 ComputePathAsync(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, entity_id_t) override { return 1; }
|
||||
void ComputePathImmediate(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, WaypointPath&) const override {}
|
||||
u32 ComputeShortPathAsync(entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t, bool, entity_id_t, entity_id_t) override { return 1; }
|
||||
WaypointPath ComputeShortPathImmediate(const ShortPathRequest&) const override { return WaypointPath(); }
|
||||
void SetDebugPath(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t) override {}
|
||||
bool IsGoalReachable(entity_pos_t, entity_pos_t, const PathGoal&, pass_class_t) override { return false; }
|
||||
std::vector<CFixedVector2D> DistributeAround(std::vector<entity_id_t>, entity_pos_t, entity_pos_t) const override { return {}; }
|
||||
bool CheckMovement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, pass_class_t) const override { return false; }
|
||||
ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, pass_class_t, bool = false) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_id_t, pass_class_t) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter&, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t, entity_id_t, pass_class_t, bool) const override { return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
|
||||
void SetDebugOverlay(bool) override {}
|
||||
void SetHierDebugOverlay(bool) override {}
|
||||
void SendRequestedPaths() override {}
|
||||
void StartProcessingMoves(bool) override {}
|
||||
void UpdateGrid() override {}
|
||||
void GetDebugData(u32&, double&, Grid<u8>&) const override {}
|
||||
void SetAtlasOverlay(bool, pass_class_t = 0) override {}
|
||||
};
|
||||
|
||||
class MockPlayerMgrTerrMan : public ICmpPlayerManager
|
||||
class MockPlayerMgrTerrManager : public ICmpPlayerManager
|
||||
{
|
||||
public:
|
||||
DEFAULT_MOCK_COMPONENT()
|
||||
|
|
@ -104,7 +104,7 @@ public:
|
|||
entity_id_t GetPlayerByID(int32_t id) override { return id + 1; }
|
||||
};
|
||||
|
||||
class MockTerrInfTerrMan : public ICmpTerritoryInfluence
|
||||
class MockTerrInfTerrManager : public ICmpTerritoryInfluence
|
||||
{
|
||||
public:
|
||||
DEFAULT_MOCK_COMPONENT()
|
||||
|
|
@ -116,7 +116,7 @@ public:
|
|||
u32 m_Radius = 0;
|
||||
};
|
||||
|
||||
class MockOwnershipTerrMan : public ICmpOwnership
|
||||
class MockOwnershipTerrManager : public ICmpOwnership
|
||||
{
|
||||
public:
|
||||
DEFAULT_MOCK_COMPONENT()
|
||||
|
|
@ -126,7 +126,7 @@ public:
|
|||
void SetOwnerQuiet(player_id_t) override {};
|
||||
};
|
||||
|
||||
class MockPositionTerrMan : public ICmpPosition
|
||||
class MockPositionTerrManager : public ICmpPosition
|
||||
{
|
||||
public:
|
||||
DEFAULT_MOCK_COMPONENT()
|
||||
|
|
@ -195,19 +195,19 @@ public:
|
|||
ComponentTestHelper test(*g_ScriptContext);
|
||||
ICmpTerritoryManager* cmp = test.Add<ICmpTerritoryManager>(CID_TerritoryManager, "", SYSTEM_ENTITY);
|
||||
|
||||
MockPathfinderTerrMan pathfinder;
|
||||
MockPathfinderTerrManager pathfinder;
|
||||
test.AddMock(SYSTEM_ENTITY, IID_Pathfinder, pathfinder);
|
||||
|
||||
MockPlayerMgrTerrMan playerMan;
|
||||
MockPlayerMgrTerrManager playerMan;
|
||||
test.AddMock(SYSTEM_ENTITY, IID_PlayerManager, playerMan);
|
||||
|
||||
pathfinder.m_PassabilityGrid.resize(ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE * 5, ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE * 5);
|
||||
|
||||
MockTerrInfTerrMan terrInf;
|
||||
MockTerrInfTerrManager terrInf;
|
||||
test.AddMock(5, IID_TerritoryInfluence, terrInf);
|
||||
MockOwnershipTerrMan ownership;
|
||||
MockOwnershipTerrManager ownership;
|
||||
test.AddMock(5, IID_Ownership, ownership);
|
||||
MockPositionTerrMan position;
|
||||
MockPositionTerrManager position;
|
||||
test.AddMock(5, IID_Position, position);
|
||||
|
||||
position.m_Pos = CFixedVector3D(
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public:
|
|||
protected:
|
||||
void NotifyFinishedOwnCommands(u32 turn) override;
|
||||
|
||||
virtual void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) override;
|
||||
void NotifyFinishedUpdate(u32 turn, const UpdateCallback& sendEventToAll) override;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_LOCALTURNMANAGER
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,7 +18,9 @@
|
|||
#include "AtlasObject.h"
|
||||
#include "AtlasObjectImpl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#define ATSMARTPTR_IMPL(T) \
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#include "AtlasObject.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Avoid complaints about unreachable code; the optimiser is realising
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
#include "tools/atlas/AtlasObject/AtlasObject.h"
|
||||
#include "tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
class ActorEditorListCtrl;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -31,7 +31,6 @@
|
|||
#include <vector>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/toolbar.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/toolbar.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <wx/button.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/toolbar.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -15,7 +15,6 @@
|
|||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/glcanvas.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -22,7 +22,6 @@
|
|||
#include <wx/chartype.h>
|
||||
#include <wx/colourdata.h>
|
||||
#include <wx/config.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/regex.h>
|
||||
|
||||
class wxWindow;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
#include "tools/atlas/AtlasUI/CustomControls/EditableListCtrl/EditableListCtrl.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/string.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -19,7 +19,6 @@
|
|||
#include "tools/atlas/AtlasUI/General/AtlasWindowCommand.h"
|
||||
|
||||
#include <vector>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/object.h>
|
||||
|
||||
class DraggableListCtrl;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,18 +18,16 @@
|
|||
#ifndef INCLUDED_EDITABLELISTCTRL
|
||||
#define INCLUDED_EDITABLELISTCTRL
|
||||
|
||||
#include "tools/atlas/AtlasObject/AtlasObject.h"
|
||||
#include "tools/atlas/AtlasUI/General/IAtlasSerialiser.h"
|
||||
|
||||
#include <vector>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/toolbar.h>
|
||||
#include <wx/validate.h>
|
||||
|
||||
class AtIter;
|
||||
class AtObj;
|
||||
class FieldEditCtrl;
|
||||
class wxPoint;
|
||||
class wxRect;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -19,12 +19,10 @@
|
|||
#include "tools/atlas/AtlasUI/General/AtlasWindowCommand.h"
|
||||
|
||||
#include <vector>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
class EditableListCtrl;
|
||||
class wxClassInfo;
|
||||
|
||||
class EditCommand_Dialog : public AtlasWindowCommand
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
#include <wx/colordlg.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/regex.h>
|
||||
#include <wx/window.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/string.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/validate.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -15,13 +15,11 @@
|
|||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/validate.h>
|
||||
|
||||
class wxButton;
|
||||
class wxClassInfo;
|
||||
class wxRect;
|
||||
class wxString;
|
||||
class wxTextCtrl;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -15,7 +15,6 @@
|
|||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/validate.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
#ifndef INCLUDED_MAPDIALOG
|
||||
#define INCLUDED_MAPDIALOG
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/string.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -24,7 +24,6 @@
|
|||
#include "tools/atlas/GameInterface/Messages.h"
|
||||
#include "tools/atlas/GameInterface/Shareable.h"
|
||||
|
||||
#include <string>
|
||||
#include <wx/button.h>
|
||||
#include <wx/clntdata.h>
|
||||
#include <wx/gdicmn.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
#ifndef INCLUDED_MAPRESIZEDIALOG
|
||||
#define INCLUDED_MAPRESIZEDIALOG
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -31,7 +31,6 @@
|
|||
#include <wx/colour.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <wx/dcgraph.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/graphics.h>
|
||||
#include <wx/mousestate.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/image.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -15,7 +15,6 @@
|
|||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/splitter.h>
|
||||
#include <wx/string.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
#include <wx/arrstr.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dynarray.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/string.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -21,12 +21,10 @@
|
|||
#include "tools/atlas/AtlasUI/General/AtlasWindowCommandProc.h"
|
||||
#include "tools/atlas/AtlasUI/General/IAtlasSerialiser.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/object.h>
|
||||
|
||||
class wxClassInfo;
|
||||
class wxPanel;
|
||||
class wxSize;
|
||||
class wxString;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -25,12 +25,11 @@
|
|||
#include "tools/atlas/AtlasUI/General/AtlasWindowCommandProc.h"
|
||||
#include "tools/atlas/AtlasUI/General/Datafile.h"
|
||||
|
||||
#include <boost/signals2/optional_last_value.hpp>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/bmpbndl.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/config.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -22,16 +22,13 @@
|
|||
#include "tools/atlas/AtlasUI/General/AtlasWindowCommandProc.h"
|
||||
#include "tools/atlas/AtlasUI/General/IAtlasSerialiser.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxClassInfo;
|
||||
class wxMenu;
|
||||
class wxMenuBar;
|
||||
class wxMenuItem;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -22,12 +22,10 @@
|
|||
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/cmdproc.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/object.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
class IAtlasSerialiser;
|
||||
class wxClassInfo;
|
||||
|
||||
class AtlasWindowCommand : public wxCommand
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -34,7 +34,6 @@
|
|||
#include <wx/cmdargs.h>
|
||||
#include <wx/config.h>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/file.h>
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/filename.h>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
#include "KeyMap.h"
|
||||
|
||||
#include <SDL_keycode.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
int GetSDLKeyFromWxKeyCode(int wxkey)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -40,7 +40,6 @@
|
|||
#include "tools/atlas/GameInterface/SharedTypes.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <wx/busyinfo.h>
|
||||
|
|
@ -174,6 +173,12 @@ private:
|
|||
if (KeyScroll(evt, true))
|
||||
return;
|
||||
|
||||
if (evt.GetKeyCode() == 'B')
|
||||
{
|
||||
POST_MESSAGE(ToggleBirdsEyeView, ());
|
||||
return;
|
||||
}
|
||||
|
||||
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), true));
|
||||
|
||||
evt.Skip();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/icon.h>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.h"
|
||||
#include "tools/atlas/AtlasUI/ScenarioEditor/Sections/Player/Player.h"
|
||||
#include "tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h"
|
||||
#include "tools/atlas/AtlasUI/ScenarioEditor/StyleSheet.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
|
@ -37,7 +38,6 @@
|
|||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/gdicmn.h>
|
||||
|
|
@ -310,10 +310,10 @@ void SectionLayout::Build(ScenarioEditor& scenarioEditor)
|
|||
|
||||
#undef ADD_SIDEBAR
|
||||
|
||||
m_VertSplitter->SetDefaultSashPosition(-BOTTOMBAR_SIZE);
|
||||
m_VertSplitter->SetDefaultSashPosition(-Atlas::Style::BOTTOMBAR_DEFAULT_SIZE);
|
||||
m_VertSplitter->Initialize(m_Canvas);
|
||||
|
||||
m_HorizSplitter->SetDefaultSashPosition(SIDEBAR_SIZE);
|
||||
m_HorizSplitter->SetDefaultSashPosition(Atlas::Style::SIDEBAR_DEFAULT_SIZE);
|
||||
m_HorizSplitter->SplitVertically(m_SidebarBook, m_VertSplitter);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,18 +27,6 @@ class SnapSplitterWindow;
|
|||
class wxString;
|
||||
class wxWindow;
|
||||
|
||||
// Some platform dependent sizes
|
||||
#if defined(__WXGTK__)
|
||||
#define SIDEBAR_SIZE 285
|
||||
#define BOTTOMBAR_SIZE 200
|
||||
#elif defined(__WXOSX__) || defined(__WXMAC__)
|
||||
#define SIDEBAR_SIZE 285
|
||||
#define BOTTOMBAR_SIZE 210
|
||||
#else // __MSW__
|
||||
#define SIDEBAR_SIZE 235
|
||||
#define BOTTOMBAR_SIZE 180
|
||||
#endif
|
||||
|
||||
class SectionLayout
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
class ScenarioEditor;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
#include "Sidebar.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@
|
|||
#include "tools/atlas/GameInterface/Shareable.h"
|
||||
#include "tools/atlas/GameInterface/SharedTypes.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <numbers>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include "tools/atlas/AtlasUI/General/Observable.h"
|
||||
#include "tools/atlas/AtlasUI/ScenarioEditor/Sections/Common/Sidebar.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
class ScenarioEditor;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -25,11 +25,9 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/image.h>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue