text:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <time.h>
#include <ctype.h>

#include "timestamp.h"

/*
%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中，十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字，使用基于周的年
%G 年分，使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟：hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒：hh:mm:ss
%u 每周的第几天，星期一为第一天 （值从0到6，星期一为0）
%U 第年的第几周，把星期日做为第一天（值从0到53）
%V 每年的第几周，使用基于周的年
%w 十进制表示的星期几（值从0到6，星期天为0）
%W 每年的第几周，把星期一做为第一天（值从0到53）
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份（值从0到99）
%Y 带世纪部分的十进制年份
%z，%Z 时区名称，如果不能得到时区名称则返回空字符。
*/
#define TM_YEAR_BASE 1900

/*
* We do not implement alternate representations. However, we always
* check whether a given modifier is allowed for a certain conversion.
*/
#define ALT_E     0x01
#define ALT_O     0x02
#define LEGAL_ALT(x)    { if (alt_format & ~(x)) return (0); }

static  int conv_num(const char **, int *, int, int);

static const char *day[7] = {
	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
	"Friday", "Saturday"
};
static const char *abday[7] = {
	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char *mon[12] = {
	"January", "February", "March", "April", "May", "June", "July",
	"August", "September", "October", "November", "December"
};
static const char *abmon[12] = {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const char *am_pm[2] = {
	"AM", "PM"
};

//window上自己实现my_strptime函数，linux已经提供my_strptime
//my_strptime函数windows平台上实现
char*
my_strptime(const char *buf, const char *fmt, struct tm *tm)
{
	char c;
	const char *bp;
	size_t len = 0;
	int alt_format, i, split_year = 0;

	bp = buf;

	while ((c = *fmt) != '\0') {
		/* Clear `alternate' modifier prior to new conversion. */
		alt_format = 0;

		/* Eat up white-space. */
		if (isspace(c)) {
			while (isspace(*bp))
				bp++;

			fmt++;
			continue;
		}

		if ((c = *fmt++) != '%')
			goto literal;

again:
	switch (c = *fmt++) {
	case '%': /* "%%" is converted to "%". */
		literal :
			if (c != *bp++)
				return (0);
		break;

		/*
		* "Alternative" modifiers. Just set the appropriate flag
		* and start over again.
		*/
	case 'E': /* "%E?" alternative conversion modifier. */
		LEGAL_ALT(0);
		alt_format |= ALT_E;
		goto again;

	case 'O': /* "%O?" alternative conversion modifier. */
		LEGAL_ALT(0);
		alt_format |= ALT_O;
		goto again;

		/*
		* "Complex" conversion rules, implemented through recursion.
		*/
	case 'c': /* Date and time, using the locale's format. */
		LEGAL_ALT(ALT_E);
		if (!(bp = my_strptime(bp, "%x %X", tm)))
			return (0);
		break;

	case 'D': /* The date as "%m/%d/%y". */
		LEGAL_ALT(0);
		if (!(bp = my_strptime(bp, "%m/%d/%y", tm)))
			return (0);
		break;

	case 'R': /* The time as "%H:%M". */
		LEGAL_ALT(0);
		if (!(bp = my_strptime(bp, "%H:%M", tm)))
			return (0);
		break;

	case 'r': /* The time in 12-hour clock representation. */
		LEGAL_ALT(0);
		if (!(bp = my_strptime(bp, "%I:%M:%S %p", tm)))
			return (0);
		break;

	case 'T': /* The time as "%H:%M:%S". */
		LEGAL_ALT(0);
		if (!(bp = my_strptime(bp, "%H:%M:%S", tm)))
			return (0);
		break;

	case 'X': /* The time, using the locale's format. */
		LEGAL_ALT(ALT_E);
		if (!(bp = my_strptime(bp, "%H:%M:%S", tm)))
			return (0);
		break;

	case 'x': /* The date, using the locale's format. */
		LEGAL_ALT(ALT_E);
		if (!(bp = my_strptime(bp, "%m/%d/%y", tm)))
			return (0);
		break;

		/*
		* "Elementary" conversion rules.
		*/
	case 'A': /* The day of week, using the locale's form. */
	case 'a':
		LEGAL_ALT(0);
		for (i = 0; i < 7; i++) {
			/* Full name. */
			len = strlen(day[i]);
			if (strncmp(day[i], bp, len) == 0)
				break;

			/* Abbreviated name. */
			len = strlen(abday[i]);
			if (strncmp(abday[i], bp, len) == 0)
				break;
		}

		/* Nothing matched. */
		if (i == 7)
			return (0);

		tm->tm_wday = i;
		bp += len;
		break;

	case 'B': /* The month, using the locale's form. */
	case 'b':
	case 'h':
		LEGAL_ALT(0);
		for (i = 0; i < 12; i++) {
			/* Full name. */
			len = strlen(mon[i]);
			if (strncmp(mon[i], bp, len) == 0)
				break;

			/* Abbreviated name. */
			len = strlen(abmon[i]);
			if (strncmp(abmon[i], bp, len) == 0)
				break;
		}

		/* Nothing matched. */
		if (i == 12)
			return (0);

		tm->tm_mon = i;
		bp += len;
		break;

	case 'C': /* The century number. */
		LEGAL_ALT(ALT_E);
		if (!(conv_num(&bp, &i, 0, 99)))
			return (0);

		if (split_year) {
			tm->tm_year = (tm->tm_year % 100) + (i * 100);
		}
		else {
			tm->tm_year = i * 100;
			split_year = 1;
		}
		break;

	case 'd': /* The day of month. */
	case 'e':
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
			return (0);
		break;

	case 'k': /* The hour (24-hour clock representation). */
		LEGAL_ALT(0);
		/* FALLTHROUGH */
	case 'H':
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
			return (0);
		break;

	case 'l': /* The hour (12-hour clock representation). */
		LEGAL_ALT(0);
		/* FALLTHROUGH */
	case 'I':
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
			return (0);
		if (tm->tm_hour == 12)
			tm->tm_hour = 0;
		break;

	case 'j': /* The day of year. */
		LEGAL_ALT(0);
		if (!(conv_num(&bp, &i, 1, 366)))
			return (0);
		tm->tm_yday = i - 1;
		break;

	case 'M': /* The minute. */
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
			return (0);
		break;

	case 'm': /* The month. */
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &i, 1, 12)))
			return (0);
		tm->tm_mon = i - 1;
		break;

	case 'p': /* The locale's equivalent of AM/PM. */
		LEGAL_ALT(0);
		/* AM? */
		if (strcmp(am_pm[0], bp) == 0) {
			if (tm->tm_hour > 11)
				return (0);

			bp += strlen(am_pm[0]);
			break;
		}
		/* PM? */
		else if (strcmp(am_pm[1], bp) == 0) {
			if (tm->tm_hour > 11)
				return (0);

			tm->tm_hour += 12;
			bp += strlen(am_pm[1]);
			break;
		}

		/* Nothing matched. */
		return (0);

	case 'S': /* The seconds. */
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
			return (0);
		break;

	case 'U': /* The week of year, beginning on sunday. */
	case 'W': /* The week of year, beginning on monday. */
		LEGAL_ALT(ALT_O);
		/*
		* XXX This is bogus, as we can not assume any valid
		* information present in the tm structure at this
		* point to calculate a real value, so just check the
		* range for now.
		*/
		if (!(conv_num(&bp, &i, 0, 53)))
			return (0);
		break;

	case 'w': /* The day of week, beginning on sunday. */
		LEGAL_ALT(ALT_O);
		if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
			return (0);
		break;

	case 'Y': /* The year. */
		LEGAL_ALT(ALT_E);
		if (!(conv_num(&bp, &i, 0, 9999)))
			return (0);

		tm->tm_year = i - TM_YEAR_BASE;
		break;

	case 'y': /* The year within 100 years of the epoch. */
		LEGAL_ALT(ALT_E | ALT_O);
		if (!(conv_num(&bp, &i, 0, 99)))
			return (0);

		if (split_year) {
			tm->tm_year = ((tm->tm_year / 100) * 100) + i;
			break;
		}
		split_year = 1;
		if (i <= 68)
			tm->tm_year = i + 2000 - TM_YEAR_BASE;
		else
			tm->tm_year = i + 1900 - TM_YEAR_BASE;
		break;

		/*
		* Miscellaneous conversions.
		*/
	case 'n': /* Any kind of white-space. */
	case 't':
		LEGAL_ALT(0);
		while (isspace(*bp))
			bp++;
		break;

	default:  /* Unknown/unsupported conversion. */
		return (0);
	}

	}

	/* LINTED functional specification */
	return ((char *)bp);
}

static int
conv_num(const char **buf, int *dest, int llim, int ulim)
{
	int result = 0;

	/* The limit also determines the number of valid digits. */
	int rulim = ulim;

	if (**buf < '0' || **buf > '9')
		return (0);

	do {
		result *= 10;
		result += *(*buf)++ - '0';
		rulim /= 10;
	} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');

	if (result < llim || result > ulim)
		return (0);

	*dest = result;
	return (1);
}

unsigned long
timestamp() {
	time_t t;
	t = time(NULL); // C库的系统函数，获取当前系统的时间戳

	return (unsigned long)t;
}

unsigned long
date2timestamp(const char* fmt_date, const char* date) {
	struct tm tmp_time;
	memset(&tmp_time, 0, sizeof(struct tm));

	// linux上面有，windows上面没有。
	my_strptime(date, fmt_date, &tmp_time);
	time_t t = mktime(&tmp_time);
	return (unsigned long)t;
}

void
timestamp2date(unsigned long t,const char*fmt_date, char* out_buf, int buf_len) {
	time_t t_value = (time_t)t;
	struct tm* date = localtime(&t_value);
	strftime(out_buf, buf_len, fmt_date, date);

}

unsigned long
timestamp_today() {
	time_t now;
	now = time(NULL);
	struct tm* date = localtime(&now);
	date->tm_hour = 0;
	date->tm_min = 0;
	date->tm_sec = 0;

	time_t today = mktime(date);
	return (unsigned long)today;
}

unsigned long
timestamp_yesterday() {
	unsigned long today = timestamp_today();
	unsigned long yesterday = today - 24 * 60 * 60;
	return (unsigned long)yesterday;
}


text:
#ifndef __TIMESTAMP_H__
#define __TIMESTAMP_H__

#ifdef __cplusplus
extern "C" {
#endif

	// 获取当前的时间戳
	unsigned long timestamp();

	// 获取给定日期的时间戳"%Y(年)%m(月)%d(日)%H(小时)%M(分)%S(秒)"
	unsigned long date2timestamp(const char* fmt_date, const char* date);

	// fmt_date "%Y(年)%m(月)%d(日)%H(小时)%M(分)%S(秒)"
	void timestamp2date(unsigned long t,const char*fmt_date, char* out_buf, int buf_len);

	unsigned long timestamp_today();

	unsigned long timestamp_yesterday();

#ifdef __cplusplus
}
#endif

#endif

mime_type: text/plain


text:
#include "DebugUtil.h"
#include "../logger/logger.h"
#include <iostream>
#include <strstream>
#include <sstream>
#include <strstream>
#include <string>
using namespace std;
void DebugUtil::LogByteArray(unsigned char* data, int len)
{
	ostringstream os;
	for (auto i = 0; i < len; i++)
	{
		os << (int)(data[i]);
	}
	log_debug(os.str().c_str());
}


text:
#ifndef __Debug_Util_H__
#define __Debug_Util_H__

class DebugUtil
{
public:
	static void LogByteArray(unsigned char* data, int len);
};

#endif // !__Debug_Util_H__


text:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "uv.h"
#include "time_list.h"

#define my_alloc malloc
#define my_free free

typedef struct timer {
	uv_timer_t uv_timer; // libuv timer handle
	void(*on_timer)(void* udata);
	void* udata;
	int repeat_count; // -1一直循环;
}timer;

static struct timer*
alloc_timer(void(*on_timer)(void* udata),
            void* udata, int repeat_count) {
	struct timer* t = my_alloc(sizeof(struct timer));
	memset(t, 0, sizeof(struct timer));

	t->on_timer = on_timer;
	t->repeat_count = repeat_count;
	t->udata = udata;
	uv_timer_init(uv_default_loop(), &t->uv_timer);
	return t;
}

