Make rallypoints moddable.

Allow use of {civ} tags in templates to simplify mod dependencies and inheritance.

Reviewed-On: #8038
Reviewed-By: @phosit
This commit is contained in:
Stan 2025-06-14 22:03:01 +02:00
parent 92ef4ffa19
commit 03f7903fec
No known key found for this signature in database
GPG key ID: 244943DFF8370D60
41 changed files with 420 additions and 166 deletions

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Athenian Waypoint Flag">
<textures>
<texture file="props/banner_greek.png" name="baseTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Britonnic Waypoint Flag">
<textures>
<texture file="props/banner_celt.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Carthaginian Waypoint Flag">
<textures>
<texture file="props/banner_carthage.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Gaul Waypoint Flag">
<textures>
<texture file="props/banner_celt.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Han Waypoint Flag">
<textures>
<texture file="props/banner_han.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Iberian Waypoint Flag">
<textures>
<texture file="props/banner_iberians.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Kush Waypoint Flag">
<textures>
<texture file="props/banner_kushites.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Macedonians Waypoint Flag">
<textures>
<texture file="props/banner_macedonians.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Mauryan Waypoint Flag">
<textures>
<texture file="props/banner_mauryas.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Pers Waypoint Flag">
<textures>
<texture file="props/banner_persian.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Ptolemaic Waypoint Flag">
<textures>
<texture file="props/banner_ptolemies.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Roman Waypoint Flag">
<textures>
<texture file="props/banner_romans.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Seleucid Waypoint Flag">
<textures>
<texture file="props/banner_seleucids.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant file="others/waypoints/base.xml" frequency="1" name="Spartan Waypoint Flag">
<textures>
<texture file="props/banner_spartans.png" name="baseTex"/>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<actor version="1">
<castshadow/>
<float/>
<group>
<variant frequency="100">
<animations>
<animation file="mechanical/waypoint_flag_idle.dae" name="Idle" speed="30"/>
</animations>
<mesh>props/waypoint_flag.dae</mesh>
<textures>
<texture file="default_norm.png" name="normTex"/>
<texture file="null_black.dds" name="specTex"/>
</textures>
</variant>
</group>
<group>
<variant name="athen">
<textures>
<texture file="props/banner_athenians.png" name="baseTex"/>
</textures>
</variant>
<variant name="brit">
<textures>
<texture file="props/banner_celt.png" name="baseTex"/>
</textures>
</variant>
<variant name="cart">
<textures>
<texture file="props/banner_carthage.png" name="baseTex"/>
</textures>
</variant>
<variant name="celt">
<textures>
<texture file="props/banner_celt.png" name="baseTex"/>
</textures>
</variant>
<variant name="gaul">
<textures>
<texture file="props/banner_celt.png" name="baseTex"/>
</textures>
</variant>
<variant name="han">
<textures>
<texture file="props/banner_han.png" name="baseTex"/>
</textures>
</variant>
<variant name="hele">
<textures>
<texture file="props/banner_greek.png" name="baseTex"/>
</textures>
</variant>
<variant name="iber">
<textures>
<texture file="props/banner_iberians.png" name="baseTex"/>
</textures>
</variant>
<variant name="kush">
<textures>
<texture file="props/banner_kushites.png" name="baseTex"/>
</textures>
</variant>
<variant name="mace">
<textures>
<texture file="props/banner_macedonians.png" name="baseTex"/>
</textures>
</variant>
<variant name="maur">
<textures>
<texture file="props/banner_mauryas.png" name="baseTex"/>
</textures>
</variant>
<variant name="pers">
<textures>
<texture file="props/banner_persian.png" name="baseTex"/>
</textures>
</variant>
<variant name="ptol">
<textures>
<texture file="props/banner_ptolemies.png" name="baseTex"/>
</textures>
</variant>
<variant name="rome">
<textures>
<texture file="props/banner_romans.png" name="baseTex"/>
</textures>
</variant>
<variant name="sele">
<textures>
<texture file="props/banner_seleucids.png" name="baseTex"/>
</textures>
</variant>
<variant name="spart">
<textures>
<texture file="props/banner_spartans.png" name="baseTex"/>
</textures>
</variant>
</group>
<material>basic_trans_norm_spec.xml</material>
</actor>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<variant name="Base">
<animations>
<animation file="mechanical/waypoint_flag_idle.dae" name="Idle" speed="30" />
</animations>
<mesh>props/waypoint_flag.dae</mesh>
<textures>
<texture file="default_norm.png" name="normTex" />
<texture file="null_black.dds" name="specTex" />
</textures>
</variant>

