public bool Init(string strBrokerHost, string strGateListenIpPort, int nGateIndex = 0) { m_nGateIndex = nGateIndex; m_strGateName = string.Format("gate#{0}", m_nGateIndex); m_ffrpc = new FFRpc(m_strGateName); if (m_ffrpc.Open(strBrokerHost) == false) { FFLog.Error("gate ffrpc open failed!"); return(false); } m_ffrpc.Reg <GateChangeLogicNodeReq, EmptyMsgRet>(this.ChangeSessionLogic); m_ffrpc.Reg <GateCloseSessionReq, EmptyMsgRet>(this.CloseSession); m_ffrpc.Reg <GateRouteMsgToSessionReq, EmptyMsgRet>(this.RouteMsgToSession); m_ffrpc.Reg <GateBroadcastMsgToSessionReq, EmptyMsgRet>(this.BroadcastMsgToSession); m_acceptor = FFNet.Listen(strGateListenIpPort, new SocketMsgHandler(HandleMsg), new SocketBrokenHandler(HandleBroken)); if (m_acceptor != null) { FFLog.Trace(string.Format("FFGate open....{0} ok", strGateListenIpPort)); } else { FFLog.Error(string.Format("FFGate open....{0} failed", strGateListenIpPort)); } return(true); }
public void HandleMsg(IFFSocket ffsocket, UInt16 cmd, byte[] strMsg) { var sessionData = ffsocket.GetSessionData(); if (sessionData == null)//!first msg { string strDefaultWorker = "worker#0"; if (m_ffrpc.IsExistNode(strDefaultWorker) == false) { //ffsocket.Close(); FFLog.Error(string.Format("gate worker[{0}] not exist", strDefaultWorker)); FFNet.SendMsg(ffsocket, 256, Util.String2Byte("server is busy!0x0!你好")); return; } Int64 sessionIDNew = ++m_nIDGenerator; ClientInfo cinfo = new ClientInfo() { sockObj = ffsocket, sessionID = sessionIDNew, strAllocWorker = strDefaultWorker }; ffsocket.SetSessionData(sessionIDNew); m_dictClients[sessionIDNew] = cinfo; RouteLogicMsg(cinfo, cmd, strMsg, true); return; } Int64 sessionID = (Int64)sessionData; if (m_dictClients.ContainsKey(sessionID) == false) { return; } ClientInfo cinfo2 = m_dictClients[sessionID]; RouteLogicMsg(cinfo2, cmd, strMsg, false); }
public bool Call <MSG_TYPE, RET_TYPE>(string strServiceName, MSG_TYPE msgData, TCallBack <RET_TYPE> callback) where MSG_TYPE : Thrift.Protocol.TBase, new() where RET_TYPE : Thrift.Protocol.TBase, new() { if (!m_brokerData.Service2node_id.ContainsKey(strServiceName)) { FFLog.Trace(string.Format("ffrpc.Call servervice:{0} not exist", strServiceName)); RET_TYPE retMsg = new RET_TYPE(); callback(retMsg); return(false); } BrokerRouteMsgReq reqMsg = new BrokerRouteMsgReq() { Callback_id = 0, Err_info = "" }; reqMsg.Dest_node_id = m_brokerData.Service2node_id[strServiceName]; reqMsg.Dest_service_name = strServiceName; reqMsg.Body = Util.Byte2String(FFNet.EncodeMsg(msgData)); reqMsg.Dest_msg_name = Type2Name(msgData); reqMsg.Callback_id = ++m_nIDGenerator; m_dictCallBack[reqMsg.Callback_id] = (BrokerRouteMsgReq dataMsg) => { RET_TYPE retMsg = new RET_TYPE(); FFNet.DecodeMsg(retMsg, dataMsg.Body); callback(retMsg); }; SendToDestNode(reqMsg); return(true); }
public void HandleClose() { if (m_nStatus == 0) { return; } m_nStatus = 0; FFNet.GetTaskQueue().Post(() => { if (m_oSocket == null) { return; } try { m_oSocket.Close(); m_oSocket = null; m_oBuffSending.Clear(); m_oSocketCtrl.HandleBroken(this); } catch (Exception ex) { FFLog.Trace("scoket: HandleClose Error " + ex.Message); } }); }
private void handleSendEnd(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; socket.EndSend(ar); } catch (SocketException ex) { FFLog.Trace("scoket: send Error " + ex.Message); HandleClose(); return; } FFNet.GetTaskQueue().Post(() => { if (m_oBuffSending.Count > 0) { m_oBuffSending.RemoveAt(0); } try { if (m_oBuffSending.Count > 0 && m_oSocket != null) { byte[] data = m_oBuffSending[0]; m_oSocket.BeginSend(data, 0, data.Length, 0, new AsyncCallback(handleSendEnd), m_oSocket); } } catch (SocketException ex) { FFLog.Trace("scoket: send Error " + ex.Message); HandleClose(); } }); }
public void Close() { FFNet.GetTaskQueue().Post(() => { HandleClose(); }); }
public void AddPerf(string nameMod, Int64 us) { FFNet.GetTaskQueue().PostOrRunIfInSameThread(() => { if (!bInit) { Init(); } if (us < 1) { us = 1; } PerfData data = null; if (m_name2data.ContainsKey(nameMod)) { data = m_name2data[nameMod]; } else { data = new PerfData() { }; m_name2data[nameMod] = data; } data.total += us; data.times += 1; if (us > data.max) { data.max = us; } if (us < data.min) { data.min = us; } }); }
public FFRpc Reg <MSG_TYPE, RET_TYPE>(TUserFunc <MSG_TYPE, RET_TYPE> funcUser) where MSG_TYPE : Thrift.Protocol.TBase, new() where RET_TYPE : Thrift.Protocol.TBase, new() { MSG_TYPE tmpData = new MSG_TYPE(); string msgname = Type2Name(tmpData); FFLog.Trace(string.Format("ffrpc.FFRpc Reg....msgname={0}", msgname)); m_dictFuncs[msgname] = (BrokerRouteMsgReq reqMsg) => { MSG_TYPE msgData = new MSG_TYPE(); FFNet.DecodeMsg(msgData, reqMsg.Body); RET_TYPE retMsg = funcUser(msgData); if (reqMsg.Callback_id != 0) { reqMsg.Dest_node_id = reqMsg.From_node_id; reqMsg.Dest_service_name = ""; reqMsg.Body = Util.Byte2String(FFNet.EncodeMsg(retMsg)); SendToDestNode(reqMsg); } }; return(this); }
public static void Main(string[] args) { string host = "tcp://127.0.0.1:43210"; FFBroker ffbroker = new FFBroker(); ffbroker.Open(host); string strServiceName = "worker#0"; FFRpc ffrpc = new FFRpc(strServiceName); if (ffrpc.Open(host) == false) { FFLog.Trace("ffrpc open failed!"); } ffrpc.Reg((SessionEnterWorkerReq req) => { FFLog.Trace(string.Format("ffrpc SessionEnterWorkerReq £¡£¡£¡FromGate={0}", req.From_gate)); return(req); }); Console.ReadKey(); ffrpc.GetTaskQueue().Post(() => { SessionEnterWorkerReq reqMsg = new SessionEnterWorkerReq() { From_gate = "gate#0" }; WorkerCallMsgReq reqWorkerCall = new WorkerCallMsgReq(); //ffrpc.Call(strServiceName, reqMsg); reqMsg.From_gate = "gate#1"; ffrpc.Call(strServiceName, reqWorkerCall, (SessionEnterWorkerReq retMsg) => { FFLog.Trace(string.Format("ffrpc SessionEnterWorkerReq return£¡£¡£¡FromGate={0}", retMsg.From_gate)); }); }); //FFNet.Timerout(1000, Theout); //FFNet.Timerout(2000, Theout); FFNet.Timerout(100000, () => { FFLog.Debug("AAAAAAAAAAAAAAA1"); ffrpc.Close(); }); FFLog.Trace(string.Format("main! {0}", System.Threading.Thread.CurrentThread.ManagedThreadId.ToString())); AppDomain.CurrentDomain.ProcessExit += (sender, arg) => { FFLog.Trace("exist!!"); }; Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) => { e.Cancel = true; FFLog.Trace("exist3!!"); FFNet.Cleanup(); FFLog.Cleanup(); }; Console.ReadKey(); FFLog.Trace("exist!!"); FFNet.Cleanup(); FFLog.Cleanup(); }
//! 广播消息给所有的client public EmptyMsgRet BroadcastMsgToSession(GateBroadcastMsgToSessionReq reqMsg) { byte[] dataBody = reqMsg.Body; foreach (var cinfo in m_dictClients.Values) { FFNet.SendMsg(cinfo.sockObj, (UInt16)reqMsg.Cmd, dataBody); } return(m_msgEmpty); }
public bool Init() { if (bInit) { return(true); } bInit = true; FFNet.TimeroutLoop(10 * 60 * 1000, this.SaveLog, "PerfMonitor"); return(true); }
public void handleMsg(FFSocket ffsocket, Int16 cmd, string strMsg) { Console.WriteLine("handleMsg....{0}, {1}", cmd, strMsg.Length); if (cmd == 3) { FFNet.decodeMsg(m_brokerData, strMsg); Console.WriteLine("handleMsg....{0}, {1}", m_brokerData.Node_id, m_brokerData.Register_flag); if (m_brokerData.Register_flag == 1) { m_nNodeID = m_brokerData.Node_id;//! -1表示注册失败,0表示同步消息,1表示注册成功 } } }
public void HandleRecv(IAsyncResult ar) { if (m_nStatus == 0) { FFLog.Trace("scoket: HandleRecv has closed"); return; } var length = 0; try { Socket socket = (Socket)ar.AsyncState; if (socket == null || m_oSocket == null) { return; } length = socket.EndReceive(ar); } catch (Exception ex) { FFLog.Warning("scoket: recv Error1 " + ex.Message); HandleClose(); return; } //FFLog.Trace(string.Format("scoket: recv 1111 {0}", length)); if (length == 0) { FFLog.Warning("HandleRecv: recv end ok file "); HandleClose(); return; } FFNet.GetTaskQueue().Post(() => { try { byte[] message = new byte[length]; Array.Copy(m_oBuffer, 0, message, 0, length); PostMsg(message); //接收下一个消息 if (m_oSocket != null) { m_oSocket.BeginReceive(m_oBuffer, 0, m_oBuffer.Length, SocketFlags.None, new AsyncCallback(HandleRecv), m_oSocket); } } catch (Exception ex) { FFLog.Error("scoket: recv Error2 " + ex.Message); HandleClose(); } }); }
public static void Main(string[] args) { CfgTool.Instance().InitCfg(args); string strBrokerListen = CfgTool.Instance().GetCfgVal("BrokerListen", "tcp://127.0.0.1:4321"); if (!FFBroker.Instance().Init(strBrokerListen)) { FFLog.Error("FFBroker open failed!"); return; } int nWorkerIndex = 0; if (FFWorker.Instance().Init(strBrokerListen, nWorkerIndex, listEnableClassNames) == false) { FFLog.Trace("FFWorker open failed!"); return; } string strGateListen = CfgTool.Instance().GetCfgVal("GateListen", "tcp://*:44000"); if (FFGate.Instance().Init(strBrokerListen, strGateListen) == false) { FFLog.Trace("ffGate open failed!"); return; } bool bExit = false; AppDomain.CurrentDomain.ProcessExit += (sender, arg) => { FFLog.Trace("exit!"); bExit = true; }; Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) => { e.Cancel = true; FFLog.Trace("exit!!"); bExit = true; }; while (!bExit) { System.Threading.Thread.Sleep(300); } FFLog.Trace("exit!!!"); FFGate.Instance().Cleanup(); FFBroker.Instance().Cleanup(); FFWorker.Instance().Cleanup(); FFNet.Cleanup(); FFLog.Cleanup(); }
//! 转发消息给client public EmptyMsgRet RouteMsgToSession(GateRouteMsgToSessionReq reqMsg) { byte[] dataBody = reqMsg.Body;// Util.String2Byte(reqMsg.Body); foreach (var sessionID in reqMsg.SessionId) { if (m_dictClients.ContainsKey(sessionID) == false) { continue; } ClientInfo cinfo = m_dictClients[sessionID]; FFNet.SendMsg(cinfo.sockObj, (UInt16)reqMsg.Cmd, dataBody); } return(m_msgEmpty); }
public bool ConnectToBroker() { m_socketBroker = FFNet.Connect(m_strBrokerHost, new SocketMsgHandler(HandleMsg), new SocketBrokenHandler(HandleBroken)); if (null == m_socketBroker) { return(false); } RegisterToBrokerReq reqMsg = new RegisterToBrokerReq { Node_type = 2, Service_name = m_strServiceName }; FFNet.SendMsg(m_socketBroker, (UInt16)FFRPC_CMD.REGISTER_TO_BROKER_REQ, reqMsg); return(true); }
public void HandleMsg(IFFSocket ffsocket, UInt16 cmd, byte[] strMsg) { //FFLog.Trace(string.Format("FFBroker handleMsg....{0}, {1} [{2}]", cmd, strMsg.Length, System.Threading.Thread.CurrentThread.ManagedThreadId.ToString())); try { switch ((FFRPC_CMD)cmd) { case FFRPC_CMD.REGISTER_TO_BROKER_REQ: { RegisterToBrokerReq reqMsg = new RegisterToBrokerReq(); FFNet.DecodeMsg(reqMsg, strMsg); FFLog.Trace(string.Format("FFBroker handleMsg.REGISTER_TO_BROKER_REQ....{0}, {1}", reqMsg.Node_type, reqMsg.Service_name)); if (FFRPC_NODE_TYPE.RPC_NODE == (FFRPC_NODE_TYPE)reqMsg.Node_type) { if (m_brokerData.Service2node_id.ContainsKey(reqMsg.Service_name)) { FFLog.Error(string.Format("FFBroker handleMsg servicename exist....{0}, {1}", reqMsg.Node_type, reqMsg.Service_name)); ffsocket.Close(); return; } Int64 nNodeID = allocNodeId(); m_dictSockets[nNodeID] = ffsocket; m_brokerData.Service2node_id[reqMsg.Service_name] = nNodeID; m_brokerData.Node_id = nNodeID; SyncNodeInfo(m_brokerData, ffsocket); //!广播给所有的子节点 } } break; case FFRPC_CMD.BROKER_ROUTE_MSG: { BrokerRouteMsgReq reqMsg = new BrokerRouteMsgReq(); FFNet.DecodeMsg(reqMsg, strMsg); FFLog.Trace(string.Format("FFBroker.BROKER_ROUTE_MSG service={0},func={1} Callback={2}", reqMsg.Dest_service_name, reqMsg.Dest_msg_name, reqMsg.Callback_id)); if (!m_dictSockets.ContainsKey(reqMsg.Dest_node_id)) { return; } IFFSocket destSocket = m_dictSockets[reqMsg.Dest_node_id]; FFNet.SendMsg(destSocket, (UInt16)FFRPC_CMD.BROKER_TO_CLIENT_MSG, reqMsg); } break; default: break; } } catch (Exception ex) { FFLog.Error("FFBroker.Error:" + ex.Message); } }
public bool connectToBroker() { m_socketBroker = FFNet.connect(m_strBrokerIP, m_nBrokerPort, new SocketMsgHandler(handleMsg), new SocketBrokenHandler(handleBroken)); if (null == m_socketBroker) { return(false); } RegisterToBrokerReq reqMsg = new RegisterToBrokerReq(); reqMsg.Node_type = 2; reqMsg.Service_name = m_strServiceName; FFNet.sendMsg(m_socketBroker, 2, reqMsg); return(true); }
public void AsyncSend(byte[] strData) { FFNet.GetTaskQueue().Post(() => { if (strData.Length == 0 || m_oSocket == null) { return; } m_oBuffSending.Add(strData); if (m_oBuffSending.Count == 1) { m_oSocket.BeginSend(strData, 0, strData.Length, 0, new AsyncCallback(handleSendEnd), m_oSocket); } }); }
private void SyncNodeInfo(RegisterToBrokerRet retMsg, IFFSocket ffsocket)//! 同步给所有的节点,当前的各个节点的信息 { //!广播给所有的子节点 foreach (IFFSocket s in m_dictSockets.Values) { if (s == ffsocket) { retMsg.Register_flag = 1; } else { retMsg.Register_flag = 0; } FFNet.SendMsg(s, (UInt16)FFRPC_CMD.REGISTER_TO_BROKER_RET, retMsg); } }
public bool Open(string strBrokerHost, int nWorkerIndex) { m_nWorkerIndex = nWorkerIndex; m_strWorkerName = string.Format("worker#{0}", m_nWorkerIndex); m_ffrpc = new FFRpc(m_strWorkerName); if (m_ffrpc.Open(strBrokerHost) == false) { FFLog.Error("worker ffrpc open failed!"); return(false); } m_ffrpc.Reg <RouteLogicMsgReq, EmptyMsgRet>(this.OnRouteLogicMsgReq); m_ffrpc.Reg <SessionOfflineReq, EmptyMsgRet>(this.OnSessionOfflineReq); FFNet.Timerout(1000, this.HandleMonsterAI); return(true); }
public bool Open(string strBrokerCfg) { if (strBrokerCfg.Length > 0) { m_strListenHost = strBrokerCfg; } m_acceptor = FFNet.Listen(m_strListenHost, new SocketMsgHandler(HandleMsg), new SocketBrokenHandler(HandleBroken)); if (m_acceptor != null) { FFLog.Trace(string.Format("FFBroker open....{0} ok", m_strListenHost)); } else { FFLog.Trace(string.Format("FFBroker open....{0} failed", m_strListenHost)); } return(true); }
public bool Call <MSG_TYPE>(string strServiceName, MSG_TYPE msgData) where MSG_TYPE : Thrift.Protocol.TBase, new() { if (!m_brokerData.Service2node_id.ContainsKey(strServiceName)) { FFLog.Trace(string.Format("ffrpc.Call servervice:{0} not exist", strServiceName)); return(false); } BrokerRouteMsgReq reqMsg = new BrokerRouteMsgReq() { Callback_id = 0, Err_info = "" }; reqMsg.Dest_node_id = m_brokerData.Service2node_id[strServiceName]; reqMsg.Dest_service_name = strServiceName; reqMsg.Body = Util.Byte2String(FFNet.EncodeMsg(msgData)); reqMsg.Dest_msg_name = Type2Name(msgData); SendToDestNode(reqMsg); return(true); }
public void HandleClose() { if (m_nStatus == 0) { return; } m_nStatus = 0; FFNet.GetTaskQueue().Post(() => { if (m_oSocket == null) { return; } m_oSocket.Close(); m_oSocket = null; m_oBuffSending.Clear(); m_funcBroken(this); }); }
public void AsyncSend(byte[] strData, bool bCheckSend = true) { FFNet.GetTaskQueue().Post(() => { if (strData.Length == 0 || m_oSocket == null) { return; } if (bCheckSend == true && m_funcPreSendCheck != null) { strData = m_funcPreSendCheck(strData); } m_oBuffSending.Add(strData); if (m_oBuffSending.Count == 1) { m_oSocket.BeginSend(strData, 0, strData.Length, 0, new AsyncCallback(handleSendEnd), m_oSocket); } }); }
public void SendToDestNode(BrokerRouteMsgReq retMsg) { retMsg.From_node_id = m_nNodeID; FFNet.SendMsg(m_socketBroker, (UInt16)FFRPC_CMD.BROKER_ROUTE_MSG, retMsg); }
public static void onRecv(FFSocket ffsocket, Int16 cmd, string strData) { Console.WriteLine("onRecv....{0}, {1}", strData, cmd); FFNet.sendMsg(ffsocket, cmd, strData); }
public TaskQueue GetTaskQueue() { return(FFNet.GetTaskQueue()); }
public void HandleMsg(IFFSocket ffsocket, UInt16 cmd, string strMsg) { //FFLog.Trace(string.Format("ffrpc.FFRpc handleMsg....{0}, {1} [{2}]", cmd, strMsg.Length, System.Threading.Thread.CurrentThread.ManagedThreadId.ToString())); try { switch ((FFRPC_CMD)cmd) { case FFRPC_CMD.REGISTER_TO_BROKER_RET: { FFNet.DecodeMsg(m_brokerData, strMsg); FFLog.Trace(string.Format("ffrpc.handleMsg..REGISTER_TO_BROKER_RET..{0}, {1}", m_brokerData.Node_id, m_brokerData.Register_flag)); if (m_brokerData.Register_flag == 1) { m_nNodeID = m_brokerData.Node_id; //! -1表示注册失败,0表示同步消息,1表示注册成功 } } break; case FFRPC_CMD.BROKER_TO_CLIENT_MSG: { BrokerRouteMsgReq reqMsg = new BrokerRouteMsgReq(); FFNet.DecodeMsg(reqMsg, strMsg); FFLog.Trace(string.Format("ffrpc.BROKER_TO_CLIENT_MSG msgname={0}", reqMsg.Dest_msg_name)); if (reqMsg.Err_info.Length > 0) { FFLog.Error(string.Format("FFRpc::handleRpcCallMsg error={0}", reqMsg.Err_info)); if (reqMsg.Callback_id == 0) { return; } } try { if (reqMsg.Dest_service_name.Length > 0) { if (!m_dictFuncs.ContainsKey(reqMsg.Dest_msg_name)) { reqMsg.Err_info = "interface named " + reqMsg.Dest_msg_name + " not found in rpc"; FFLog.Error(string.Format("FFRpc::handleRpcCallMsg error={0}", reqMsg.Err_info)); reqMsg.Dest_node_id = reqMsg.From_node_id; reqMsg.Dest_service_name = ""; SendToDestNode(reqMsg); return; } FFRpcFunc destFunc = m_dictFuncs[reqMsg.Dest_msg_name]; destFunc(reqMsg); } else { if (!m_dictCallBack.ContainsKey(reqMsg.Callback_id)) { return; } FFRpcFunc destFunc = m_dictCallBack[reqMsg.Callback_id]; destFunc(reqMsg); } } catch (Exception ex) { FFLog.Error("ffrpc handleMsg" + ex.Message); } } break; default: break; } } catch (Exception ex) { FFLog.Error("ffprc.Error:" + ex.Message); } }
public bool Init() { //InitRobot(); int nGenId = 10000; int num = 0; for (int i = 0; i < 3; ++i) { string strName = string.Format("尸霸{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 18 + 20 - (int)MapCfg.CenterX + i * 2, y = 28 + 30 - (int)MapCfg.CenterY - i, apprID = 69 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("蓝魔{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 12 + 20 - (int)MapCfg.CenterX + i * 2, y = 32 + 30 - (int)MapCfg.CenterY - i, apprID = 102 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("山魔{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 15 + 20 - (int)MapCfg.CenterX + i * 2, y = 40 + 30 - (int)MapCfg.CenterY - i, apprID = 103 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("黑暗魔王{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 20 + 20 - (int)MapCfg.CenterX + i * 2, y = 40 + 30 - (int)MapCfg.CenterY - i, apprID = 104 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("双足蜥蜴{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 25 + 20 - (int)MapCfg.CenterX + i * 2, y = 39 + 30 - (int)MapCfg.CenterY - i, apprID = 105 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("变异蜘蛛{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 25 + 20 - (int)MapCfg.CenterX + i * 2, y = 28 + 30 - (int)MapCfg.CenterY - i, apprID = 106 }; RoleMgr.Instance().AddRole(mon); } for (int i = 0; i < num; ++i) { string strName = string.Format("土妖{0}", i + 1); nGenId++; var mon = new Monster() { nSessionID = nGenId, strName = strName, x = 16 + 20 - (int)MapCfg.CenterX + i * 2, y = 30 - i, apprID = 100 }; RoleMgr.Instance().AddRole(mon); } FFNet.TimeroutLoop(1000, this.HandleMonsterAI, "HandleMonsterAI"); return(true); }