static void
free_timer(struct timer* t) {
	my_free(t);
}

static void
on_uv_timer(uv_timer_t* handle) {
	struct timer* t = handle->data;
	if (t->repeat_count < 0) { // 不断的触发;
		t->on_timer(t->udata);
	}
	else {
		t->repeat_count --;
		t->on_timer(t->udata);
		if (t->repeat_count == 0) { // 函数time结束
			uv_timer_stop(&t->uv_timer); // 停止这个timer
			free_timer(t);
		}
	}

}

struct timer*
schedule_repeat(void(*on_timer)(void* udata),
         void* udata,
		 int after_msec,
         int repeat_count,int repeat_msec) {
	struct timer* t = alloc_timer(on_timer, udata, repeat_count);

	// 启动一个timer;
	t->uv_timer.data = t;
	uv_timer_start(&t->uv_timer, on_uv_timer, after_msec, repeat_msec);
	// end
	return t;
}

void
cancel_timer(struct timer* t) {
	if (t->repeat_count == 0) { // 全部触发完成，;
		return;
	}
	uv_timer_stop(&t->uv_timer);
	free_timer(t);
}

struct timer*
schedule_once(void(*on_timer)(void* udata),
              void* udata,
			  int after_msec) {
	return schedule_repeat(on_timer, udata, after_msec, 1, after_msec);
}

void* get_timer_udata(timer* t)
{
	return t->udata;
}


text:
#ifndef __MY_TIMER_LIST_H__
#define __MY_TIMER_LIST_H__

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

// on_timer是一个回掉函数,当timer触发的时候调用;
// udata: 是用户传的自定义的数据结构;
// on_timer执行的时候 udata,就是你这个udata;
// after_sec: 多少秒开始执行;
// repeat_count: 执行多少次, repeat_count == -1一直执行;
// 返回timer的句柄;
struct timer;

struct timer*
schedule_repeat(void(*on_timer)(void* udata),
         void* udata,
		 int delay,
		 int repeat_count,
		int repeat_msec);

// 取消掉这个timer;
void
cancel_timer(struct timer* t);

struct timer*
schedule_once(void(*on_timer)(void* udata),
              void* udata,
			  int after_msec);

void* get_timer_udata(struct timer* t);

#ifdef __cplusplus
}
#endif // __cplusplus

#endif


text:
return {
    Auth = 1,
    System = 2,
    Logic = 3,
};


text:
return {
	Ok = 0,
	SystemError = -100,
	UserIsFreeze = -101,
	InvalidParams = -103,
	UnameHasExist = -104,
	UnameOrPwdError = -105,
	InvalidOperate = -106,
};


text:
local ServiceType = require("ServiceType");
local ProtoType=require("ProtoType");

local remote_servers={};

--注册服务所部署的IP地址和端口
remote_servers[ServiceType.Auth]={
    serviceType = ServiceType.Auth,
    ip = "127.0.0.1",
    port = 6081,
    descrip = "Auth Server",
};

-- remote_servers[ServiceType.System]={
--     serviceType = ServiceType.System,
--     ip = "127.0.0.1",
--     port = 8001,
--     descrip = "System Server",
-- };

remote_servers[ServiceType.Logic]={
    serviceType = ServiceType.Logic,
    ip = "127.0.0.1",
    port = 6082,
    descrip = "Logic Server",
};

return {

    protoType=ProtoType.Protobuf;

    gateway_tcp_ip = "121.196.178.141",
    gateway_tcp_port = 6080,

    enable_gateway_log=false;
    enable_proto_log=false;
    enable_match_log=true;

    servers = remote_servers,

    auth_mysql={
        host="127.0.0.1",
        port=3306,
        dbName="xxxxx",
        uname="xxxxx",
        upwd="xxxxx",
	},

    game_mysql={
        host="127.0.0.1",
        port=3306,
        dbName="xxxxx",
        uname="xxxxx",
        upwd="xxxxx",
    },

    center_redis={
        host="127.0.0.1",
        port=6379,
        db_index=1,
        auth="xxxxx",
    },

    game_redis={
        host="127.0.0.1",
        port=6379,
        db_index=2,
        auth="xxxxx",
    },
    logic_udp={
        host="127.0.0.1",
        port=8800,
    },
};


text:
return {
    Json=0,
    Protobuf=1,
};


text:
local config=require("GameConfig");
local mysqlConn=nil;

--链接数据库
local function mysql_connect_to_auth_center()

	if mysqlConn then
		return;
	end

	local authConfig = config.auth_mysql;
	Mysql.Connect(
		authConfig.host,
		authConfig.port,
		authConfig.dbName,
		authConfig.uname,
		authConfig.upwd,
		function ( err,conn )
			if err then
				Debug.LogError(err);
				Timer.Once(mysql_connect_to_auth_center,5000);
				return;
			end
			Debug.Log("connect to mysql [ auth_center_db ] success");
			mysqlConn=conn;
		end);
end

--根据guest_key获取uinfo
--handler:err,uinfo
local function get_uinfo_by_key( key,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql="select uid,unick,usex,uface,uvip,status,is_guest from uinfo where guest_key=\"%s\" limit 1";
	sql=string.format(sql,key);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local uinfo =
		{
			uid= tonumber(result[1]),
			unick=result[2],
			usex=tonumber(result[3]),
			uface=tonumber(result[4]),
			uvip=tonumber(result[5]),
			status=tonumber(result[6]),
			is_guest=tonumber(result[7]),
		};
		if handler then
			handler(nil,uinfo);
		end
	end);
end

--根据uid获取用户信息
local function get_uinfo_by_uid( uid,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql="select uid,unick,usex,uface,uvip,status,is_guest from uinfo where uid=\"%d\" limit 1";
	sql=string.format(sql,uid);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local uinfo =
		{
			uid= tonumber(result[1]),
			unick=result[2],
			usex=tonumber(result[3]),
			uface=tonumber(result[4]),
			uvip=tonumber(result[5]),
			status=tonumber(result[6]),
			is_guest=tonumber(result[7]),
		};
		if handler then
			handler(nil,uinfo);
		end
	end);
end

--插入guest_key
--handler: err
local function insert_guest_user( key,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end
	local sql="insert into uinfo(guest_key,unick,uface,usex,is_guest)values(\"%s\",\"%s\",%d,%d,1)";
	local unick = "gst"..math.random(100000,999999);
	local uface = math.random(1,9);
	local usex = math.random(0,1);
	sql=string.format(sql,key,unick,uface,usex);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err);
			end
			return;
		end
		if handler then
			handler(nil);
		end
	end);
end

--修改用户信息
--handler: err
local function edit_profile(uid,unick,uface,usex,handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end

	local sql = 'update uinfo set unick="%s",usex=%d,uface=%d where uid=%d';
	sql=string.format(sql,unick,usex,uface,uid);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				handler(err);
			else
				handler(nil);
			end
		end);
end

--判断用户名是否存在
--handler: err,foundUid
local function check_uname_exist(	uname,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql = 'select uid from usertable where uname="%s"';
	sql=string.format(sql,uname);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				if handler then
					handler(err,nil);
				end
				return;
			end
			if ret==nil or #ret<=0 then
				if handler then
					handler(err,nil);
				end
				return;
			end
			if handler then
				local result = ret[1];
				handler(err,result);
			end
		end);
end

--根据用户名密码查找用户信息
--handler:err,uinfo
local function get_uinfo_by_uname_pwd( uname,upwd,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end

	local sql="select uid,uname,pwd,unick,ulevel,uexp,urank,ucoin,udiamond,usignature,uintegrity,status,uface,heros,urankExp from usertable where uname=\"%s\" and pwd=\"%s\" limit 1";
	sql=string.format(sql,uname,upwd);
	--print(sql);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local uinfo =
		{
			uid= tonumber(result[1]),
			uname=result[2],
			pwd=result[3],
			unick=result[4],
			ulevel=tonumber(result[5]),
			uexp=tonumber(result[6]),
			urank=tonumber(result[7]),
			ucoin=tonumber(result[8]),
			udiamond=tonumber(result[9]),
			usignature=result[10],
			uintegrity=tonumber(result[11]),
			status=tonumber(result[12]),
			uface=tonumber(result[13]),
			heros=result[14],
			urankExp=tonumber(result[15]),
		};
		if handler then
			handler(nil,uinfo);
		end
	end);
end

--根据用户名获取匹配信息
--handler:err,matcherinfo
local function get_matcherinfo_by_uname(uname,handler)

	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end

	local sql="select unick,urank,uface,ulevel from usertable where uname=\"%s\" limit 1";
	sql=string.format(sql,uname);

	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local matchInfo =
		{
			unick=result[1],
			urank=tonumber(result[2]),
			uface=tonumber(result[3]),
			ulevel=tonumber(result[4]),
		};
		if handler then
			handler(nil,matchInfo);
		end
	end);
end

--根据用户名获取默认英雄
local function get_default_heroId_by_uname(uname,handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end

	local sql="select heros from usertable where uname=\"%s\" limit 1";
	sql=string.format(sql,uname);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local  startIndex, endIndex = string.find(result[1],",",1);
		local defaultHeroId=tonumber(string.sub(result[1],1,startIndex));
		if handler then
			handler(nil,defaultHeroId);
		end
	end);
end

--根据用户名，密码，昵称注册
local function registe(uname,pwd,unick,handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end
	local sql="insert into usertable(uname,pwd,unick)values(\"%s\",\"%s\",\"%s\")";
	sql=string.format(sql,uname,pwd,unick);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err);
			end
			return;
		end
		if handler then
			handler(nil);
		end
	end);
end

--根据用户名获取仓库信息
--handler(err,{ulevel,uexp,urank,urankExp,ucoin,udiamond})
local function get_package_info_by_uname(uname,handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end

	local sql="select ulevel,uexp,urank,urankExp,ucoin,udiamond from usertable where uname=\"%s\" limit 1";
	sql=string.format(sql,uname);
	--print(sql);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local packageInfo =
		{
			ulevel=tonumber(result[1]),
			uexp=tonumber(result[2]),
			urank=tonumber(result[3]),
			urankExp=tonumber(result[4]),
			ucoin=tonumber(result[5]),
			udiamond=tonumber(result[6]),
		};
		if handler then
			handler(nil,packageInfo);
		end
	end);
end

--根据uname更新仓库信息
--handler(err,{ulevel,uexp,urank,urankExp,ucoin,udiamond})
local function update_package_info_by_uname(uname,packageInfo,handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end

	local sql = 'update usertable set ulevel=%d,uexp=%d,urank=%d,urankExp=%d,ucoin=%d,udiamond=%d where uname=\"%s\"';
	sql=string.format(sql,packageInfo.ulevel,packageInfo.uexp,packageInfo.urank,packageInfo.urankExp,packageInfo.ucoin,
		packageInfo.udiamond,uname);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				handler(err);
			else
				handler(nil);
			end
		end);
end

return {
	Connect=mysql_connect_to_auth_center,
	GetUinfoByKey=get_uinfo_by_key,
	GetUinfoByUid=get_uinfo_by_uid,
	GetUinfoByUnamePwd=get_uinfo_by_uname_pwd,
	GetMatcherInfoByUname=get_matcherinfo_by_uname,
	GetDefaultHeroIdByUname=get_default_heroId_by_uname,
	EditProfile=edit_profile,
	CheckUnameExist=check_uname_exist,
	IsConnect=function() return mysqlConn~=nil end,
	Registe=registe,
	GetPackageInfoByUname=get_package_info_by_uname,
	UpdatePackageInfoByUname=update_package_info_by_uname,
};


text:
local config=require("GameConfig");
local mobaConfig = require("MobaConfig");
local mysqlConn=nil;

--链接数据库
local function mysql_connect_to_game_center()

	if mysqlConn then
		return;
	end

	local gameConfig = config.game_mysql;
	Mysql.Connect(
		gameConfig.host,
		gameConfig.port,
		gameConfig.dbName,
		gameConfig.uname,
		gameConfig.upwd,
		function ( err,conn )
			if err then
				Debug.LogError(err);
				Timer.Once(mysql_connect_to_game_center,5000);
				return;
			end
			Debug.Log("connect to mysql [ moba_game ] success");
			mysqlConn=conn;
		end);
