#include "RUStateMachineLoader.h" #include "RUState.h" #include "RUMetaState.h" NS_RU_BEGIN static StateMachineLoader *_instance = nullptr; StateMachineLoader* StateMachineLoader::getInstance() { if (_instance == nullptr) { _instance = new (std::nothrow) StateMachineLoader; } return _instance; } StateMachine* StateMachineLoader::createStateMachine(const std::string& stateMachineName, void* userObj4StateDelegate) { return _createStateMachine(stateMachineName, {} , userObj4StateDelegate); } StateMachine* StateMachineLoader::_createStateMachine(const std::string& stateMachineName, const std::vector& fullStatePath, void* userObj4StateDelegate) { fsmproto::StateMachine* stateMachineData = getStateMachineData(stateMachineName); const std::string& initStateName = stateMachineData->init_state_name(); std::unordered_map states; std::vector transitions; std::map params; //解析状态列表 const google::protobuf::RepeatedPtrField& states_pb = stateMachineData->states(); states.reserve(states_pb.size()); for(const fsmproto::State& state_pb : states_pb){ std::vector newFullStatePath = fullStatePath; const std::string& stateName = state_pb.name(); std::vector entryActInfos = _createStateActInfos(state_pb.entry()); std::vector idleActInfos = _createStateActInfos(state_pb.idle()); std::vector exitActInfos = _createStateActInfos(state_pb.exit()); const std::string& stateDelegateKey = state_pb.state_delegate_key(); newFullStatePath.push_back(stateName); redutils::State* state = nullptr; //是不是分层状态机 const std::string& fsm_name = state_pb.fsm_name(); if (fsm_name.empty() == true) { //普通状态 state = redutils::State::create(stateName, newFullStatePath, kStateType::NORMAL, entryActInfos, idleActInfos, exitActInfos, stateDelegateKey, userObj4StateDelegate); }else{ StateMachine* metaStateMachine = _createStateMachine(fsm_name, newFullStatePath, userObj4StateDelegate); state = redutils::MetaState::create(stateName, newFullStatePath, kStateType::META, entryActInfos, idleActInfos, exitActInfos, stateDelegateKey, userObj4StateDelegate, metaStateMachine); } CCASSERT(states.find(stateName) == states.end(), "重复的状态?"); states.emplace(stateName,state); } //解析状态转换 const google::protobuf::RepeatedPtrField& transitions_pb = stateMachineData->transitions(); transitions.reserve(transitions_pb.size()); for(const fsmproto::Transition& transition_pb : transitions_pb) { FsmTransition fsmTransition = _createFsmTransition(transition_pb); transitions.push_back(std::move(fsmTransition)); } //解析状态机自定义提交参数 const google::protobuf::Map& params_pb = stateMachineData->params(); for (auto iter = params_pb.begin(); iter != params_pb.end(); iter++) { const std::string& param_name = iter->first; const fsmproto::Param& param_pb = iter->second; FsmParameter param; param.name = param_name; const std::string& type = param_pb.type(); if (type == "int") { param.type = FsmParamType::PARAM_T_INT; param.iv = cocos2d::Value(param_pb.default_value()).asInt(); }else if (type == "float"){ param.type = FsmParamType::PARAM_T_FLOAT; param.fv = cocos2d::Value(param_pb.default_value()).asFloat(); }else if (type == "string"){ param.type = FsmParamType::PARAM_T_STRING; param.sv = param_pb.default_value(); }else if (type == "trigger"){ param.type = FsmParamType::PARAM_T_TRIGGER; param.iv = cocos2d::Value(param_pb.default_value()).asInt(); } params.emplace(param_name,std::move(param)); } StateMachine* stateMachine = StateMachine::create(stateMachineName, initStateName, states, transitions, params); return stateMachine; } std::vector StateMachineLoader::_createStateActInfos(const google::protobuf::RepeatedPtrField& actions_pb) { std::vector stateActInfos; stateActInfos.reserve(actions_pb.size()); // 预分配内存 for(const fsmproto::Action& action_pb : actions_pb){ StateActInfo stateActInfo; stateActInfo.actType = action_pb.type();; const google::protobuf::Map& params_pb = action_pb.params(); for (auto iter = params_pb.begin(); iter != params_pb.end(); ++iter) { stateActInfo.actParams.emplace(iter->first, iter->second); } stateActInfos.push_back(std::move(stateActInfo)); } return stateActInfos; } FsmTransition StateMachineLoader::_createFsmTransition(const fsmproto::Transition& transition_pb) { FsmTransition fsmTransition; fsmTransition.eventName = transition_pb.event(); fsmTransition.fromState = transition_pb.src(); fsmTransition.toState = transition_pb.dst(); //转移条件 std::list> conditions; const google::protobuf::RepeatedPtrField& conditions_group_pb = transition_pb.condition(); for(const fsmproto::ConditionData& conditions_pb : conditions_group_pb){ std::list fsmTansConditions; for(const fsmproto::ConditionValue& conditionValue_pb : conditions_pb.values()){ FsmTansCondition fsmTansCondition; fsmTansCondition.name = conditionValue_pb.param_name(); fsmTansCondition.op = conditionValue_pb.symbol(); fsmTansCondition.v = conditionValue_pb.compare_value(); fsmTansConditions.push_back(std::move(fsmTansCondition)); } conditions.push_back(std::move(fsmTansConditions)); } fsmTransition.conditions = std::move(conditions); fsmTransition.beforeSwitchActInfos = _createStateActInfos(transition_pb.before_switch_actions()); fsmTransition.afterSwitchActInfos = _createStateActInfos(transition_pb.after_switch_actions()); return fsmTransition; } fsmproto::StateMachine* StateMachineLoader::getStateMachineData(const std::string& stateMachineName) { fsmproto::StateMachine* stateMachineData = nullptr; auto p = _stateMachineDataCacheMap.find(stateMachineName); if( p != _stateMachineDataCacheMap.end()){ stateMachineData = p->second; }else { std::string fileName = stateMachineName + ".fsm"; cocos2d::Data datas = cocos2d::FileUtils::getInstance()->getDataFromFile(fileName); unsigned char *data = datas.getBytes(); ssize_t len = datas.getSize(); std::string fileStr(data, data + len); stateMachineData = new fsmproto::StateMachine(); stateMachineData->ParseFromString(fileStr); _stateMachineDataCacheMap.emplace(stateMachineName, stateMachineData); } CCASSERT(stateMachineData != nullptr, "wtf"); return stateMachineData; } void StateMachineLoader::releaseAllStateMachineDataCache() { for(auto iter : _stateMachineDataCacheMap ){ delete iter.second; } _stateMachineDataCacheMap.clear(); } NS_RU_END