View file

@ -161,7 +161,7 @@ export function* generateMap()
"units/gaul/infantry_slinger_b",
"units/gaul/infantry_javelineer_b",
"units/gaul/champion_fanatic",
"actor|props/special/common/waypoint_flag.xml",
"actor|props/special/common/waypoint_flag_factions.xml",
"actor|props/special/eyecandy/barrel_a.xml",
"actor|props/special/eyecandy/basket_celt_a.xml",
"actor|props/special/eyecandy/crate_a.xml",

View file

@ -28,7 +28,7 @@ export function* generateMap(mapSettings)
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const aWaypointFlag = "actor|props/special/common/waypoint_flag.xml";
const aWaypointFlag = "actor|props/special/common/waypoint_flag_factions.xml";
const pForest1 = [
tForestFloor2 + TERRAIN_SEPARATOR + oTree1,

View file

@ -272,7 +272,7 @@
"campEntities": [
"gaia/treasure/metal",
"gaia/treasure/standing_stone",
"actor|props/special/common/waypoint_flag.xml",
"actor|props/special/common/waypoint_flag_factions.xml",
"actor|props/special/eyecandy/barrel_a.xml",
"actor|props/special/eyecandy/basket_celt_a.xml",
"actor|props/special/eyecandy/crate_a.xml",

View file

@ -1,9 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/actor">
<Identity>
<Civ>gaia</Civ>
<GenericName>Rally point flag</GenericName>
<Undeletable>true</Undeletable>
<Icon/>
</Identity>
<Visibility>
<AlwaysVisible>true</AlwaysVisible>
</Visibility>
<VisualActor>
<Actor>props/special/common/waypoint_flag.xml</Actor>
<Actor>props/special/common/{civ}_waypoint_flag.xml</Actor>
</VisualActor>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>athen</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>brit</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>cart</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>gaul</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>han</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>iber</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>kush</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>mace</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>maur</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>pers</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>ptol</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>rome</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>sele</Civ>
</Identity>
</Entity>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="special/rallypoint">
<Identity>
<Civ>spart</Civ>
</Identity>
</Entity>

View file

@ -79,7 +79,7 @@
</Position>
<RallyPoint/>
<RallyPointRenderer>
<MarkerTemplate>special/rallypoint</MarkerTemplate>
<MarkerTemplate>special/rallypoints/{civ}</MarkerTemplate>
<LineTexture>art/textures/misc/rallypoint_line.png</LineTexture>
<LineTextureMask>art/textures/misc/rallypoint_line_mask.png</LineTextureMask>
<LineThickness>0.25</LineThickness>

View file

@ -35,7 +35,7 @@
<VisualActor>
<SilhouetteDisplay>false</SilhouetteDisplay>
<SilhouetteOccluder>true</SilhouetteOccluder>
<Actor>props/special/common/waypoint_flag.xml</Actor>
<Actor>props/special/common/waypoint_flag_factions.xml</Actor>
<VisibleInAtlasOnly>true</VisibleInAtlasOnly>
</VisualActor>
</Entity>

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2024 Wildfire Games.
/* Copyright (C) 2025 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,10 @@
#ifndef ALGORITHM_H
#define ALGORITHM_H
#include <algorithm>
#include <string>
#include <string_view>
namespace PS
{
/**
@ -34,6 +38,27 @@ bool contains(Range&& range, const T& value)
return elem == value;
});
}
/**
* @brief Replaces all occurrences of a substring within a string with a given value.
*
* This function searches the input string `base` for all instances of the specified
* `tag` and replaces them with the provided `value`. The replacement is performed
* in-place and modifies the original string.
*
* @param base The string in which to perform replacements. Modified in-place.
* @param tag The substring to search for (e.g., a placeholder like L"{civ}").
* @param value The string to replace each occurrence of `tag` with.
*/
inline void ReplaceSubrange(std::wstring& base, std::wstring_view tag, std::wstring_view value)
{
size_t pos = 0;
while ((pos = base.find(tag, pos)) != std::wstring::npos)
{
base.replace(pos, tag.length(), value);
pos += value.length();
}
}
} // namespace PS
#endif // ALGORITHM_H

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2025 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,9 @@
#include "precompiled.h"
#include "CCmpRallyPointRenderer.h"
#include "ICmpIdentity.h"
#include "ps/algorithm.h"
#include "ps/Profile.h"
#include "simulation2/components/ICmpRangeManager.h"
#include "simulation2/helpers/Los.h"
@ -218,69 +220,71 @@ void CCmpRallyPointRenderer::UpdateMessageSubscriptions()
GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, m_Displayed && IsSet());
}
void CCmpRallyPointRenderer::CreateMarkerEntity(size_t index, player_id_t ownerId)
{
if (m_MarkerTemplate.empty() || ownerId == INVALID_PLAYER)
return;
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
if (!cmpPlayerManager)
return;
CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId));
if (!cmpPlayer)
return;
CmpPtr<ICmpIdentity> cmpIdentity(GetSimContext(), cmpPlayer->GetEntityId());
if (!cmpIdentity)
return;
// Create a copy we do not want to alter the marker template.
std::wstring markerTemplate = m_MarkerTemplate;
PS::ReplaceSubrange(markerTemplate, L"{civ}", cmpIdentity->GetCiv());
CComponentManager& componentMgr = GetSimContext().GetComponentManager();
entity_id_t newMarker = componentMgr.AllocateNewLocalEntity();
if (newMarker != INVALID_ENTITY)
newMarker = componentMgr.AddEntity(markerTemplate, newMarker);
m_MarkerEntityIds[index] = newMarker;
}
void CCmpRallyPointRenderer::UpdateMarkers()
{
player_id_t previousOwner = m_LastOwner;
CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
const player_id_t ownerId{cmpOwnership ? cmpOwnership->GetOwner() : 0};
for (size_t i = 0; i < m_RallyPoints.size(); ++i)
{
if (i >= m_MarkerEntityIds.size())
m_MarkerEntityIds.push_back(INVALID_ENTITY);
if (m_MarkerEntityIds[i] == INVALID_ENTITY)
{
// No marker exists yet, create one first
CComponentManager& componentMgr = GetSimContext().GetComponentManager();
CreateMarkerEntity(i, ownerId);
// Allocate a new entity for the marker
if (!m_MarkerTemplate.empty())
{
m_MarkerEntityIds[i] = componentMgr.AllocateNewLocalEntity();
if (m_MarkerEntityIds[i] != INVALID_ENTITY)
m_MarkerEntityIds[i] = componentMgr.AddEntity(m_MarkerTemplate, m_MarkerEntityIds[i]);
}
}
// The marker entity should be valid at this point, otherwise something went wrong trying to allocate it
if (m_MarkerEntityIds[i] == INVALID_ENTITY)
{
LOGERROR("Failed to create rally point marker entity");
continue;
}
CmpPtr<ICmpPosition> markerCmpPosition(GetSimContext(), m_MarkerEntityIds[i]);
if (markerCmpPosition)
{
if (m_Displayed && IsSet())
{
markerCmpPosition->MoveTo(m_RallyPoints[i].X, m_RallyPoints[i].Y);
}
else
{
markerCmpPosition->MoveOutOfWorld();
}
}
// Set rally point flag selection based on player civilization
CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
if (!cmpOwnership)
continue;
player_id_t ownerId = cmpOwnership->GetOwner();
if (ownerId == INVALID_PLAYER || (ownerId == previousOwner && m_LastMarkerCount >= i))
continue;
m_LastOwner = ownerId;
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
// cmpPlayerManager should not be null as long as this method is called on-demand instead of at Init() time
// (we can't rely on component initialization order in Init())
if (!cmpPlayerManager)
continue;
CmpPtr<ICmpIdentity> cmpIdentity(GetSimContext(), cmpPlayerManager->GetPlayerByID(ownerId));
if (!cmpIdentity)
continue;
CmpPtr<ICmpVisual> cmpVisualActor(GetSimContext(), m_MarkerEntityIds[i]);
if (cmpVisualActor)
cmpVisualActor->SetVariant("civ", CStrW(cmpIdentity->GetCiv()).ToUTF8());
}
m_LastMarkerCount = m_RallyPoints.size() - 1;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -194,6 +194,14 @@ private:
*/
void UpdateMarkers();
/**
* @brief Creates a rally point marker entity for the specified index and owner.
*
* @param index The index in the rally point list for which to create a marker.
* @param ownerId The ID of the player who currently owns the entity.
*/
void CreateMarkerEntity(size_t index, player_id_t ownerId);
/**
* Recomputes all the full paths from this entity to the rally point and from the rally point to the next, and does all the necessary
* post-processing to make them prettier.

View file

@ -27,6 +27,8 @@
#include "ICmpIdentity.h"
#include "ICmpMirage.h"
#include "ICmpOwnership.h"
#include "ICmpPlayer.h"
#include "ICmpPlayerManager.h"
#include "ICmpPosition.h"
#include "ICmpTemplateManager.h"
#include "ICmpTerrain.h"
@ -47,6 +49,7 @@
#include "maths/Frustum.h"
#include "maths/Matrix3D.h"
#include "maths/Vector3D.h"
#include "ps/algorithm.h"
#include "ps/CLogger.h"
#include "ps/GameSetup/Config.h"
#include "renderer/Scene.h"
@ -560,7 +563,7 @@ public:
}
private:
// Replace {phenotype} with the correct value in m_ActorName
// Replace {phenotype} and {civ} with the correct value in m_ActorName
void ParseActorName(std::wstring base);
/// Helper function shared by component init and actor reloading
@ -583,18 +586,13 @@ REGISTER_COMPONENT_TYPE(VisualActor)
void CCmpVisualActor::ParseActorName(std::wstring base)
{
CmpPtr<ICmpIdentity> cmpIdentity(GetEntityHandle());
const std::wstring pattern = L"{phenotype}";
if (cmpIdentity)
{
size_t pos = base.find(pattern);
while (pos != std::string::npos)
{
base.replace(pos, pattern.size(), cmpIdentity->GetPhenotype());
pos = base.find(pattern, pos + pattern.size());
}
PS::ReplaceSubrange(base, L"{phenotype}", cmpIdentity->GetPhenotype());
PS::ReplaceSubrange(base, L"{civ}", cmpIdentity->GetCiv());
}
m_ActorName = base;
m_ActorName = std::move(base);
}
void CCmpVisualActor::InitModel()

View file

@ -340,22 +340,32 @@ class CheckRefs:
and entity.find("VisualActor").find("Actor") is not None
and entity.find("Identity") is not None
):
phenotype_tag = entity.find("Identity").find("Phenotype")
phenotypes = (
phenotype_tag.text.split()
if (phenotype_tag is not None and phenotype_tag.text)
else ["default"]
)
cmp_identity = entity.find("Identity")
actor = entity.find("VisualActor").find("Actor")
if "{phenotype}" in actor.text:
for phenotype in phenotypes:
# See simulation2/components/CCmpVisualActor.cpp and Identity.js
# for explanation.
actor_path = actor.text.replace("{phenotype}", phenotype)
self.deps.append((fp, Path(f"art/actors/{actor_path}")))
if cmp_identity is not None:
actor_path = actor.text
if "{civ}" in actor_path:
civ_tag = cmp_identity.find("Civ")
civ = civ_tag.text if civ_tag is not None else "gaia"
actor_path = actor_path.replace("{civ}", civ)
if "{phenotype}" in actor_path:
phenotype_tag = cmp_identity.find("Phenotype")
phenotypes = (
phenotype_tag.text.split()
if (phenotype_tag is not None and phenotype_tag.text)
else ["default"]
)
for phenotype in phenotypes:
# See simulation2/components/CCmpVisualActor.cpp and Identity.js
# for explanation.
phenotype_path = actor_path.replace("{phenotype}", phenotype)
self.deps.append((fp, Path(f"art/actors/{phenotype_path}")))
else:
actor_path = actor.text
self.deps.append((fp, Path(f"art/actors/{actor_path}")))
foundation_actor = entity.find("VisualActor").find("FoundationActor")
if foundation_actor is not None:
self.deps.append((fp, Path(f"art/actors/{foundation_actor.text}")))