end

--获取游戏数据
--handler: err,uinfo
local function get_ugame_info( uid,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql="select ucoin_1,ucoin_2,uexp,uvip,uitem_1,uitem_2,ustatus from ugame where uid=%d limit 1";
	sql=string.format(sql,uid);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local uinfo =
		{
			ucoin_1= tonumber(result[1]),
			ucoin_2=tonumber(result[2]),
			uexp=tonumber(result[3]),
			uvip=tonumber(result[4]),
			uitem_1=tonumber(result[5]),
			uitem_2=tonumber(result[6]),
			ustatus=tonumber(result[7]),
		};
		if handler then
			handler(nil,uinfo);
		end
	end);
end

--插入游戏数据
--handler: err
local function insert_ugame_info( uid,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end
	local sql="insert into ugame(uid,ucoin_1,ucoin_2,uvip,uexp)values(%d,%d,%d,%d,%d)";
	sql=string.format(sql,uid,mobaConfig.ugame.ucoin_1,mobaConfig.ugame.ucoin_2,mobaConfig.ugame.uvip,mobaConfig.ugame.uexp);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err);
			end
			return;
		end
		if handler then
			handler(nil);
		end
	end);
end

--获取登陆奖励信息
--handler: err,bonuesInfo
local function get_bonues_info( uid,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql="select bonues,status,bonues_time,days from login_bonues where uid=%d limit 1";
	sql=string.format(sql,uid);
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据
		local result = ret[1];
		local bonuesInfo =
		{
			bonues= tonumber(result[1]),
			status=tonumber(result[2]),
			bonues_time=tonumber(result[3]),
			days=tonumber(result[4]),
		};
		if handler then
			handler(nil,bonuesInfo);
		end
	end);
end

--插入登陆奖励
--handler: err
local function insert_bonues_info( uid,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end
	local sql="insert into login_bonues(uid,bonues_time,status)values(%d,%d,1)";
	sql=string.format(sql,uid,Utils.TimeStamp());
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err);
			end
			return;
		end
		if handler then
			handler(nil);
		end
	end);
end

--更新登陆信息
--handler: err
local function set_bonues_info( uid,uinfo,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end

	local sql = 'update login_bonues set status=0,bonues=%d,bonues_time=%d,days=%d where uid=%d';
	sql=string.format(sql,uinfo.bonues,uinfo.bonues_time,uinfo.days,uid);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				handler(err);
			else
				handler(nil);
			end
		end);
end

--添加货币一
local function add_coin( uid,coin_1,handler )
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end

	local sql = 'update ugame set ucoin_1=ucoin_1+%d where uid=%d';
	sql=string.format(sql,coin_1,uid);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				handler(err);
			else

				handler(nil);
			end
		end);
end

--修改登陆奖励信息
--handle: err
local function update_login_bonues_status( uid,handler )

	if handler ==nil then
		Debug.LogWarning("[update_login_bonues_status( uid,handler )]Handler is nil ??");
		return;
	end
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected");
		end
		return;
	end

	local sql = 'update login_bonues set status=1 where uid=%d';
	sql=string.format(sql,uid);
	Mysql.Query(mysqlConn,sql,
		function( err,ret )
			if err then
				if handler then
					handler(err);
				end
			else
				if handler then
					handler(nil);
				end
			end
		end);
end

--获取机器人信息
--handle: err,ret
local function get_robot_ugame_info(handler)
	if mysqlConn==nil then
		--数据库还没有联好
		if handler then
			handler("mysql is not connected",nil);
		end
		return;
	end
	local sql="select ucoin_1,ucoin_2,uexp,uvip,uitem_1,uitem_2,ustatus,uid from ugame where is_robot=1";
	Mysql.Query(mysqlConn,sql,function( err,ret )
		--出现错误
		if err then
			if handler then
				handler(err,nil);
			end
			return;
		end
		--没有查到数据
		if ret==nil or #ret <=0 then
--			print("no data found");
			if handler then
				handler(nil,nil);
			end
			return;
		end
		--查到数据

		local robots={};

		for k, result in pairs(ret) do
			local uinfo =
			{
				ucoin_1= tonumber(result[1]),
				ucoin_2=tonumber(result[2]),
				uexp=tonumber(result[3]),
				uvip=tonumber(result[4]),
				uitem_1=tonumber(result[5]),
				uitem_2=tonumber(result[6]),
				ustatus=tonumber(result[7]),
				uid=tonumber(result[8]),
			};
			table.insert(robots,uinfo);
		end

		if handler then
--			print("Get data :",#robots);
			handler(nil,robots);
		end
	end);
end

return {
	Connect=mysql_connect_to_game_center,
	GetUgameInfo=get_ugame_info,
	GetBonuesInfo=get_bonues_info,
	InsertBonuesInfo=insert_bonues_info,
	SetBonuesInfo=set_bonues_info,
	InsertUgameInfo=insert_ugame_info,
	UpdateLoginBonuesStatus=update_login_bonues_status,
	AddCoin1=add_coin,
	IsConnect=function() return mysqlConn~=nil end,
	GetRobotUgameInfo=get_robot_ugame_info,
}


text:
local config=require("GameConfig");
local conn=nil;

local function redis_connect_to_center()

	if conn then
		return;
	end

	local host = config.center_redis.host;
	local port = config.center_redis.port;
	local index = config.center_redis.db_index;

	Redis.Connect(host,port,
		function( err,redisConn )
			--链接错误，重连
			if err~=nil then
				Debug.LogError(err);
				Timer.Once(redis_connect_to_center,5000);
				return;
			end
			--连接成功
			conn=redisConn;
			Redis.Query(conn,"select "..index,
				function( err,ret )
					if err then
						Debug.LogError(err);
						return;
					end
					print("connect to redis [ "..index.." ] success");
				end)
		end);
end

local function set_uinfo( uid,uinfo,handler )
	if nil==conn then
		Debug.LogError("redis is not connected yet");
		return;
	end

	local cmd = "hmset moba_auth_center_user_uid_"..uid..
				" unick "..uinfo.unick..
				" usex ".. uinfo.usex..
				" uface "..uinfo.uface..
				" uvip ".. uinfo.uvip..
				" is_guest "..uinfo.is_guest;
	Redis.Query(conn,cmd,
		function ( err,ret )
			if err then
				Debug.LogError(err);
				return;
			end
			--print("[Redis]",ret);
			if handler then
				handler();
			end
		end);
end

--handler: err,uinfo
local function get_uinfo( uid,handler )
	if nil==conn then
		Debug.LogError("redis is not connected yet");
		return;
	end
	local cmd = "hgetall moba_auth_center_user_uid_"..uid;
	Redis.Query(conn,cmd,
		function ( err,ret )
			if err then
				Debug.LogError(err);
				if handler then
					handler(err,nil);
				end
				return;
			end

			if nil==ret or #ret < 10 then
				Debug.LogError("get ret error, wrong uid: ",uid,err);
				if handler then
					handler("get ret error",nil);
				end
				return;
			end

			local uinfo = {};
			uinfo.uid=uid;
			uinfo.unick=ret[2];
			uinfo.uface=tonumber(ret[4]);
			uinfo.uvip=tonumber(ret[6]);
			uinfo.usex=tonumber(ret[8]);
			uinfo.is_guest=tonumber(ret[10]);
			handler(nil,uinfo);
		end);
end

local function edit_profile( uid,unick,usex,uface )
	get_uinfo(uid,
		function ( err,uinfo )
			if err then
				Debug.LogError("redis get error");
				return;
			end
			uinfo.unick=unick;
			uinfo.usex=usex;
			uinfo.uface=uface;

			set_uinfo(uid,uinfo);
		end)
end

return {
	Connect=redis_connect_to_center,
	GetUinfo=get_uinfo,
	SetUinfo=set_uinfo,
	EditProfile=edit_profile,
	IsConnect=function() return conn~=nil end
};


text:
local config=require("GameConfig");
local conn=nil;

local function redis_connect_to_game()

	if conn then
		return;
	end

	local host = config.game_redis.host;
	local port = config.game_redis.port;
	local index = config.game_redis.db_index;

	Redis.Connect(host,port,
		function( err,redisConn )
			--链接错误，重连
			if err~=nil then
				Debug.LogError("Redis Connect Error",err);
				Timer.Once(redis_connect_to_game,5000);
				return;
			end
			--连接成功
			conn=redisConn;
			Redis.Query(conn,"select "..index,
				function( err,ret )
					if err then
						Debug.LogError(err);
						return;
					end
					print("connect to redis [ "..index.." ] success");
				end)
		end);
end

--设置用户游戏信息
local function set_ugame_info(uid,ugameinfo,handler)

--	print("flag 1");
	if conn==nil then
		--数据库还没有联好
		Debug.LogError("redis is not connected");
		return;
	end
	local cmd = "hmset moba_ugame_user_uid_"..uid..
			" ucoin_1 "..ugameinfo.ucoin_1..
			" uexp "..ugameinfo.uexp..
			" uvip ".. ugameinfo.uvip;
	Redis.Query(conn,cmd,
		function ( err,ret )
			if err then
				Debug.LogError(err);
				return;
			end
--			print("[Redis]",ret);
			if handler then
				handler();
			end
		end);
end

--获取用户游戏信息
--handler: err,ginfo
local function get_ugame_info(uid,handler)
	if nil==conn then
		Debug.LogError("redis is not connected yet");
		return;
	end
	local cmd = "hgetall moba_ugame_user_uid_"..uid;
	Redis.Query(conn,cmd,
		function ( err,ret )
			if err then
				Debug.LogError(err);
				if handler then
					handler(err,nil);
				end
				return;
			end
			local ginfo = {};
			ginfo.uid=uid;
			ginfo.ucoin_1=tonumber(ret[2]);
			ginfo.uexp=tonumber(ret[4]);
			ginfo.uvip=tonumber(ret[6]);
			handler(nil,ginfo);
		end);
end

--添加货币1
local function add_coin_1(uid,add_coin)
	get_ugame_info(uid,
		function(err,ginfo)
			if err then
				Debug.LogError(err);
				return;
			end
			ginfo.ucoin_1 = ginfo.ucoin_1 + add_coin;

			set_ugame_info(uid,ginfo);
		end);
end

return {
	Connect=redis_connect_to_game,
	IsConnect=function() return conn~=nil end,
	GetUgameInfo=get_ugame_info,
	SetUgameInfo=set_ugame_info,
	AddCoin1=add_coin_1,
};


text:
local mysql = require("database/mysql_center");
local sType = require("ServiceType");
local cmdType = require("auth/const/CmdType");
local responce = require("Respones");

local function on_user_registe(s,req)
    local utag=req[3];
    local info=req[4];
    local uname=info.uname;
    local pwd=info.pwd;
    local unick=info.unick;

    --检验参数合法性
    if string.len(uname) <=0 or string.len(pwd) <=0 or string.len(unick) <=0 then
        local res = {sType.Auth,cmdType.UserRegisteRes,utag,
        {
            status = responce.InvalidParams,
        }};
        Session.SendPackage(s,res);
        return;
    end

    mysql.CheckUnameExist(uname,function(err,uid)
        if err then
            Debug.LogError("Check uname err:"..err);
            local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                {
                    status = responce.SystemError
                }};
            Session.SendPackage(s,retMsg);
            return;
        end

        if uid then
            --重复注册
            local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                {
                    status = responce.UnameHasExist
                }};
            Session.SendPackage(s,retMsg);
            return;
        end

        mysql.Registe(uname,pwd,unick,function(err)
            if err then
                Debug.LogError("Registe error:"..err);
                local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                    {
                        status = responce.SystemError
                    }};
                Session.SendPackage(s,retMsg);
                return;
            end

            mysql.GetUinfoByUnamePwd(uname,pwd,function( err,uinfo )
                if err then
                    --告诉客户端某个错误信息
                    print("something wrong", err)
                    local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                        {
                            status = responce.SystemError
                        }};
                    Session.SendPackage(s,retMsg);
                    return;
                end
                --没有查到对应信息
                if uinfo==nil then
                    print("UnameOrPwdError");
                    local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                        {
                            status = responce.UnameOrPwdError,
                        }};
                    Session.SendPackage(s,retMsg);
                    return;
                end
                --找到对应游戏数据
                if uinfo.status~=0 then
                    --游客账号被查封
                    print("this key has been frozen");
                    local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                        {
                            status = responce.UserIsFreeze
                        }};
                    Session.SendPackage(s,retMsg);
                    return;
                end

                --登陆成功
                print(uinfo.uid.." "..uinfo.unick.." registe and login".." uface-"..uinfo.uface.." heros-"..uinfo.heros);

                local retMsg = {sType.Auth,cmdType.UserRegisteRes,utag,
                    {
                        status = responce.Ok,
                        uinfo = uinfo,
                    }};
                --print("send utag: ",utag);
                Session.SendPackage(s,retMsg);

            end);--mysql.GetUinfoByUnamePwd

        end);--mysql.Registe

    end);--mysql.CheckUnameExist
