Index: source/simulation2/components/CCmpVisualActor.cpp =================================================================== --- source/simulation2/components/CCmpVisualActor.cpp +++ source/simulation2/components/CCmpVisualActor.cpp @@ -39,6 +39,7 @@ #include "graphics/Decal.h" #include "graphics/Frustum.h" #include "graphics/Model.h" +#include "graphics/ModelDef.h" #include "graphics/ObjectBase.h" #include "graphics/ObjectEntry.h" #include "graphics/Unit.h" @@ -86,6 +87,11 @@ fixed m_AnimSyncOffsetTime; std::map m_VariantSelections; + /** + * Can be used to retrieve special locations given by the artists + * to place actors with precision on this actor. + */ + std::vector m_PropPointsPositions; u32 m_Seed; // seed used for random variations @@ -448,6 +454,8 @@ return m_AnimName; } + virtual std::vector GetPropPoints() const; + virtual void SelectAnimation(const std::string& name, bool once = false, fixed speed = fixed::FromInt(1)) { m_AnimName = name; @@ -467,7 +475,7 @@ if (!m_Unit || !m_Unit->GetAnimation() || !m_Unit->GetID()) return; - m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed.ToFloat(), m_AnimDesync.ToFloat(), m_SoundGroup.c_str()); + m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed.ToFloat(), m_AnimDesync.ToFloat(), m_SoundGroup.c_str()); } virtual void SelectMovementAnimation(const std::string& name, fixed speed) @@ -651,6 +659,24 @@ // the model is now responsible for cleaning up the descriptor if (m_ShapeDescriptor != nullptr) m_Unit->GetModel().SetCustomSelectionShape(m_ShapeDescriptor); + + if (m_Unit == nullptr || m_Unit->GetModel().ToCModel() == nullptr) + return; + + std::vector& props = m_Unit->GetModel().ToCModel()->GetModelDef()->m_PropPoints; + m_PropPointsPositions.reserve(props.size()); + for (const SPropPoint& prop : props) + { + JsProp jsProp; + jsProp.m_Name = prop.m_Name.EscapeToPrintableASCII(); + jsProp.m_Position = CFixedVector3D( + fixed::FromFloat(prop.m_Position.X), + fixed::FromFloat(prop.m_Position.Y), + fixed::FromFloat(prop.m_Position.Z) + ); + + m_PropPointsPositions.emplace_back(jsProp); + } } void CCmpVisualActor::InitSelectionShapeDescriptor(const CParamNode& paramNode) @@ -775,3 +801,8 @@ if (!m_AnimSyncOffsetTime.IsZero()) m_Unit->GetAnimation()->SetAnimationSyncOffset(m_AnimSyncOffsetTime.ToFloat()); } + +std::vector CCmpVisualActor::GetPropPoints() const +{ + return m_PropPointsPositions; +} Index: source/simulation2/components/ICmpVisual.h =================================================================== --- source/simulation2/components/ICmpVisual.h +++ source/simulation2/components/ICmpVisual.h @@ -27,8 +27,19 @@ #include "maths/FixedVector3D.h" #include "lib/file/vfs/vfs_path.h" +#include +#include +#include + class CUnit; + +struct JsProp +{ + std::string m_Name; + CFixedVector3D m_Position; +}; + /** * The visual representation of an entity (typically an actor). */ @@ -75,6 +86,13 @@ virtual CFixedVector3D GetProjectileLaunchPoint() const = 0; /** + * Return all the prop points an entity currently have with their location + * Return type is CFixedVector3D because it is exposed to the JS interface. + * Returns (0,0,0) if no point can be found. + */ + virtual std::vector GetPropPoints() const = 0; + + /** * Returns the underlying unit of this visual actor. May return NULL to indicate that no unit exists (e.g. may happen if the * game is started without graphics rendering). * Originally intended for introspection purposes in Atlas; for other purposes, consider using a specialized getter first. Index: source/simulation2/components/ICmpVisual.cpp =================================================================== --- source/simulation2/components/ICmpVisual.cpp +++ source/simulation2/components/ICmpVisual.cpp @@ -26,6 +26,7 @@ DEFINE_INTERFACE_METHOD_CONST_0("GetAnimationName", std::string, ICmpVisual, GetAnimationName) DEFINE_INTERFACE_METHOD_CONST_0("GetProjectileActor", std::wstring, ICmpVisual, GetProjectileActor) DEFINE_INTERFACE_METHOD_CONST_0("GetProjectileLaunchPoint", CFixedVector3D, ICmpVisual, GetProjectileLaunchPoint) +DEFINE_INTERFACE_METHOD_CONST_0("GetPropPoints", std::vector, ICmpVisual, GetPropPoints) DEFINE_INTERFACE_METHOD_3("SelectAnimation", void, ICmpVisual, SelectAnimation, std::string, bool, fixed) DEFINE_INTERFACE_METHOD_1("SetAnimationSyncRepeat", void, ICmpVisual, SetAnimationSyncRepeat, fixed) DEFINE_INTERFACE_METHOD_1("SetAnimationSyncOffset", void, ICmpVisual, SetAnimationSyncOffset, fixed) Index: source/simulation2/scripting/EngineScriptConversions.cpp =================================================================== --- source/simulation2/scripting/EngineScriptConversions.cpp +++ source/simulation2/scripting/EngineScriptConversions.cpp @@ -28,6 +28,7 @@ #include "ps/utf16string.h" #include "simulation2/helpers/CinemaPath.h" #include "simulation2/helpers/Grid.h" +#include "simulation2/components/ICmpVisual.h" #include "simulation2/system/IComponent.h" #include "simulation2/system/ParamNode.h" @@ -339,8 +340,26 @@ return true; } +template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const JsProp& val) +{ + JSAutoRequest rq(cx); + JS::RootedObject obj(cx, JS_NewPlainObject(cx)); + + JS::RootedValue name(cx); + JS::RootedValue position(cx); + ToJSVal(cx, &name, val.m_Name); + ToJSVal(cx, &position, val.m_Position); + + ScriptInterface::CreateObject( + cx, + ret, + "name", name, + "position", position); +} + // define vectors JSVAL_VECTOR(CFixedVector2D) +JSVAL_VECTOR(JsProp) #undef FAIL #undef FAIL_VOID