#ifndef _FINITE_STATE_H
#define _FINITE_STATE_H
#include <map>
#include <functional>
class CFiniteStateMachine;
class CFiniteState
{
friend class CFiniteStateMachine;
private:
CFiniteState(DWORD state) { m_StateID = state; }
virtual ~CFiniteState()
{
std::map<DWORD, DWORD>::iterator iter, iterPrev;
iter = TransitionList.begin();
while (iter != TransitionList.end())
{
iterPrev = iter++;
TransitionList.erase(iterPrev);
}
}
DWORD GetStateID() const { return m_StateID; }
void AddTransition(DWORD inputEvent, DWORD outputStateID) { TransitionList[inputEvent] = outputStateID; }
void DeleteTransition(DWORD inputEvent) { TransitionList.erase(inputEvent); }
DWORD GetCount() { return TransitionList.size(); }
bool OutputState(DWORD inputEvent, DWORD& outputState)
{
std::map<DWORD, DWORD>::iterator iter;
iter = TransitionList.find(inputEvent);
if (iter == TransitionList.end())
{
//LogError("[CRITICAL] CFiniteState::OutputState(%d)", inputEvent);
return false;
}
outputState = TransitionList[inputEvent];
return true;
}
private:
DWORD m_StateID;
std::map<DWORD, DWORD> TransitionList;
};
#endif //!< FiniteState.h
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifndef _FINITE_STATE_MACHINE_H
#define _FINITE_STATE_MACHINE_H
#include "FiniteState.h"
#include <ctime>
#include <string>
class CFiniteStateMachine
{
public:
CFiniteStateMachine() { m_CurrentState = 0; }
virtual ~CFiniteStateMachine()
{
std::map<DWORD, CFiniteState*>::iterator iter, iterPrev;
iter = m_StateList.begin();
while (iter != m_StateList.end())
{
iterPrev = iter++;
delete iterPrev->second;
m_StateList.erase(iterPrev);
}
}
void SetName(const char* name_) { m_name = name_; }
LONGLONG GetCurrentStateTime() { return m_nCurrentStateTime; }
bool GetOutputState(DWORD inputEvent, DWORD& outputState)
{
std::map<DWORD, CFiniteState*>::iterator iter;
CFiniteState* state;
iter = m_StateList.find(GetCurrentStateID());
if (iter == m_StateList.end())
{
//logError("[CRITICAL] CFiniteStateMachine[%s]::GetOutputState(%d)", m_name.c_str(), inputEvent);
return 0;
}
state = m_StateList[GetCurrentStateID()];
return state->OutputState(inputEvent, outputState);
}
void AddStateTransition(DWORD stateID, DWORD inputEvent, DWORD outputStateID)
{
std::map<DWORD, CFiniteState*>::iterator iter;
CFiniteState* state;
iter = m_StateList.begin();
while (iter != m_StateList.end())
{
state = iter->second;
if (state->GetStateID() == stateID)
break;
iter++;
}
if (iter == m_StateList.end())
{
state = new CFiniteState(stateID);
m_StateList[state->GetStateID()] = state;
}
state->AddTransition(inputEvent, outputStateID);
}
void DeleteTransition(DWORD stateID, DWORD inputEvent);
{
std::map<DWORD, CFiniteState*>::iterator iter, iterPrev;
CFiniteState* state;
iter = m_StateList.begin();
while (iter != m_StateList.end())
{
iterPrev = iter;
state = iter->second;
if (state->GetStateID() == stateID)
break;
iter++;
}
if (iter == m_StateList.end())
return;
state->DeleteTransition(inputEvent);
if (0 == state->GetCount())
{
delete state;
m_StateList.erase(iterPrev);
}
}
void SetCurrentState(DWORD stateID)
{
std::map<DWORD, CFiniteState*>::iterator iter;
iter = m_StateList.find(stateID);
if (iter == m_StateList.end())
{
//logError("[CRITICAL] CFiniteStateMachine[%s]::SetCurrentState(%d)", m_name.c_str(), stateID);
return;
}
m_CurrentState = iter->second;
m_nCurrentStateTime = GetTime();
}
DWORD GetCurrentStateID() const
{
if (0 == m_CurrentState)
{
//logError("[CRITICAL] CFiniteStateMachine[%s]::GetCurrentStateID()", m_name.c_str());
return 0;
}
return m_CurrentState->GetStateID();
}
bool StateTransition(int event)
{
if (0 == m_CurrentState)
{
//logError("[CRITICAL] CFiniteStateMachine[%s]::StateTransition(%d)", m_name.c_str(), event);
return false;
}
else
{
DWORD OutputState;
if (true == m_CurrentState->OutputState(event, OutputState))
{
//logDebug("FSM[%s] Event:%d State:%d", m_name.c_str(), event, m_CurrentState->GetStateID());
m_CurrentState = m_StateList[OutputState];
m_nCurrentStateTime = GetTime();
return true;
}
else
{
//logError("FSM[%s] Event:%d State:%d", m_name.c_str(), event, m_CurrentState->GetStateID());
return false;
}
}
}
private:
std::map<DWORD, CFiniteState*> m_StateList;
std::string m_name;
CFiniteState* m_CurrentState;
LONGLONG m_nCurrentStateTime;
};
#endif //!< FiniteStateMachine.h
///////////////////////////////////////////////////////////////////////////
#ifndef __BASE_PROCESS_H_
#define __BASE_PROCESS_H_
#include "FiniteStateMachine.h"
class BaseProcess
{
public:
BaseProcess(const char* name_) : m_timeAdvance(0) { m_FSM.SetName(name_); }
virtual ~BaseProcess() {}
//!< FSM Pure virtual functions
virtual void SetTransition(DWORD event) = 0;
virtual void ProcessState(int timeAdvance) = 0;
protected:
virtual void RegisterState() = 0;
virtual void RegisterTransition() = 0;
void SetTimeAdvance(int timeAdvance) { m_timeAdvance = timeAdvance; }
int GetTimeAdvance() const { return m_timeAdvance; }
bool CheckState(DWORD state) const { return (m_FSM.GetCurrentStateID() == state); }
protected:
int m_timeAdvance;
CFiniteStateMachine m_FSM; //!< state transition
};
#endif //!< BaseProcess.h
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifndef _CREATURE_BASE_PROCESS_H
#define _CREATURE_BASE_PROCESS_H
#include "BaseProcess.h"
template<class T>
class CObjBaseProcess : public BaseProcess
{
public:
CObjBaseProcess(T& container, const char* name_) : BaseProcess(name_), m_container(container) {}
virtual ~CObjBaseProcess() {}
virtual void InitFSM() = 0;
virtual bool InitData() = 0;
//!< Get User
T& GetContainer() { return m_container; }
const T& GetContainer() const { return m_container; }
private:
T& m_container;
};
#endif //!< ObjBaseProcess.h
/**********************************************************/
/**********************************************************/
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Sample
//!< CUser.h
class CUser // : public CCreature
{
public:
CUser();
virtual ~CUser() {}
virtual void Run(LONGLONG nCurTime, int tickDelay);
void InitFSMProcess();
bool InitUser();
void InitProcessManager();
void Parse(char *pBuf, int nLen);
bool Send(const char *pBuf, int nLen);
public:
CUserDataProcess m_UserDataProcess;
CUserCtrlProcess m_UserCtrlProcess;
CUserLifeProcess m_UserLifeProcess;
CUserItemProcess m_UserItemProcess;
CUserBattleProcess m_UserBattleProcess;
CUserSpellProcess m_UserSpellProcess;
CUserMoveProcess m_UserMoveProcess;
CUserProductProcess m_UserProductProcess;
CUserProcessManager m_UserProcessMgr;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//!< CUser.cpp
void CUser::InitFSMProcess()
{
m_UserCtrlProcess.InitFSM();
m_UserDataProcess.InitFSM();
m_UserItemProcess.InitFSM();
m_UserBattleProcess.InitFSM();
m_UserSpellProcess.InitFSM();
m_UserMoveProcess.InitFSM();
m_UserLifeProcess.InitFSM();
m_UserProductProcess.InitFSM();
InitProcessManager();
}
bool CUser::InitUser()
{
//CCreature::InitCreature();
if (false == m_UserDataProcess.InitData()) return false;
if (false == m_UserCtrlProcess.InitData()) return false;
if (false == m_UserItemProcess.InitData()) return false;
if (false == m_UserBattleProcess.InitData()) return false;
if (false == m_UserSpellProcess.InitData()) return false;
if (false == m_UserMoveProcess.InitData()) return false;
if (false == m_UserLifeProcess.InitData()) return false;
if (false == m_UserProductProcess.InitData()) return false;
return true;
}
void CUser::Run(LONGLONG nCurTime, int tickDelay)
{
int timeAdvance = TIMETICK_IN_MSEC + tickDelay;
if (true == m_UserMoveProcess.IsInMap())
{
//CCreature::Run(nCurTime, tickDelay);
m_UserCtrlProcess.ProcessState(timeAdvance);
m_UserLifeProcess.ProcessState(timeAdvance);
if (true == m_UserLifeProcess.IsAlive())
{
m_UserMoveProcess.ProcessState(timeAdvance);
m_UserBattleProcess.ProcessState(timeAdvance);
}
m_UserItemProcess.ProcessState(timeAdvance);
}
}
void CUser::Parse(char *pBuf, int nLen)
{
if (static_cast<int>(3 * sizeof(int)) > nLen)
{
//logError("Parse Error: Invalid Packet Length: %d", nLen);
return;
}
int uid, cid, nCommand, offset = 0;
memcpy(&nCommand, pBuf+offset, sizeof(int));
offset += sizeof(int);
memcpy(&uid, pBuf+offset, sizeof(int));
offset += sizeof(int);
memcpy(&cid, pBuf+offset, sizeof(int));
//!< replace nCommand position
memcpy(pBuf+offset, &nCommand, sizeof(int));
pBuf += offset;
nLen -= offset;
m_UserCtrlProcess.UpdateAliveTime();
if (true == m_UserCtrlProcess.Parse(uid, nCommand, pBuf, nLen)) return;
if (true == m_UserMoveProcess.Parse(nCommand, pBuf, nLen)) return;
if (true == m_UserSpellProcess.Parse(nCommand, pBuf, nLen)) return;
if (true == m_UserBattleProcess.Parse(nCommand, pBuf, nLen)) return;
if (true == m_UserLifeProcess.Parse(nCommand, pBuf, nLen)) return;
if (true == m_UserItemProcess.Parse(nCommand, pBuf, nLen)) return;
if (true == m_UserProductProcess.Parse(nCommand, pBuf, nLen)) return;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
enum eEVENT_USER
{
EVENT_USER_ON = 1,
EVENT_USER_OFF,
//!< Move
EVENT_USER_WARP,
EVENT_USER_OUTMAP,
EVENT_USER_INMAP,
EVENT_USER_STOP,
EVENT_USER_MOVE,
EVENT_USER_GETON,
EVENT_USER_GETDOWN,
//!< Battle
EVENT_USER_ATTACK,
EVENT_USER_LOSTTARGET,
//!< Life
EVENT_USER_INVINCIBLE,
EVENT_USER_VINCIBLE,
EVENT_USER_RESURRECT,
EVENT_USER_DIE,
EVENT_USER_MEAL_START,
EVENT_USER_MEAL_END,
//!< Item (associated inven)
EVENT_USER_EXCHANGE_START,
EVENT_USER_EXCHANGE_END,
EVENT_USER_SHOP_START,
EVENT_USER_VENDOR_START,
EVENT_USER_VENDOR_END,
EVENT_USER_ADMINCTL_START,
EVENT_USER_ADMINCTL_END,
EVNET_USER_POST_START,
EVENT_USER_POST_END,
//!< Expertise (manufacture, extract)
EVENT_USER_EXPERTISE_MAKING,
EVENT_USER_EXPERTISE_EXTRACTING,
EVENT_USER_EXPERTISE_COMPLETE,
};
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifndef _OBJECT_STATE_H
#define _OBJECT_STATE_H
//////////////////////////////////////////////////////////////////////
// CObjState
template<class T>
class CObjState
{
public:
CObjState( T& parent ) : m_parent( parent ) {}
virtual ~CObjState() {}
virtual void Enter() = 0;
virtual void Process() = 0;
virtual void Exit() = 0;
T& GetObj() { return m_parent; }
protected:
T& m_parent;
};
#endif //!< ObjState.h
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifndef _USER_STATE_PRODUCT_H
#define _USER_STATE_PRODUCT_H
#include "ObjState.h"
enum eSTATE_EXPERTISE
{
STATE_USER_EXPERTISE_NORMAL,
STATE_USER_EXPERTISE_MAKING,
STATE_USER_EXPERTISE_EXTRACTING,
MAX_USER_STATE_EXPERTISE,
};
//!< USER Expertise States
class CUser;
class CUserExpertiseNormal : public CObjState<CUser>
{
public:
CUserExpertiseNormal(CUser& parent) : CObjState<CUser> (parent) {}
virtual ~CUserExpertiseNormal() {}
virtual void Enter();
virtual void Process();
virtual void Exit();
};
class CUserExpertiseMaking : public CObjState<CUser>
{
public:
CUserExpertiseMaking(CUser& parent) : CObjState<CUser> (parent) {}
virtual ~CUserExpertiseMaking() {}
virtual void Enter();
virtual void Process();
virtual void Exit();
};
class CUserExpertiseExtracting : public CObjState<CUser>
{
public:
CUserExpertiseExtracting(CUser& parent) : CObjState<CUser> (parent) {}
virtual ~CUserExpertiseExtracting() {}
virtual void Enter();
virtual void Process();
virtual void Exit();
};
#endif //!< UserStateProduct.h
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Process
#ifndef _USER_PRODUCT_PROCESS_H
#define _USER_PRODUCT_PROCESS_H
#include "FSM/ObjBaseProcess.h"
#include "UserStateProduct.h"
class CUser;
class CUserProductProcess : public CObjBaseProcess<CUser>
{
public:
CUserProductProcess(CUser& user);
virtual ~CUserProductProcess() {}
private:
CUserProductProcess();
CUserProductProcess( const CUserProductProcess& rhs);
CUserProductProcess& operator = (const CUserProductProcess& rhs);
void ParsePacketClientGameserverProductKit(char* pBuf, int nLen);
public:
virtual void InitFSM();
virtual bool InitData();
virtual void SetTransition(DWORD event);
virtual void ProcessState(int timeAdvance);
virtual void RegisterState();
virtual void RegisterTransition();
DWORD GetState() const { return m_FSM.GetCurrentStateID(); }
bool Parse(int nCommand, char* pBuf, int nLen);
bool DropProductKit(const int nProductID);
void SetMaking(int nSpellID);
void EndState();
private:
CObjState<CUser>* m_pState; //!< current Expertise state
CObjState<CUser>* m_pStateList[MAX_USER_STATE_EXPERTISE]; //!< Expertise state list
}
#endif //!< UserProductProcess.h
///////////////////////////////////////////////////////////////////////////
//!< CUserProductProcess.cpp
#include "UserProductProcess.h"
#include "User.h"
CUserProductProcess::CUserProductProcess(CUser& user)
: CObjBaseProcess<CUser>(user, "CUserProductProcess")
{
RegisterState();
RegisterTransition();
}
void CUserProductProcess::InitFSM()
{
m_pState = m_pStateList[STATE_USER_EXPERTISE_NORMAL];
m_FSM.SetCurrentState(STATE_USER_EXPERTISE_NORMAL);
}
bool CUserProductProcess::InitData()
{
return true;
}
void CUserProductProcess::RegisterState()
{
m_pStateList[STATE_USER_EXPERTISE_NORMAL]
= (CObjState<CUser>*) new CUserExpertiseNormal(GetContainer());
m_pStateList[STATE_USER_EXPERTISE_MAKING]
= (CObjState<CUser>*) new CUserExpertiseMaking(GetContainer());
m_pStateList[STATE_USER_EXPERTISE_EXTRACTING]
= (CObjState<CUser>*) new CUserExpertiseExtracting(GetContainer());
}
void CUserProductProcess::RegisterTransition()
{
m_FSM.AddStateTransition(STATE_USER_EXPERTISE_NORMAL,
EVENT_USER_EXPERTISE_MAKING,
STATE_USER_EXPERTISE_MAKING);
m_FSM.AddStateTransition(STATE_USER_EXPERTISE_NORMAL,
EVENT_USER_EXPERTISE_EXTRACTING,
STATE_USER_EXPERTISE_EXTRACTING);
m_FSM.AddStateTransition(STATE_USER_EXPERTISE_MAKING,
EVENT_USER_EXPERTISE_COMPLETE,
STATE_USER_EXPERTISE_NORMAL);
m_FSM.AddStateTransition(STATE_USER_EXPERTISE_EXTRACTING,
EVENT_USER_EXPERTISE_COMPLETE,
STATE_USER_EXPERTISE_NORMAL);
}
void CUserProductProcess::SetTransition(DWORD event)
{
if (true == m_FSM.StateTransition(event))
{
m_pState->Exit();
m_pState = m_pStateList[m_FSM.GetCurrentStateID()];
m_pState->Enter();
}
}
void CUserProductProcess::ProcessState(int timeAdvance)
{
if (nullptr != m_pState)
{
SetTimeAdvance(timeAdvance);
m_pState->Process();
}
}
bool CUserProductProcess::Parse(int nCommand, char* pBuf, int nLen)
{
bool bCatched =false;
switch (nCommand)
{
case _PACKET_CLIENT_GAMESERVER_PRODUCTKIT_ID:
{
ParsePacketClientGameserverProductKit(pBuf, nLen);
bCatched = true;
}break;
}
return bCatched;
}
void CUserProductProcess::ParsePacketClientGameserverProductKit(char* pBuf, int nLen)
{
CPacket <_PACKET_CLIENT_GAMESERVER_PRODUCTKIT> RecvPacket;
if (false == RecvPacket.ReadData(pBuf, nLen))
{
//logError("Packet[%d]: Failed at Packet Reading", RecvPacket.m_Data.nID);
return;
}
DropProductKit(RecvPacket.m_Data.nProductID);
}
bool CUserProductProcess::DropProductKit(const int nProductID)
{
DWORD curstate = GetContainer().m_UserProductProcess.GetState(); //!< check state
if (STATE_USER_EXPERTISE_MAKING != curstate)
{
GetContainer().m_UserSpellProcess.RemoveSpell(nProductID);
m_nProductIndex = GetContainer().m_UserDataProcess.ReSetProductKit(nProductID);
if (true == IS_VALID_PRODUCTINDEX(m_nProductIndex)) //!< Success DropProductKit
{
//SendDeleteProduct(m_nProductIndex, nProductID);
return true;
}
else //!< FAIL
{
//SendErrorProduct(RESULT_FAIL_PRODUCT_KIT, nProductID);
return false;
}
}
return false;
}
void CUserProductProcess::SetMaking(int nSpellID)
{
SetTransition(EVENT_USER_EXPERTISE_MAKING);
//GetContainer().m_UserItemProcess.SetTransition(EVENT_USER_EXPERTISE_MAKING);
m_SpellID = nSpellID;
}
void CUserProductProcess::EndState()
{
DWORD curstate = GetState();
switch (curstate)
{
case STATE_USER_EXPERTISE_MAKING:
case STATE_USER_EXPERTISE_EXTRACTING:
{
SetTransition(EVENT_USER_EXPERTISE_COMPLETE);
//GetContainer().m_UserItemProcess.SetTransition(EVENT_USER_EXPERTISE_COMPLETE);
}break;
} //!< !switch()
}
'[ Programing ] > Algorithm' 카테고리의 다른 글
매주 이벤트(퀘스트) 주차 초기화 계산. (0) | 2022.04.21 |
---|---|
[C++] mt19937 난수 생성기 (Random 클래스) (0) | 2019.11.21 |
비트(bit)값 연산 정리. (0) | 2018.03.08 |
Tip 클래스 객체 생성과 초기 선언을 한줄로... (0) | 2016.07.25 |
설정된 기간 관련 카운터(주간) 계산하기 (0) | 2014.01.10 |