end

local function user_login( s,req )

    local utag = req[3];
    local preq = req[4];

    local uname = preq.uname;
    local pwd = preq.pwd;
    --检验参数合法性
    if string.len(uname) <=0 then
        print("upgrade failed: InvalidParams",uname,pwd);
        local res = {sType.Auth,cmdType.UserLoginRes,utag,
        {
            status = responce.InvalidParams,
        }};
        Session.SendPackage(s,res);
        return;
    end

    --检查用户名与密码是否正确

    mysql.GetUinfoByUnamePwd(uname,pwd,function( err,uinfo )
            if err then
                --告诉客户端某个错误信息
                print("something wrong", err)
                local retMsg = {sType.Auth,cmdType.UserLoginRes,utag,
                    {
                        status = responce.SystemError
                    }};
                Session.SendPackage(s,retMsg);
                return;
            end
            --没有查到对应信息
            if uinfo==nil then
                print("UnameOrPwdError");
                local retMsg = {sType.Auth,cmdType.UserLoginRes,utag,
                    {
                        status = responce.UnameOrPwdError,
                    }};
                Session.SendPackage(s,retMsg);
                return;
            end
            --找到对应游戏数据
            if uinfo.status~=0 then
                --游客账号被查封
                print("this key has been frozen");
                local retMsg = {sType.Auth,cmdType.UserLoginRes,utag,
                    {
                        status = responce.UserIsFreeze
                    }};
                Session.SendPackage(s,retMsg);
                return;
            end

            --登陆成功
            print(uinfo.uid.." "..uinfo.unick.." login".." uface-"..uinfo.uface.." heros-"..uinfo.heros);

            local retMsg = {sType.Auth,cmdType.UserLoginRes,utag,
                {
                    status = responce.Ok,
                    uinfo = uinfo,
                }};
            --print("send utag: ",utag);
            Session.SendPackage(s,retMsg);
        end);
end

local function user_unregister( s,req )
    local uid = req[3];

    local res = {sType.Auth,cmdType.UserUnregisterRes,uid,
    {
        status = responce.Ok,
    }};
    Session.SendPackage(s,res);
end

local function user_lost_conn(s, req)
    Debug.Log("a user disconnect from auth");
end

mysql.Connect();

return {
    UserLogin = user_login,
    UserUnregister=user_unregister,
    EditProfile=DoEditProfile,
    UserLostConn=user_lost_conn,
    OnUserRegiste=on_user_registe,
};


text:
--初始化日志模块
Debug.LogInit("../logs/auth","auth",true);

--读取配置文件
local sType = require("ServiceType");
local config = require("GameConfig");

--初始化协议
ProtoManager.Init(config.protoType,"C:\\Users\\Administrator\\Documents\\GitHub\\distributed-architecture-of-moba-game-server\\ServerApp\\scripts\\auth\\const");

--如果是Protobuf协议，还需要注册映射表
local cmdNameMap=require("auth/const/CmdNameMap");
if cmdNameMap then
    ProtoManager.RegisterCmdMap(cmdNameMap);
else
    Debug.LogError("Protobuf register cmdNameMap failed");
end

local authServerConfig=config.servers[sType.Auth];

--开启服务器
Netbus.TcpListen(authServerConfig.port
    ,function(s)
        local ip,port = Session.GetAddress(s);
        print("new client come ["..ip..":"..port.."]");
    end);

Debug.Log("Auth server [tcp] listen at: ", authServerConfig.port);

--注册服务
local authService = require("auth/AuthService");
local ret = Service.Register(sType.Auth,authService);
if ret then
    print("register Auth Service:[" .. sType.Auth .. "] service success");
else
    print("register Auth Service:[" .. sType.Auth .. "] service failed");
end


text:
local sType=require("ServiceType");
local cType=require("auth/const/CmdType");

local authMessageHandler = require("auth/MessageHandler");

local cTypeToCallback = {};
cTypeToCallback[cType.UserLostConn]=authMessageHandler.UserLostConn;
cTypeToCallback[cType.EditProfileReq]=authMessageHandler.EditProfile;
cTypeToCallback[cType.UserLoginReq]=authMessageHandler.UserLogin;
cTypeToCallback[cType.UserUnregisterReq]=authMessageHandler.UserUnregister;
cTypeToCallback[cType.UserRegisteReq]=authMessageHandler.OnUserRegiste;

return   {
    OnSessionRecvCmd=function(s,msg)
        --{sType,cType,utag,body}
        if cTypeToCallback[msg[2]] then
            cTypeToCallback[msg[2]](s,msg);
        else
            Debug.LogError("unregistered cmdType: ",msg[2]);
        end
    end,
    OnSessionDisconnected=function(s,sType)
    	local ip,port = Session.GetAddress(s);
    	print("client ["..ip..":"..port.."] leave");
    end,
};


text:
local ServiceType = require("ServiceType");

local cmdNameMap={};
cmdNameMap[ServiceType.Auth]={
	UserLostConn = 0,
	ReLogin = 1,
	UserLoginReq = 2,
	UserLoginRes = 3,
	UserUnregisterRes = 4,
	UserUnregisterReq = 5,
	EditProfileReq = 6,
	EditProfileRes = 7,
	UserRegisteReq = 8,
	UserRegisteRes = 9,
};

return cmdNameMap;


text:
return {
	UserLostConn = 0,
	ReLogin = 1,
	UserLoginReq = 2,
	UserLoginRes = 3,
	UserUnregisterRes = 4,
	UserUnregisterReq = 5,
	EditProfileReq = 6,
	EditProfileRes = 7,
	UserRegisteReq = 8,
	UserRegisteRes = 9,
};


text:
syntax = "proto2";

message UserUnregisterRes{
	required int32 status = 1;
}

message EditProfileReq{
	required string unick = 1;
	required int32 uface = 2;
	required int32 usex = 3;
}

message EditProfileRes{
	required int32 status = 1;
}

message UserAccountInfo{
	 required int32 uid = 1;
	 required string uname = 2;
	 required string pwd = 3;
	 required string unick = 4;
	 required int32 ulevel = 5;
	 required int32 uexp = 6;
	 required int32 urank = 7;
	 required int32 ucoin = 8;
	 required int32 udiamond = 9;
	 required string usignature = 10;
	 required int32 uintegrity = 11;
	 required int32 status = 12;
	 required int32 uface = 13;
	 required string heros = 14;
	 required int32 urankExp = 15;
}
message UserLoginReq{
	required string uname = 1;
	required string pwd = 2;
}

message UserLoginRes{
	required int32 status = 1;
	optional UserAccountInfo uinfo = 2;
}

message UserRegisteReq{
	required string uname = 1;
	required string pwd = 2;
	required string unick = 3;
}
message UserRegisteRes{
	required int32 status = 1;
	optional UserAccountInfo uinfo = 2;
}

message UserUnregisteRes{
	required string status = 1;
	optional UserAccountInfo uinfo = 2;
}


text:
--初始化日志模块
Debug.LogInit("../logs/gateway","gateway",true);

--读取配置文件
local config = require("GameConfig");

--初始化协议
ProtoManager.Init(config.protoType,"C:\\Users\\Administrator\\Documents\\GitHub\\distributed-architecture-of-moba-game-server\\ServerApp\\scripts\\gateway\\const");

local cmdNameMap=require("gateway/const/CmdNameMap");
if cmdNameMap then
    ProtoManager.RegisterCmdMap(cmdNameMap);
else
    Debug.LogError("register cmdNameMap failed");
end

--开启网关
Netbus.TcpListen(config.gateway_tcp_port
    ,function(s)
            local ip,port = Session.GetAddress(s);
            print("new client come ["..ip..":"..port.."]");
    end);

Debug.Log("Gateway Server [tcp] listen at: ",config.gateway_tcp_port);

--注册服务
local gatewayService = require("gateway/GatewayService");
for k,v in pairs(config.servers) do

    --注意这里每一个服务器都注册了一个网关服务，所以，网关服务的代码会被多个服务器使用和访问
    --需注意可能引发的矛盾冲突

    local ret = Service.RegisterRaw(v.serviceType,gatewayService);
    if ret then
        print("register Gateway Service:[" .. v.descrip .. "] service success");
    else
        print("register Gateway Service:[" .. v.descrip .. "] service failed");
    end
end


text:
local config = require("GameConfig");
local CmdType = require("gateway/const/CmdType");
local ServiceType = require("ServiceType");
local Responce = require("Respones");

-- stype -> session 映射表
local sessionDic={}
-- 当前正在链接的服务器
local connectingSession={};
local g_ukey=1;
local tag_sessionDic={};
local uid_sessionDic={};

--连接到指定服务器
local function ConnectToServer(stype,ip,port)
	Netbus.TcpConnect(ip,port,
		--链接成功的回调
		function(session)
			connectingSession[stype]=false;
			if not session then
				Debug.LogError("connect to server ["..config.servers[stype].descrip.."]"..ip..port.." failed, reconnecting...");
				return;
			end
			--链接成功
			print("connect to server ["..config.servers[stype].descrip.."]"..ip..port.." success");
			sessionDic[stype]=session;
		end)
end

--检查服务器的链接
local function CheckServerConnect()
	-- 检查服务的链接，每秒进行一次
	for k,v in pairs(config.servers) do
		if sessionDic[v.serviceType]==nil
			and connectingSession[v.serviceType]==false
			then
			--如果没有链接，就链接服务器
			connectingSession[v.serviceType]=true;
			ConnectToServer(v.serviceType,v.ip,v.port);
		end
	end
end

--初始化网关服务器
local function GatewayServiceInit()
	for k,v in pairs(config.servers) do
		sessionDic[v.serviceType]=nil;
		connectingSession[v.serviceType]=false;
	end
	--启动一个定时器
	Timer.Repeat(CheckServerConnect,1000,-1,5000);
end

--是否为登陆返回消息
local function _IsLoginAuthRes(stype, ctype )
	if stype ~= ServiceType.Auth then
		return false;
	end

    if CmdType.UserLoginRes == ctype or CmdType.UserRegisteRes == ctype then
        return true;
    end
    return false;
end

--是否为登陆请求
local function _IsLoginAuthReq(stype, ctype )
	if stype ~= ServiceType.Auth then
		return false;
	end
    if CmdType.UserLoginReq == ctype or CmdType.UserRegisteReq == ctype then
        return true;
    end
    return false;
end

--是否为登陆逻辑服务器的请求
local function _IsLoginLogicReq(stype, ctype)
	return stype ==ServiceType.Logic and ctype == CmdType.LoginLogicReq;
end

