Files
test/agent-skills/03-code-patterns.md
2026-02-24 09:50:08 +07:00

8.6 KiB

Code Patterns - C++ to C# Conversions

Abstract Base Classes

C++ Pattern

class CGfxMoveBase
{
protected:
    CGfxMoveBase(GfxMoveMode mode) : m_Mode(mode) {}
    
public:
    virtual ~CGfxMoveBase() {}
    virtual void StartMove(const A3DVECTOR3& vHost, const A3DVECTOR3& vTarget) = 0;
    virtual bool TickMove(DWORD dwDeltaTime, ...) = 0;
    virtual void SetParam(const GFX_SKILL_PARAM* param) { /* default impl */ }
    static CGfxMoveBase* CreateMoveMethod(GfxMoveMode mode);
};

C# Pattern

public abstract class CGfxMoveBase
{
    protected CGfxMoveBase(GfxMoveMode mode)
    {
        m_Mode = mode;
    }
    
    // Pure virtual (= 0) → abstract
    public abstract void StartMove(Vector3 vHost, Vector3 vTarget);
    public abstract bool TickMove(uint dwDeltaTime, ...);
    
    // Virtual with default → virtual
    public virtual void SetParam(GFX_SKILL_PARAM param)
    {
        // default implementation
    }
    
    // Static factory method
    public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode)
    {
        switch (mode)
        {
            case GfxMoveMode.enumLinearMove: return new CGfxLinearMove(mode);
            default: return new CGfxLinearMove(mode);
        }
    }
}

Inheritance Patterns

C++ Pattern

class CGfxLinearMove : public CGfxMoveBase
{
protected:
    float m_fSpeed;
    
public:
    CGfxLinearMove(GfxMoveMode mode) : CGfxMoveBase(mode) {}
    virtual void StartMove(const A3DVECTOR3& vHost, const A3DVECTOR3& vTarget);
    virtual bool TickMove(DWORD dwDeltaTime, ...);
};

C# Pattern

public class CGfxLinearMove : CGfxMoveBase
{
    protected float m_fSpeed;
    
    public CGfxLinearMove(GfxMoveMode mode) : base(mode) { }
    
    public override void StartMove(Vector3 vHost, Vector3 vTarget)
    {
        // implementation
    }
    
    public override bool TickMove(uint dwDeltaTime, ...)
    {
        // implementation
    }
}

Static Factory Methods

C++ Pattern

inline CGfxMoveBase* CGfxMoveBase::CreateMoveMethod(GfxMoveMode mode)
{
    switch(mode)
    {
    case enumLinearMove:
        return new CGfxLinearMove(mode);
    case enumOnTarget:
        return new CGfxOnTargetMove(mode);
    default:
        assert(false);
        return NULL;
    }
}

C# Pattern

public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode)
{
    switch (mode)
    {
        case GfxMoveMode.enumLinearMove:
            return new CGfxLinearMove(mode);
        case GfxMoveMode.enumOnTarget:
            return new CGfxOnTargetMove(mode);
        default:
            return new CGfxLinearMove(mode); // fallback
    }
}

Vector Operations

Normalize Pattern

C++:

A3DVECTOR3 vDir = vTarget - m_vPos;
float fDist = vDir.Normalize();  // In-place normalize, returns magnitude
if (fDist < 1e-4f) return true;

C#:

Vector3 vDir = vTarget - m_vPos;
float fDist = Normalize(ref vDir);  // Helper method
if (fDist < 1e-4f) return true;

// Helper implementation:
protected static float Normalize(ref Vector3 v)
{
    float mag = v.magnitude;
    if (mag < 1e-6f) { v = Vector3.zero; return 0f; }
    v /= mag;
    return mag;
}

Vector Math

C++:

m_vPos += vFlyDir * fFlyDist;
m_vMoveDir = vFlyDir;

C#:

m_vPos += vFlyDir * fFlyDist;
m_vMoveDir = vFlyDir;

Protected Helper Methods

C++ Pattern

protected:
    void CalcRange(const A3DVECTOR3& vDir)
    {
        m_vYRange = _unit_y;
        m_vZRange.Set(vDir.x, 0, vDir.z);
        if (m_vZRange.Normalize() < .01f) m_vZRange = _unit_z;
        m_vXRange = CrossProduct(m_vYRange, m_vZRange);
        // ...
    }
    
    A3DVECTOR3 GetRandOff() const
    {
        if (m_Shape == enumBox)
        {
            // ...
        }
        // ...
    }

C# Pattern

protected void CalcRange(Vector3 vDir)
{
    m_vYRange = Vector3.up;
    m_vZRange = new Vector3(vDir.x, 0, vDir.z);
    if (Normalize(ref m_vZRange) < 0.01f) m_vZRange = Vector3.forward;
    m_vXRange = Vector3.Cross(m_vYRange, m_vZRange);
    // ...
}

protected Vector3 GetRandOff()
{
    if (m_Shape == EmitShape.enumBox)
    {
        // ...
    }
    // ...
}

State Machine Pattern

C++ Pattern

enum
{
    enumWait,
    enumFlying,
    enumHit,
    enumFinished
} m_enumState;