-- 发给客户端
local function _server_send_to_client(s,raw)

	local stype,ctype,utag = RawCmd.ReadHeader(raw);

	--print("from server tag: ",utag);
	local clientSession = nil;
	--如果是登陆命令的回复
	if _IsLoginAuthRes(stype, ctype) then

		--取消tag_sessionDIc中的引用
		clientSession=tag_sessionDic[utag];
		tag_sessionDic[utag]=nil;

		if clientSession==nil then
			Debug.LogWarning("clientSession is null, uTag:", utag);
			return;
		end

		local body = RawCmd.ReadBody(raw);

		if config.enable_gateway_log then
			Debug.Log("s-c:LoginAuthRes "..body.status);
		end

		--如果返回结果不正常，直接返回
		if body.status~=Responce.Ok then
			Debug.LogWarning("Responce is not ok",body.status);
			RawCmd.SetUTag(raw,0);
			Session.SendRawPackage(clientSession,raw);
			return;
		end

		local uid = body.uinfo.uid;

		--判断是否有session已经用这个id登陆
		if uid_sessionDic[uid] and uid_sessionDic[uid]~=clientSession then
			--说明重复登陆
			Debug.LogWarning("somebody relogin");
			local reloginMsg = {ServiceType.Auth,CmdType.ReLogin,0,nil};
			Session.SendPackage(uid_sessionDic[uid],reloginMsg);
			Session.Close(uid_sessionDic[uid]);
			-- uid_sessionDic[uid]=nil;
		end

		--记录uid
		--print("remember uid: ",uid);
		uid_sessionDic[uid]=clientSession;
		Session.SetUId(clientSession,uid);

		--发送回客户端
		--print("send back to client");
		body.uinfo.uid=0;
		local loginRes={stype,ctype,0,body};
		Session.SendPackage(clientSession,loginRes);
		return;
	else
		if config.enable_gateway_log then
			Debug.Log("S->C["..utag.."] ["..stype..":"..ctype.."]");
		end
	end

	--print("BBB");
	clientSession=uid_sessionDic[utag];

	--发给用户
	if clientSession then
		--print("flag");
		--永远不要让用户知道utag
		RawCmd.SetUTag(raw,0);
		Session.SendRawPackage(clientSession,raw);

		--如果是注销消息
		if stype==ServiceType.Auth and ctype==CmdType.UserUnregisterRes then
			Session.SetUId(clientSession,0);
			uid_sessionDic[utag]=nil;
		end
	else
		print("clientSession is null? utag: ",utag);
	end
end

-- 发给服务器
local function _client_send_to_server(s,raw)

	local stype,ctype,utag = RawCmd.ReadHeader(raw);
	local targetServerSession = sessionDic[stype];
	if nil==targetServerSession then
		print("server is null, stype:"..stype);
		return;
	end

	if _IsLoginAuthReq(stype,ctype) then
		--如果是登陆用户服务器请求
		utag = Session.GetUTag(s);
		if utag==0 then
			--用户第一次登陆
			utag=g_ukey;
			g_ukey=g_ukey+1;
			Session.SetUTag(s,utag);
		end
		tag_sessionDic[utag]=s;

		if config.enable_gateway_log then
			Debug.Log("c-s:LoginAuthReq "..utag);
		end

		--print("get utag: ",utag);
	elseif _IsLoginLogicReq(stype,ctype) then
		--如果是登陆逻辑服务器请求
		utag = Session.GetUId(s);
		if uid==0 then
			--该操作需要先登陆
			Debug.LogError("you need to login first");
			return;
		end

		if config.enable_gateway_log then
			Debug.Log("c-s:LoginLoginReq");
		end
	else
		utag = Session.GetUId(s);
		if utag==0 then
			--该操作需要先登陆
			Debug.LogWarning("you need to login first");
			return;
		end
		--uid_sessionDic[uid]=s;
		if config.enable_gateway_log then
			Debug.Log("c-s:Normal ["..stype.."-"..ctype.."]");
		end
	end

	--打上utag然后发给我们的服务器
	--print("client tag: "..utag.." send to server")
	RawCmd.SetUTag(raw,utag);
	Session.SendRawPackage(targetServerSession,raw);
end

GatewayServiceInit();

return   {
    OnSessionRecvRaw=function(s,raw)
    	if Session.IsClient(s) then
    		_server_send_to_client(s,raw);
    	else
		    _client_send_to_server(s,raw);
    	end
    end,
    OnSessionDisconnected=function(s,stype)
		if Session.IsClient(s) then
			--和其他服务器的连接断开
    		for k,v in pairs(sessionDic) do
    			if v==s then
    				Debug.LogError("disconnected from: ["..config.servers[k].descrip.."]");
    				sessionDic[k]=nil;
    			end
    		end
    		return;
    	else
    		--和玩家断开

            local ip,port = Session.GetAddress(s);
            print("client ["..ip..":"..port.."] leave");

    		--1.把客户端从utag临时映射表删除，只有发起登录请求但是没有收到回复的会走这个逻辑
    		local utag = Session.GetUTag(s);
    		if tag_sessionDic[utag] and tag_sessionDic[utag]==s then
    			tag_sessionDic[utag]=nil;
    			Session.SetUTag(s,0);
    		end
            --2.把客户端从uid映射表删除，已经登陆了的短线请求会走这里
    		local uid = Session.GetUId(s);
    		if uid_sessionDic[uid] and uid_sessionDic[uid]==s then
    			uid_sessionDic[uid]=nil;
                --这里不能把用户uid值为零，用户注册的每个服务都会走这段代码
                --如果第一次我们就把uid置为零，后面走这段代码的服务器就不知道
                --是哪个用户掉线了
    			--Session.SetUId(s,0);
    			--table.remove(uid_sessionDic,uid);
    		end

            local targetServer = sessionDic[stype];
			if nil==targetServer then
				Debug.LogError("Unexpeced stype:"..stype);
                return;
            end

            --客户端uid用户掉线，我要把这个事件告诉中转服务器
            if uid~=0 then
                local userLostMsg = {stype,CmdType.UserLostConn,uid,nil};
                Session.SendPackage(targetServer,userLostMsg);
            end
    	end
    end,
};


text:
syntax = "proto2";
message UserAccountInfo{
	 required int32 uid = 1;
	 required string uname = 2;
	 required string pwd = 3;
	 required string unick = 4;
	 required int32 ulevel = 5;
	 required int32 uexp = 6;
	 required int32 urank = 7;
	 required int32 ucoin = 8;
	 required int32 udiamond = 9;
	 required string usignature = 10;
	 required int32 uintegrity = 11;
	 required int32 status = 12;
	 required int32 uface = 13;
	 required string heros = 14;
	 required int32 urankExp = 15;
}
message UserLoginReq{
	required string uname = 1;
	required string pwd = 2;
}

message UserLoginRes{
	required int32 status = 1;
	optional UserAccountInfo uinfo = 2;
}
message UserRegisteReq{
	required string uname = 1;
	required string pwd = 2;
	required string unick = 3;
}
message UserRegisteRes{
	required int32 status = 1;
	optional UserAccountInfo uinfo = 2;
}


text:
--
-- Created by IntelliJ IDEA.
-- User: ReadyGamerOne
-- Date: 2020/3/1
-- Time: 11:16
-- To change this template use File | Settings | File Templates.
--
local ServiceType = require("ServiceType");

local cmdNameMap={};
cmdNameMap[ServiceType.Logic]={
	LoginLogicReq = 1,
};

cmdNameMap[ServiceType.Auth]={
	UserLostConn = 0,
	ReLogin = 1,
	UserLoginReq = 2,
	UserLoginRes = 3,
	UserUnregisterRes = 4,
	UserRegisteReq = 8,
	UserRegisteRes = 9,
}

return cmdNameMap;


text:
--
-- Created by IntelliJ IDEA.
-- User: ReadyGamerOne
-- Date: 2020/3/1
-- Time: 10:34
-- To change this template use File | Settings | File Templates.
--

return {
	UserLostConn = 0,
	ReLogin = 1,
	UserLoginReq = 2,
	UserLoginRes = 3,
	UserUnregisterRes = 4,
	UserRegisteReq = 8,
	UserRegisteRes = 9,

	LoginLogicReq = 1,
    SelectHeroReq = 12,
}


text:
local Respones = require("Respones")
local Stype = require("ServiceType")
local CmdType = require("logic/const/CmdType")
local config= require("GameConfig");
local MatchMgr=require("logic/MatchMgr");

local logicServerConfig=config.servers[Stype.Logic];
local LogicConfig=require("logic/LogicConfig");

local function login_logic_server(s, req)
	local utag = req[3];
	local stype = req[1];

    if config.enable_proto_log then
        Debug.Log("a player login LogicServer")
    end

	MatchMgr.InitPlayer(s, utag, req[4].uname);
end

local function udp_test(s, req)
	local stype = req[1]
	local ctype = req[2]
	local body = req[4]

	local msg = {stype, CmdType.UdpTestRes, 0, {
		content = "success! "..body.content,
	}}

	local ip,port=Session.GetAddress(s);

    if config.enable_proto_log then
		Debug.Log("UdpTest: "..body.content.." IP-"..ip.." Port-"..port);
	end

	Session.UdpSendPackage(ip,port,msg);
end

local function on_start_match(s,req)
	local roomType = req[2];
	local uname = req[4].uname;
    if config.enable_proto_log then
        Debug.Log(uname.." try match")
	end

	MatchMgr.OnPlayerTryMatch(uname,roomType);
end

local function on_stop_match(s,req)
    if config.enable_proto_log then
        Debug.Log(req[4].uname.." try stop match");
	end
	MatchMgr.OnPlayerTryStopMatch(req[4].uname);
end

local function on_user_lost_conn(s,req)
    if config.enable_proto_log then
        Debug.Log("User["..req[3].."] lost conn");
	end
	MatchMgr.OnUserLostConn(req[3]);
end

local function on_select_hero(s,req)
	if not req[4].hero_id then
		Debug.LogError("there is no heroId");
		return;
	end
    if config.enable_proto_log then
        Debug.Log(req[4].uname.." select hero "..req[4].hero_id);
	end
	MatchMgr.OnPlayerSelectHero(req[4].uname,req[4].hero_id);
end

local function on_submit_hero(s,req)
    if config.enable_proto_log then
        Debug.Log(req[4].uname.." submit hero ");
	end
	MatchMgr.OnPlayerSubmitHero(req[4].uname);
end

local function on_start_game(s,req)
    if config.enable_proto_log then
        Debug.Log(req[4].uname.." request to start game");
	end
    MatchMgr.OnPlayerTryStartGame(req[4].uname);
end

local function on_get_next_frame_input(s,req)
    MatchMgr.OnTakeFrameInput(req[4].roomType,req[4].roomId,req[4].frameId,req[4].seatId,req[4].inputs);
end

local function on_init_udp(s,req)
	local uname=req[4].uname;
	local ip,port=Session.GetAddress(s);
	MatchMgr.SetUdpAddr(uname,ip,port);
end

local function on_start_multi_match(s,req)
	local roomType = req[2];
	local uname = req[4].uname;
    if config.enable_proto_log then
        Debug.Log(uname.." try match multi");
	end

	MatchMgr.OnPlayerTryMatch(uname,roomType);
end

local function on_start_story_mode(s, req)
	Session.SendPackage(s,{req[1],CmdType.StartStoryRes,req[3]});
end

local function on_player_exit_game(s, req)
	local uname=req[4].uname;

	if config.enable_proto_log then
		Debug.Log(uname.." try exit game");
	end

	MatchMgr.OnPlayerExitGame(uname);
end

return {
	OnUdpTest = udp_test,
    OnPlayerLoginLogic = login_logic_server,
    OnStartMatch = on_start_match,
	OnUserLostConn = on_user_lost_conn,
	OnStopMatch = on_stop_match,
	OnSelectHero = on_select_hero,
	OnSubmitHero = on_submit_hero,
	OnStartGameReq = on_start_game,
	OnGetNextFrameInput = on_get_next_frame_input,
	OnInitUdp = on_init_udp,
	OnStartMultiMatch = on_start_multi_match,
	OnStartStoryMode = on_start_story_mode,
	OnPlayerExitGame = on_player_exit_game,
}


text:
--初始化日志模块
Debug.LogInit("../logs/logic","logic",true);

--读取配置文件
local sType = require("ServiceType");
local config = require("GameConfig");

--初始化协议
ProtoManager.Init(config.protoType,"C:\\Users\\Administrator\\Documents\\GitHub\\distributed-architecture-of-moba-game-server\\ServerApp\\scripts\\logic\\const");

--如果是Protobuf协议，还需要注册映射表
local cmdNameMap=require("logic/const/CmdNameMap");
if cmdNameMap then
    ProtoManager.RegisterCmdMap(cmdNameMap);
else
    Debug.LogError("Protobuf register cmdNameMap failed");
end

local logicServerConfig=config.servers[sType.Logic];
local logicConfig=require("logic/LogicConfig");

--开启服务器
Netbus.TcpListen(logicServerConfig.port
    ,function(s)
        local ip,port = Session.GetAddress(s);
        print("new client come ["..ip..":"..port.."]");
    end);

print("Logic server [tcp] listen at: ", logicServerConfig.port);

Netbus.UdpListen(logicConfig.udp_port);
print("Logic server [udp] listen at: ", logicConfig.udp_port);

--注册服务
local logicService = require("logic/LogicService");
local ret = Service.Register(sType.Logic,logicService);
if ret then
    print("register Logic Service:[" .. sType.Logic .. "] service success");
else
    Debug.LogError("register Logic Service:[" .. sType.Logic .. "] service failed");
end


text:
local CmdType=require("logic/const/CmdType");

roomInfos={};
roomInfos[CmdType.StartMatchReq]={
    Max=1,
    GameTime=30,
};
roomInfos[CmdType.StartMultiReq]={
    Max=2,
    GameTime=600,
};

return {
    udp_ip="121.196.178.141",
    udp_port=10000,
    room_infos=roomInfos,
    heroSelectTime=20,
    finishSelectDelay=2,

    startGameDelay=3,

    logicFrameDeltaTime=50,--ms

    broadTimes=1,
};


text:
local function range(m,n)
    return math.random(m,n);
end

local function get_ulevel_uexp(curlevel,curExp,exp)
    if curExp+exp>100 then
        return curlevel+1,curExp+exp-100;
    end
    return curlevel,curExp+exp;
end

local function get_urank_urankExp(curRank,curRankExp,exp)
    if curRankExp+exp>125 then
        return curRank+1,curRankExp+exp-125;
    end
    return curRank,curRankExp+exp;
end

return {
    Range=range,
    GetUlevelAndUexp=get_ulevel_uexp,
    GetUrankAndUrankExp=get_urank_urankExp,
};


text:
local List=require("logic/src/List");
local Room=require("logic/src/Room");
local Player=require("logic/src/Player");
local LogicConfig=require("logic/LogicConfig");
local CmdType=require("logic/const/CmdType");
local Respones=require("Respones");
local config=require("GameConfig");
local PlayerState=require("logic/const/PlayerState");

local roomType_RoomList={}
local uname_Player={};
local utag_Player={};

--确保有房间
local function GetRoom(roomType)
    --create roomList if not this roomType
    if not roomType_RoomList[roomType] then
        roomType_RoomList[roomType]=List:New("[RoomType:"..roomType.."]RoomList");
    end
    --find an empty room, if not, create one
    local roomList=roomType_RoomList[roomType];
    local room=roomList:FindFirst(function(room)return not room:IsFull();end);
    if not room then
        --create room
        room=Room:New(roomType,LogicConfig.room_infos[roomType].Max);
        roomList:Add(room);
    end
    return room;
end

--自带报错
local function GetRoomByTypeAndId(roomType, roomId)
    if not roomType_RoomList[roomType] then
        Debug.LogError("Unexpected roomType:"..roomType);
        return;
    end

    local roomList=roomType_RoomList[roomType];
    local room=roomList:FindFirst(function(room)return room.RoomId==roomId;end);
    if not room then
        Debug.LogError("Unexpected roomId:"..roomId);
        return;
    end
    return room;

end

local function on_new_player_come(s,utag,uname)
    local player=uname_Player[uname] or utag_Player[utag];
    if not player then
        player=Player:New(s,uname,utag);
    end
    uname_Player[uname]=player;
    utag_Player[utag]=player;

    player:TcpSend(CmdType.LoginLogicRes,{
        udp_ip=LogicConfig.udp_ip,
        udp_port=LogicConfig.udp_port,
    });

    player:OnLine();
end

local function on_player_try_match(uname, roomType)
    local player=uname_Player[uname];
    if not player then
        Debug.LogError("Unexpected uname: "..uname);
        return;
    end
    player.ExpectedRoomType=roomType;
    local room=GetRoom(roomType);

    --start match feedback
    player:TcpSend(CmdType.StartMatchRes,{
        current=room:PlayerCount(),
        max=room.Max;
    })

    --add player to room
    room:AddPlayer(player);
end

local function set_player_udp_addr(uname, ip, port)
    local player=uname_Player[uname];
    if not player then
        Debug.LogError("Unexpected uname: "..uname);
        return;
    end
    player:SetUdpAddr(ip, port);
    player:UdpSend(CmdType.InitUdpRes);
end

local function on_player_stop_match(uname)
    if not uname_Player[uname] then
        Debug.LogError("unexpected uname: "..uname);
        return;
    end
    local player=uname_Player[uname];
    local room=player.Room;
    if not room then
        Debug.LogError("player "..uname.." is not in any room");
        return;
    end
    if room:IsFull() then
        --cant't leave
        player:TcpSend(CmdType.StopMatchRes,{status=Respones.InvalidOperate});
    else
        player:TcpSend(CmdType.StopMatchRes,{status=Respones.Ok});
        room:RemovePlayer(player);
    end

end

local function on_player_select_hero(uname, heroId)
    if not uname_Player[uname] then
        Debug.LogError("unexpected uname: "..uname);
        return;
    end
    local player=uname_Player[uname];
    local room=player.Room;
    if not room then
        Debug.LogError("player "..uname.." is not in any room");
        return;
    end

    if config.enable_match_log then
        Debug.Log(uname.." select hero["..heroId.."]");
    end

    player.HeroId=heroId;
    room:BroadMessage(CmdType.SelectHeroRes,{
        seatId = player.SeatId,
        hero_id = player.HeroId,
    });
end

local function on_player_submit_hero(uname)
    if not uname_Player[uname] then
        Debug.LogError("unexpected uname: "..uname);
        return;
    end

    local player=uname_Player[uname];
    local room=player.Room;
    if not room then
        Debug.LogError("player "..uname.." is not in any room");
        return;
    end
    if config.enable_match_log then
        Debug.Log(uname.." submit");
    end

    room:OnMatcherSubmit(uname);
end

local function on_player_try_start_game(uname)
    if not uname_Player[uname] then
        Debug.LogError("unexpected uname: "..uname);
        return;
    end
    local player=uname_Player[uname];
    local room=player.Room;
    if not room then
        Debug.LogError("player "..uname.." is not in any room");
        return;
    end
    room:OnPlayerReady(player);
end

local function on_take_frame_input(roomType, roomId, frameId,seatId,inputs)
    if not roomType then
        Debug.LogError("roomType is nil");
        return;
    end
    if not roomId then
        Debug.LogError("roomId is nil");
        return;
    end
    local room=GetRoomByTypeAndId(roomType,roomId);

    if not room then
        Debug.LogError("unexcepted room: type-"..roomType..", roomId-"..roomId);
        return;
    end
    room:TakeFrameInput(frameId,seatId,inputs);
end

local function on_user_lost_conn(utag)
    local player = utag_Player[utag];
    if not player then
        Debug.LogError("Unexpected utag:"..utag);
        return;
    end
    player:OnOffLine();
end

local function on_player_exit_game(uname)
    if not uname_Player[uname] then
        Debug.LogError("unexpected uname: "..uname);
        return;
    end

    local player=uname_Player[uname];
    local room=player.Room;
    if not room then
        Debug.LogError("player "..uname.." is not in any room");
        return;
    end
    if config.enable_match_log then
        Debug.Log(uname.." exit game");
    end

    room:OnPlayerExitGame(player);

end

return {
    OnPlayerTryMatch=on_player_try_match,
    OnPlayerTryStopMatch=on_player_stop_match,
    OnPlayerSelectHero=on_player_select_hero,
    OnPlayerSubmitHero=on_player_submit_hero,
    OnPlayerTryStartGame=on_player_try_start_game,
    OnTakeFrameInput=on_take_frame_input,
    InitPlayer=on_new_player_come,
    SetUdpAddr=set_player_udp_addr,
    OnUserLostConn=on_user_lost_conn,
    OnPlayerExitGame=on_player_exit_game,
}


text:
local sType=require("ServiceType");
local cType=require("logic/const/CmdType");

local logicMessageHandler = require("logic/MessageHandler");

local cTypeToCallback = {};
cTypeToCallback[cType.UserLostConn] = logicMessageHandler.OnUserLostConn;
cTypeToCallback[cType.LoginLogicReq] = logicMessageHandler.OnPlayerLoginLogic;
cTypeToCallback[cType.UdpTestReq] = logicMessageHandler.OnUdpTest;
cTypeToCallback[cType.StartMatchReq] = logicMessageHandler.OnStartMatch;
cTypeToCallback[cType.StopMatchReq] = logicMessageHandler.OnStopMatch;
cTypeToCallback[cType.SelectHeroReq] = logicMessageHandler.OnSelectHero;
cTypeToCallback[cType.SubmitHeroReq] = logicMessageHandler.OnSubmitHero;
cTypeToCallback[cType.StartGameReq] = logicMessageHandler.OnStartGameReq;
cTypeToCallback[cType.NextFrameInput] = logicMessageHandler.OnGetNextFrameInput;
cTypeToCallback[cType.InitUdpReq] = logicMessageHandler.OnInitUdp;
cTypeToCallback[cType.StartMultiReq] = logicMessageHandler.OnStartMultiMatch;
cTypeToCallback[cType.StartStoryReq] = logicMessageHandler.OnStartStoryMode;
cTypeToCallback[cType.ExitGameReq] = logicMessageHandler.OnPlayerExitGame;

return   {
    OnSessionRecvCmd=function(s,msg)
        --{sType,cType,utag,body}
        if cTypeToCallback[msg[2]] then
            cTypeToCallback[msg[2]](s,msg);
        else
            Debug.LogError("unregistered cmdType: ",msg[2]);
        end
    end,
    OnSessionDisconnected=function(s,sType)
    	local ip,port = Session.GetAddress(s);
    	print("client ["..ip..":"..port.."] leave");
    end,
};


text:
local Object=require("logic/src/Object");
local Player=Object:New("[Class] Player");
local ServiceType=require("ServiceType");
local config=require("GameConfig");
local Mysql=require("database/mysql_center");
local PlayerState=require("logic/const/PlayerState");
local Util=require("logic/Util");
Mysql.Connect();

function Player:New(tcpSession,uname,utag)
    local instance = Object.New(self,uname);
    --socketinfo
    instance.__tcpSession=tcpSession;
    instance.__utag=utag;
    instance.__udpIp=nil;
    instance.__udpPort=0;
    --userinfo
    instance.Uname=uname;
    instance.State=PlayerState.OnLine;
    --roomInfo
    instance.IsSubmit=false;
    instance.IsReady=false;
    instance.Room=nil;
    instance.SeatId=-1;
    instance.HeroId=-1;
    instance.ExpectedRoomType=-1;
    --game
    instance.SyncFrameId=0;

    return instance;
end

function Player:SetUdpAddr(udpIp,udpPort)
    self.__udpIp=udpIp;
    self.__udpPort=udpPort;
end

function Player:IsInRoom()
    return self.Room~=nil;
end

function Player:OnAddToRoom(room)
    self.Room=room;
    self.State=PlayerState.Matching;
    if config.enable_match_log then
        Debug.Log("Player["..self.Uname.."] enter Room["..self.Room.RoomId.."]");
    end
end

function Player:OnRemoveFromRoom(room)
    if config.enable_match_log then
        Debug.Log("Player["..self.Uname.."] leave Room["..room.RoomId.."]");
    end
    self.Room=nil;
    self.SeatId=-1;
    self.HeroId=-1;
    self.SyncFrameId=0;
    self.IsReady=false;
    self.IsSubmit=false;
    self.State=PlayerState.OnLine;
end

function Player:UdpSend(cmdType,body)
	--玩家已经断线
	if not self.__tcpSession then
		return;
	end

    if not self.__udpIp or self.__udpPort==0 then
		return;
	end

   Session.UdpSendPackage(self.__udpIp,self.__udpPort,{
    ServiceType.Logic,cmdType,0,body
   });