void Tick(DWORD dwDeltaTime)
{
    if (m_enumState == enumFinished) return;
    else if (m_enumState == enumHit)
    {
        // handle hit state
    }
    else if (m_enumState == enumWait)
    {
        if (m_dwCurSpan < m_dwDelayTime) return;
        m_enumState = enumFlying;
    }
    else // enumFlying
    {
        if (m_pMoveMethod.TickMove(dwDeltaTime, ...))
            HitTarget(GetTargetCenter());
    }
}

C# Pattern

protected GfxSkillEventState m_enumState;

public virtual void Tick(uint dwDeltaTime)
{
    if (m_enumState == GfxSkillEventState.enumFinished) return;
    else if (m_enumState == GfxSkillEventState.enumHit)
    {
        // handle hit state
    }
    else if (m_enumState == GfxSkillEventState.enumWait)
    {
        if (m_dwCurSpan < m_dwDelayTime) return;
        m_enumState = GfxSkillEventState.enumFlying;
    }
    else // enumFlying
    {
        if (m_pMoveMethod.TickMove(dwDeltaTime, ...))
            HitTarget(GetTargetCenter());
    }
}

Const Correctness → Readonly

C++ Pattern

const A3DVECTOR3& GetPos() const { return m_vPos; }
GfxMoveMode GetMode() const { return m_Mode; }

C# Pattern

public Vector3 GetPos() { return m_vPos; }  // No const needed
public GfxMoveMode GetMode() { return m_Mode; }  // No const needed

Delegate Pattern (Virtual Methods)

C++ Pattern

class A3DSkillGfxEvent
{
    CGfxMoveBase* m_pMoveMethod;
    
public:
    GfxMoveMode GetMode() const { return m_pMoveMethod->GetMode(); }
    void SetReverse(bool bReverse) const { m_pMoveMethod->SetReverse(bReverse); }
    void SetParam(const GFX_SKILL_PARAM* param) { m_pMoveMethod->SetParam(param); }
};

C# Pattern

public class A3DSkillGfxEvent
{
    protected CGfxMoveBase m_pMoveMethod;
    
    public GfxMoveMode GetMode() { return m_pMoveMethod.GetMode(); }
    public void SetReverse(bool bReverse) { m_pMoveMethod.SetReverse(bReverse); }
    public void SetParam(GFX_SKILL_PARAM param) { m_pMoveMethod.SetParam(param); }
}

Random Number Generation

C++ Pattern

float _SymmetricRandom() { return (rand() / (float)RAND_MAX) * 2.0f - 1.0f; }
float _UnitRandom() { return rand() / (float)RAND_MAX; }

A3DVECTOR3 GetRandOff() const
{
    if (m_Shape == enumBox)
    {
        A3DVECTOR3 xOff, yOff, zOff;
        xOff = _SymmetricRandom() * m_vXRange;
        yOff = _SymmetricRandom() * m_vYRange;
        zOff = _SymmetricRandom() * m_vZRange;
        return xOff + yOff + zOff;
    }
}

C# Pattern

private static float SymRandom() 
{ 
    return UnityEngine.Random.value * 2f - 1f; 
}

private static float UnitRandom() 
{ 
    return UnityEngine.Random.value; 
}

protected Vector3 GetRandOff()
{
    if (m_Shape == EmitShape.enumBox)
    {
        Vector3 xOff = SymRandom() * m_vXRange;
        Vector3 yOff = SymRandom() * m_vYRange;
        Vector3 zOff = SymRandom() * m_vZRange;
        return xOff + yOff + zOff;
    }
}

Conditional Compilation → #if UNITY_EDITOR

C++ Pattern

#ifdef _DEBUG
    assert(false);
#endif

C# Pattern

#if UNITY_EDITOR
    UnityEngine.Debug.Assert(false);
#endif

Memory Management Patterns

C++ Pattern

void ReleaseFlyGfx()
{
    if (m_pFlyGfx)
    {
        if (m_bFadeOut)
            AfxGetGFXExMan()->QueueFadeOutGfx(m_pFlyGfx, 1000);
        else
        {
            m_pFlyGfx->Release();
            delete m_pFlyGfx;
        }
        m_pFlyGfx = NULL;
    }
}

C# Pattern

protected void ReleaseFlyGfx()
{
    if (m_pFlyGfx != null)
    {
        if (m_bFadeOut)
            AfxGetGFXExMan().QueueFadeOutGfx(m_pFlyGfx, 1000);
        else
        {
            m_pFlyGfx.Release();
            // C#: Automatic garbage collection, no delete needed
        }
        m_pFlyGfx = null;
    }
}

Common Conversion Checklist

When converting a class:

  • Abstract base → abstract class
  • Pure virtual methods → abstract methods
  • Virtual with default → virtual methods
  • Non-virtual → regular methods
  • Static factory → static method
  • Const methods → regular methods (no const)
  • Pointers → references (remove *)
  • References → value types or ref/out
  • DWORDuint
  • A3DVECTOR3Vector3
  • Union access → param.value.fVal
  • Hungarian notation → preserved