end

function Player:TcpSend(cmdType,body)
    -- Debug.Log("[Player.TcpSend] User "..self.Uname.."  cmdType "..cmdType);
    Session.SendPackage(
        self.__tcpSession,
        {
            ServiceType.Logic,
            cmdType,
            self.__utag,
            body,
        }
    );
end

--handler:matcher
function Player:GetMatchInfo(seatId,handler)
    self.SeatId=seatId;
    Mysql.GetMatcherInfoByUname(self.Uname,function(err,matchInfo)
        if err then
            Debug.LogError("[Player:GetMatchInfo MysqlError]"..err);
            handler(nil);
            return;
        end
        if not matchInfo then
            Debug.LogError("[Player:GetMatchInfo MysqlError] matchInfo is null");
            handler(nil);
            return;
        end
        matchInfo.seatId=self.SeatId;
        handler(matchInfo);
    end);
end

--handler:defaultHeroId
function Player:GetDefaultHeroId(handler)
    Mysql.GetDefaultHeroIdByUname(self.Uname,function(err,defaultHeroId)
        if err then
            Debug.LogError("[Player:GetDefaultHeroId MysqlError]"..err);
            handler(nil);
            return;
        end
        if not defaultHeroId then
            Debug.LogError("[Player:GetDefaultHeroId MysqlError] defaultHeroId is null");
            handler(nil);
            return;
        end
        handler(defaultHeroId);
    end);
end

function Player:OnLine()
    self.State=PlayerState.OnLine;
    if self.Room then
        self.Room:OnPlayerOnLine(self);
    end
end

function Player:OnOffLine()
    self.State=PlayerState.OffLine;
    if self:IsInRoom() then
        self.Room:OnPlayerOffLine(self);
    end
end

--获取用户仓库信息
--handler(err,{ulevel,uexp,urank,urankExp,ucoin,udiamond})
function Player:GetUserPackageInfo(handler)
    Mysql.GetPackageInfoByUname(self.Uname,handler);
end

--更新用户仓库信息
--handler(err,packageInfo)
function Player:UpdatePackageInfo(exp,rankExp,coin,diamond,handler)
    self:GetUserPackageInfo(function(err,packageInfo)
        if err then
            if handler then
                handler(err,nil);
            end
            return;
        end
        packageInfo.ulevel,packageInfo.uexp=Util.GetUlevelAndUexp(packageInfo.ulevel,packageInfo.uexp,exp);
        packageInfo.urank,packageInfo.urankExp=Util.GetUrankAndUrankExp(packageInfo.urank,packageInfo.urankExp,rankExp);
        packageInfo.ucoin=packageInfo.ucoin+coin;
        packageInfo.udiamond=packageInfo.udiamond+diamond;

        Mysql.UpdatePackageInfoByUname(self.Uname,packageInfo,function(internalError)
            if internalError then
                handler(internalError,nil);
            end
            handler(nil,packageInfo);
        end);
    end);
end

return Player;


text:
local Object={};

--metamethods
Object.__index=Object;

--class properties
Object.name="[Object.Class.Property.name]name";

--instance methods
function Object:Print()
    print("[Object.Instance.Method.Print] "..self.name);
end

--constructor
function Object:New(name)
    local instance = {};

    --necessary settings
    setmetatable(instance, self);
    instance.__index=instance;

    --instance properies
    instance.name= name or "[Object.Instance.Property.name]name";

    return instance;
end

return Object;


text:
local Object=require("logic/src/Object");
local List=require("logic/src/List");
local CmdType=require("logic/const/CmdType");
local LogicConfig=require("logic/LogicConfig");
local PlayerState=require("logic/const/PlayerState");
local RoomState=require("logic/const/RoomState");
local Respones=require("Respones");
local Util=require("logic/Util");

local Room=Object:New("[Class] Room");

Room.__roomIndex=0;

--new constructor
function Room:New(roomType, max)
    Room.__roomIndex=Room.__roomIndex+1;

    local instance=Object.New(self, "[Room:"..Room.__roomIndex.."]");

    --new instance properies
    instance.RoomId=Room.__roomIndex;
    instance.RoomType=roomType;
    instance.Max=max;
    instance.PlayerList=List:New(instance.name.."PlayerList");
    instance.__leftTime=0;
    instance.__selectTimer=nil;
    instance.State=RoomState.Matching;

    --game
    instance.__gameLoopTimer=nil;
    instance.__gameEndCallbackTimer=nil;
	instance.__frameId=1;--当前帧id
	instance.__allFrames={};--所有帧操作
    instance.__nextFrame=--当前帧操作
    {
		frameId = instance.__frameId,
		inputs = {},
	};

    return instance;
end

--override
function Room:Print()
    --call base method
    --Object.Print(self);
    Debug.Log("[Room.Instance.Method.Print]")
end

--new methods
function Room:LogRoomInfo()
    Debug.Log("[Room]RoomId-"..self.RoomId..":RoomType-"..self.RoomType..":Player-"..self.PlayerList:Count().."/"..self.Max);
end

function Room:BroadMessage(cmdType,body,ignore)
    self.PlayerList:Foreach(function(index,player)
        if ignore~=player then
            player:TcpSend(cmdType,body)
        end
    end)
end

function Room:AddPlayer(player)
    --add player
    player:OnAddToRoom(self);
    self.PlayerList:Add(player);

    --notice all players
    self:BroadMessage(CmdType.AddMatcherTick);

    --check if finish
    if self:IsFull() then
        self.State=RoomState.HeroSelecting;
        self:StartHeroPick();
    end
end

function Room:RemovePlayer(player)
    player:OnRemoveFromRoom(self);
    self.PlayerList:Remove(player);

    self:BroadMessage(CmdType.RemoveMatcherTick);
end

function Room:PlayerCount()
    return self.PlayerList:Count();
end

function Room:IsFull()
    return self.PlayerList:Count()==self.Max;
end

--开始英雄选择
function Room:StartHeroPick()
    Debug.Log("Room["..self.RoomId.."] start hero pick");
    local matchinfoArr=List:New("matchInfoArr:"..self.RoomId);
    local finished=0;
    self.PlayerList:Foreach(function(index,player)
        player:GetMatchInfo(index,
        function(matchInfo)
            matchinfoArr:Add(matchInfo);
            finished=finished+1;
            --信息获取完成，广播消息匹配完成
            if finished==self.Max then
                self:BroadMessage(CmdType.FinishMatchTick,{
                    matchers=matchinfoArr:Data(),
                    heroSelectTime=LogicConfig.heroSelectTime,
                    roomId = self.RoomId,
                });
                --英雄选择倒计时
                self.__leftTime=LogicConfig.heroSelectTime;
                self.__selectTimer=Timer.Repeat(function()
                    self.__leftTime=self.__leftTime-1;
                    if self.__leftTime==0 then
                        self:ForceStartGame();
                    else
                        self:BroadMessage(CmdType.UpdateSelectTimer,{current=self.__leftTime});
                    end
                end,1000,self.__leftTime-1,1000);
            end
        end);
    end);
end

--有人时间到了还没选好
function Room:ForceStartGame()
    Debug.Log("Room:ForceStartGame")
    Timer.Cancel(self.__selectTimer);
    self.__selectTimer=nil;
    local unfinishedPlayers=self.PlayerList:Where(function(player)return player.HeroId==-1;end);
    local finished=0;
    local uname_heroId={};
    unfinishedPlayers:Foreach(function(index, player)
        player:GetDefaultHeroId(function(defaultHeroId)
            finished=finished+1;
            uname_heroId[player.Uname]=defaultHeroId;

            --已经获取所有未选中的人的默认英雄
            if finished==unfinishedPlayers:Count() then
                local selectHeroResList=List:New();
                self.PlayerList:Foreach(function(index,player)
                    --锁定英雄
                   player.IsSubmit=true;
                   --设置默认英雄
                   if player.HeroId==-1 then
                        player.HeroId=uname_heroId[player.Uname];
                   end
                   selectHeroResList:Add({
                        seatId = player.SeatId,
                        hero_id = player.HeroId,
                   });
                end);
                self:BroadMessage(CmdType.ForceSelect,{
                    selectResults = selectHeroResList:Data(),
                });
                Timer.Once(function() self:StartLoadGame(); end, LogicConfig.finishSelectDelay*1000);
            end
        end);
    end);
end

--有人锁定了英雄
function Room:OnMatcherSubmit(uname)
    local submitCount=0;
    local player=nil;
    self.PlayerList:Foreach(function(index, player)
        if player.Uname==uname then
            if not player.IsSubmit then
                --锁定英雄
                player.IsSubmit=true;
                self:BroadMessage(CmdType.SubmitHeroRes,{seatId=player.SeatId});
            end
            submitCount=submitCount+1;
        elseif player.IsSubmit then
            submitCount=submitCount+1;
        end
    end);
    --全部锁定就开始游戏
    if submitCount==self:PlayerCount() then
        Timer.Cancel(self.__selectTimer);
        self.__selectTimer=nil;
        Timer.Once(function() self:StartLoadGame(); end, LogicConfig.finishSelectDelay*1000);
    end
end

--开始加载游戏
function Room:StartLoadGame()
    self.State=RoomState.Gaming;
    self:BroadMessage(CmdType.StartLoadGame);
end

--有玩家加载完毕，就绪
function Room:OnPlayerReady(player)
    player.IsReady=true;
    if self.PlayerList:All(function(player)return player.IsReady;end) then
        self.PlayerList:Foreach(function(index,player)
            player.State=PlayerState.Gaming;
        end);
        self:StartGame();
    end
end

--开始帧同步
function Room:StartGame()

    Debug.Log("Room["..self.RoomId.."] game start");

    --notice all players
    local roomConfig=LogicConfig.room_infos[CmdType.StartMatchReq];
    local startGameRes={
       gameTime = roomConfig.GameTime,
       randSeed = math.floor(math.random()*1000+10),
       logicFrameDeltaTime = LogicConfig.logicFrameDeltaTime,
       startGameDelay = LogicConfig.startGameDelay,
    };
    self:BroadMessage(CmdType.StartGameRes,startGameRes);

    self.__gameLoopTimer=Timer.Repeat(
        function()self:FrameSyncLoop();end,
        LogicConfig.startGameDelay,-1,LogicConfig.logicFrameDeltaTime);
    self.__gameEndCallbackTimer=Timer.Once(
        function()self:OnGameEnd();end,
        (LogicConfig.startGameDelay+roomConfig.GameTime)*1000);
end

--游戏结束回调
function Room:OnGameEnd()
    if self.__gameLoopTimer then
        Timer.Cancel(self.__gameLoopTimer);
        self.__gameLoopTimer=nil;
    end
    if self.__gameEndCallbackTimer then
        self.__gameEndCallbackTimer=nil;
    end

    local count=0;
    self.PlayerList:Foreach(function(_,player)
        player:UpdatePackageInfo(
            Util.Range(20,50),
            Util.Range(10,60),
            Util.Range(200,500),
            Util.Range(1,10),
            function(err,packageInfo)
                if err then
                    Debug.LogError("UpdatePackageInfo error: "..err);
                    player:TcpSend(CmdType.OnGameEndTick,{status=Respones.SystemError});
                else
                    player:TcpSend(CmdType.OnGameEndTick,{
                        status=Respones.Ok,
                        score=Util.Range(1,5),
                        packageInfo=packageInfo,
                    });
                end

                count=count+1;
                if count==self.PlayerList:Count() then
                    Debug.Log("Room["..self.RoomId.."] OnGameEnd");
                    self:Clear();
                end
            end);--player:UpdatePackageInfo
    end);--self.PlayerList:Foreach
end

--帧同步主循环
function Room:FrameSyncLoop()
    self.__allFrames[self.__frameId]=self.__nextFrame;

    local sendFramesInfo="";

    self.PlayerList:Foreach(function(_,player)

        if player.State~=PlayerState.Gaming then
            return;
        end

        --发送尚未同步的帧
        local frames = {};

        for i = (player.SyncFrameId+1), #self.__allFrames do
            table.insert(frames,self.__allFrames[i]);
        end

        sendFramesInfo=sendFramesInfo.." ["..player.SeatId.."-"..#frames.."]";

        --	print("player.SyncFrameId:"..player.SyncFrameId.."self.__frameId"..self.__frameId.."#self.__allFrames:"..#self.__allFrames);
        for i=1,LogicConfig.broadTimes do
            player:UdpSend(CmdType.LogicFramesToSync,{
                frameId=self.__frameId,
                unsyncFrames=frames,
            });
        end
    end);

    Debug.Log("Room["..self.RoomId.."] FrameSync["..self.__frameId.."]"..sendFramesInfo);

    self.__frameId=self.__frameId+1;

    self.__nextFrame=
    {
		frameId = self.__frameId,
		inputs = {},
	};
end

--接受收到的输入
function Room:TakeFrameInput(frameId, seatId,inputs)

	--是否内容无效
	if #inputs <= 0 then
		Debug.LogError("get empty NextFrameOpts");
		return;
	end
	--是否不对应玩家
    if seatId<1 or seatId>self:PlayerCount() then
        --Debug.LogError("unexpected seatId: "..seatId);
        return;
    end

    local player=self.PlayerList:At(seatId);

    --消息包重复
    if player.SyncFrameId>=frameId-1 then
        return;
    end
    --更新客户端同步到帧数
    player.SyncFrameId=frameId-1;
    --是否过时
    if frameId<self.__frameId then
        Debug.Log("frameId is out of date: "..frameId);
        return;
    end

    -- Debug.Log("TakeInput Player["..player.SeatId.."].SyncFrameId="..player.SyncFrameId);

	--加入到当前帧操作
	for k, opt in pairs(inputs) do
		table.insert(self.__nextFrame.inputs,opt);
	end
end

--玩家上线回调
function Room:OnPlayerOnLine(player)
end

--玩家掉线回调
function Room:OnPlayerOffLine(player)

    --提醒其他玩家有人掉线
    self:BroadMessage(CmdType.OnCharacterExitTick,{seatId=player.SeatId},player);
    player:OnRemoveFromRoom(self);

    --全部掉线关闭房间
    if self.PlayerList:All(function(player)return player.State~=PlayerState.Gaming;end) then
        self:Clear();
    end
end

--玩家主动离开游戏
function Room:OnPlayerExitGame(player)

    player:TcpSend(CmdType.ExitGameRes,{status=Respones.Ok});

    self:OnPlayerOffLine(player);

end

--清理出所有玩家，全部内部变量初始化
function Room:Clear()

    Debug.Log("Room["..self.RoomId.."] Clear");
    self.PlayerList:Foreach(function(_,player)player:OnRemoveFromRoom(self);end);
    self.PlayerList:Clear();
    self.__leftTime=0;
    self.__selectTimer=nil;
    self.State=RoomState.Matching;

    --game
    if self.__gameLoopTimer then
        Timer.Cancel(self.__gameLoopTimer);
        self.__gameLoopTimer=nil;
    end
    if self.__gameEndCallbackTimer then
        Timer.Cancel(self.__gameEndCallbackTimer);
        self.__gameEndCallbackTimer=nil;
    end
	self.__frameId=1;--当前帧id
	self.__allFrames={};--所有帧操作
    self.__nextFrame=--当前帧操作
    {
		frameId = self.__frameId,
		inputs = {},
    };
end

return Room;


text:
local Object=require("logic/src/Object");
local List=Object:New("[Class] List");

function List:New(name)
    local instance=Object.New(self, "[List] "..name)
    instance.__content={};
    return instance;
end

function List:Count()
    return #self.__content;
end

function List:Add(item)
    self.__content[#self.__content+1]=item;
end

function List:Remove(item)
    local newContent={};
    for i, v in ipairs(self.__content) do
        if v~=item then
            newContent[#newContent+1]=v;
        end
    end
    for i, v in ipairs(self.__content) do
        if i<=#newContent then
            self.__content[i]=v;
        else
            self.__content[i]=nil;
        end
    end
end

function List:Clear()
    self.__content={};
end

function List:Contains(item)
    return self:Any(function(value)return item==value;end);
end

function List:Foreach(action_index_value)
    for i,v in ipairs(self.__content) do
        action_index_value(i,v);
    end
end

function List:At(index)
    if index<1 or index>self:Count() then
        Debug.LogError("index is out of range:"..index.." List-"..self.name);
        return;
    end
    return self.__content[index];
end

function List:FindFirst(func_bool_item)
    for i,v in ipairs(self.__content) do
        if func_bool_item(v) then
            return v;
        end
    end
    return nil;
end

function List:Where(func_bool_item)
    local ans=List:New("Where-"..self.name);
    self:Foreach(function(index,item)
        if func_bool_item(item) then
            ans:Add(item);
        end
    end);
    return ans;
end

function List:All(func_bool_item)
    local ans=true;
    self:Foreach(function(index,item)
        if not func_bool_item(item) then
            ans=false;
        end
    end);
    return ans;
end

function List:Any(func_bool_item)
    local ans=false;
    self:Foreach(function(index,item)
        if func_bool_item(item) then
            ans=true;
        end
    end);
    return ans;
end

function List:Data()
    return self.__content;
end;

return List;


text:
return {
    Matching=1;
    HeroSelecting=2;
    Gaming=3;
}


text:
local ServiceType = require("ServiceType");

local cmdNameMap={};
cmdNameMap[ServiceType.Logic]={
    UserLostConn = 0,
    LoginLogicReq = 1,
    LoginLogicRes = 2,
    UdpTestReq = 3,
    UdpTestRes = 4,
    StartMatchReq = 5,
    StartMatchRes = 6,
    AddMatcherTick = 7,
    RemoveMatcherTick = 8,
    FinishMatchTick = 9,
    StopMatchReq = 10,
    StopMatchRes = 11,
    SelectHeroReq = 12,
    SelectHeroRes = 13,
    SubmitHeroReq = 14,
    SubmitHeroRes = 15,
    UpdateSelectTimer = 16,
    ForceSelect = 17,
    StartLoadGame = 18,
    StartGameReq = 19,
    StartGameRes = 20,
    NextFrameInput = 21,
    LogicFramesToSync = 22,
    InitUdpReq = 23,
    InitUdpRes = 24,
    StartStoryReq = 25,
    StartStoryRes = 26,
    StartMultiReq = 27,
    ExitGameReq = 28,
    ExitGameRes = 29,
    OnCharacterExitTick = 30,
    OnGameEndTick = 31,
};
return cmdNameMap;


text:
return {
    OnLine=1,
    Matching=2,
    Gaming=3,
    OffLine=4,
};


text:
return {
    UserLostConn = 0,
    LoginLogicReq = 1,
    LoginLogicRes = 2,
    UdpTestReq = 3,
    UdpTestRes = 4,
    StartMatchReq = 5,
    StartMatchRes = 6,
    AddMatcherTick = 7,
    RemoveMatcherTick = 8,
    FinishMatchTick = 9,
    StopMatchReq = 10,
    StopMatchRes = 11,
    SelectHeroReq = 12,
    SelectHeroRes = 13,
    SubmitHeroReq = 14,
    SubmitHeroRes = 15,
    UpdateSelectTimer = 16,
    ForceSelect = 17,
    StartLoadGame = 18,
    StartGameReq = 19,
    StartGameRes = 20,
    NextFrameInput = 21,
    LogicFramesToSync = 22,
    InitUdpReq = 23,
    InitUdpRes = 24,
    StartStoryReq = 25,
    StartStoryRes = 26,
    StartMultiReq = 27,
    ExitGameReq = 28,
    ExitGameRes = 29,
    OnCharacterExitTick = 30,
    OnGameEndTick = 31,
};


text:
syntax = "proto2";

message LoginLogicReq{
    required string uname = 1;
}

message LoginLogicRes{
    required string udp_ip = 1;
    required int32 udp_port = 2;
}

message UdpTestReq{
    required string content = 1;
}

message UdpTestRes{
    required string content = 1;
}

message StartMatchReq{
    required string uname = 1;
}

message StartMatchRes{
    required int32 current = 1;
    required int32 max = 2;
}

message StartMultiReq{
    required string uname = 1;
}

message StartStoryReq{
    required string uname = 1;
}

message StopMatchReq{
    required string uname = 1;
}

message StopMatchRes{
    required int32 status = 1;
}

message MatchInfo{
    required string unick = 1;
    required int32 urank = 2;
    required int32 seatId = 3;
    required int32 uface = 4;
    required int32 ulevel = 5;
}

message FinishMatchTick{
    repeated MatchInfo matchers = 1;
    required int32 heroSelectTime = 2;
    required int32 roomId = 3;
}

message SelectHeroReq{
    required string uname = 1;
    required int32 hero_id = 2;
}

message SelectHeroRes{
    required int32 seatId = 1;
    required int32 hero_id = 2;
}

message SubmitHeroReq{
    required string uname = 1;
}
message SubmitHeroRes{
    required int32 seatId = 1;
}

message UpdateSelectTimer{
    required int32 current = 1;
}

message ForceSelect{
    repeated SelectHeroRes selectResults = 1;
}

message PlayerInput{
    required int32 seatId = 1;
    required int32 moveX = 2;
    required int32 moveY = 3;
    required bool jump = 4;
    required int32 mouseX = 5;
    required int32 mouseY = 6;
    required bool attack = 7;
    required bool heroFirstSkill = 8;
    required bool heroSecondSkill = 9;
    required bool weaponFirstSkill = 10;
    required bool weaponSecondSkill = 11;
    required int32 faceX = 12;
    required int32 faceY = 13;
    required int32 faceZ = 14;
}

message LogicFrame{
    required int32 frameId = 1;
    repeated PlayerInput inputs = 2;
}

message NextFrameInput{
    required int32 frameId = 1;
    required int32 roomId = 2;
    required int32 roomType = 3;
    required int32 seatId = 4;
    repeated PlayerInput inputs = 5;
}

message LogicFramesToSync{
    required int32 frameId = 1;
    repeated LogicFrame unsyncFrames = 2;
}

message StartGameReq{
    required string uname = 1;
}

message StartGameRes{
    required int32 gameTime = 1;
    required int32 randSeed = 2;
    required int32 logicFrameDeltaTime = 3;
    required int32 startGameDelay = 4;
}

message InitUdpReq{
    required string uname = 1;
}

message ExitGameReq{
    required string uname = 1;
}

message ExitGameRes{
    required int32 status = 1;
}

message OnCharacterExitTick
{
    required int32 seatId = 1;
}

message UserPackageInfo
{
    required int32 ulevel = 1;
    required int32 uexp = 2;
    required int32 urank = 3;
    required int32 urankExp = 4;
    required int32 ucoin = 6;
    required int32 udiamond = 7;
}

message OnGameEndTick
{
    required int32 status = 1;
    optional int32 score = 2;
    optional UserPackageInfo  packageInfo = 3;
}


text:
local Object=require("logic/src/Object");

Debug.LogInit("../logs/debug","debug",true);
local o1=Object:New("o1");
local o2 =Object:New("o2");
o1:Print();
o2:Print();

local Room=require("logic/src/Room");
local r1=Room:New(0,10);
r1:LogRoomInfo();

local List=require("logic/src/List");
local roomList=List:New("Room");
roomList:Add(o1);
roomList:Add(o2);
Debug.Log("ListSize:"..roomList:Count());
roomList:Foreach(function(i,v)
    Debug.Log("Foreach: "..i.." "..v.name);
end)
roomList:Remove(o1);
Debug.Log("ListSize:"..roomList:Count());
roomList:Foreach(function(i,v)
    Debug.Log("Foreach: "..i.." "..v.name);
end)

for i=0,1 do
    print(i);
end


text:
@echo off
rem �����ļ�
for /f "delims=" %%i in ('dir /b/a ".\protos\*.proto"') do echo protos\%%i
rem תcpp  for /f "delims=" %%i in ('dir /b/a "*.proto"') do protoc -I=. --cpp_out=. %%i
for /f "delims=" %%i in ('dir /b/a ".\protos\*.proto"') do bin\protogen -i:protos\%%i -o:..\Assets\PurificationPioneer\Network\ProgoGen\%%~ni.cs  -ns:PurificationPioneer.Network.ProtoGen
pause