<file_sep>local socket = require "clientsocket"
local skynet = require "skynet"

local NORET = {}
server = server or {}


function server.onclose(errmsg)
	print(string.format("%s lost connect,errmsg:%s",server.fd,errmsg))
	socket.close(server.fd)
	server.fd = nil
	-- cann't use call
	skynet.send(server.client,"lua","cmd","exit")
	skynet.exit()
end

function server.unpack_package(text)
	local size = #text
	if size < 2 then
		return nil,text
	end
	local s = text:byte(1) * 256 + text:byte(2)
	if size < s + 2 then
		return nil,text
	end
	return text:sub(3,s+2),text:sub(s+3)
end

function server.recv_package()
	if not server.fd then
		return nil
	end
	local result
	result,server.last = server.unpack_package(server.last)
	if result then
		return result
	end
	local isok,r = pcall(socket.recv,server.fd)
	if not isok then
		server.onclose(r)
		return nil
	end
	--print("server.recv_package",server.fd,r)
	if not r then
		return nil
	end
	if r == "" then
		server.onclose()
		return nil
	end
	result,server.last = server.unpack_package(server.last .. r)
	return result
end

function server.sendpackage(pack)
	if not server.fd then
		return
	end
	local size = #pack
	assert(size <= 65535)
	local package = string.char(math.floor(size/256))..
					string.char(size%256) ..
					pack
	socket.send(server.fd,package)
	return NORET
end


function server.send_request(protoname,cmd,request,session)
	local str = server.request(protoname .. "_" .. cmd,request,session)
	server.sendpackage(str)
	return NORET
end


function server.init(conf)
	local sprotoloader = require "sprotoloader"
	server.host = sprotoloader.load(1):host "package"
	server.request = server.host:attach(sprotoloader.load(2))
	server.client = assert(conf.client)
	server.last = ""
	local fd = assert(socket.connect(conf.ip,conf.port))
	server.fd = fd
end

-- server -> client
function server.dispatch_package()
	skynet.timeout(100,server.dispatch_package)
	while true do
		local v = server.recv_package()
		if not v then
			break
		end
		local typ,cmd,request,response = server.host:dispatch(v)
		if typ == "REQUEST" then
			local result = skynet.call(server.client,"lua","data",typ,cmd,request)
			if response then
				local result = response(result)
				server.sendpackage(result)
			end
		else
			assert(typ=="RESPONSE")
			local session = cmd
			local response = request
			skynet.send(server.client,"lua","data",typ,session,response)
		end
	end
end

local command = {
	send_request = server.send_request,
	sendpackage = server.sendpackage,
}

function command.start(conf)
	conf.ip = conf.ip or "127.0.0.1"
	conf.port = conf.port or 8001
	server.init(conf)
	server.dispatch_package()
	return NORET
end

function command.exit()
	skynet.exit()
	return NORET
end

-- client -> server
function server.dispatch(session,source,cmd,...)
	local func = command[cmd]
	local isok,result = pcall(func,...)
	if isok then
		if result ~= NORET then
			skynet.ret(skynet.pack(result))
		end
	else
		skynet.error(result)
	end
end

skynet.start(function (conf)
	skynet.dispatch("lua",server.dispatch)
end)
<file_sep>local skynet = require "skynet"

robert = robert or {}
robert.server = nil -- init in proto#command.start

function moveto(pos)
	sendpackage(robert.server,"scene","move",{
		dstpos=pos,
		time = os.time(),
	})	
end

function enterscene(sceneid,pos)
	sendpackage(robert.server,"scene","enter",{
		sceneid = sceneid,
		pos = pos,
	})
end

function stop()
	sendpackage(robert.server,"scene","stop",{})
end

function setpos(pos)
	sendpackage(robert.server,"scene","setpos",{
		pos = pos,
	})
end

local ALL_POS = {
	{x=1,y=1,dir=1},
	{x=2,y=2,dir=1},
	{x=3,y=3,dir=1},
	{x=4,y=4,dir=1},
	{x=5,y=5,dir=1},
	{x=6,y=6,dir=1},
	{x=7,y=7,dir=1},
	{x=8,y=8,dir=1},
	{x=9,y=9,dir=1},
	{x=10,y=10,dir=1},
	{x=11,y=11,dir=1},
	{x=12,y=12,dir=1},
	{x=13,y=13,dir=1},
	{x=14,y=14,dir=1},
	{x=15,y=15,dir=1},
	{x=16,y=16,dir=1},
}

function randompos()
	local i = math.random(#ALL_POS)
	return ALL_POS[i]
end

local ALL_SCENEID = {1,2,3,4,5,6}
	
function randomsceneid()
	local i = math.random(#ALL_SCENEID)
	return ALL_SCENEID[i]
end

function ishit(num,limit)
	return math.random(1,limit) <= num
end

local allcmd = {
	moveto = 5,
	stop = 4,
	setpos = 90,
	enterscene = 1,
}



function robert.run(server)
	if not robert.server then
		print "Server close"
		return
	end
	local interval = 300 -- 1s
	skynet.timeout(interval,robert.run)
	local cmd = choosekey(allcmd)
	--print("cmd:",cmd)
	if cmd == "moveto" then
		local pos = randompos()
		moveto(pos)
	elseif cmd == "stop" then
		stop()
	elseif cmd == "setpos" then
		local pos = randompos()
		setpos(pos)
	elseif cmd == "enterscene" then
		local sceneid = randomsceneid()
		local pos = randompos()
		enterscene(sceneid,pos)
	end
end

return robert
<file_sep>local skynet = require "skynet"

skynet.start(function ()
	skynet.uniqueservice("script/service/protoloader")

	skynet.newservice("debug_console",6666)

	local num = tonumber(skynet.getenv("num"))
	local startpid = tonumber(skynet.getenv("startpid"))
	if num and startpid then
		skynet.newservice("script/service/robertd",num,startpid)
	end
end)
<file_sep>local skynet = require "skynet"
local num,startpid = ...
num=tonumber(num) or 1
startpid=tonumber(startpid) or 1000001

skynet.start(function ()
	local ip = skynet.getenv("ip") or "127.0.0.1"
	local port = skynet.getenv("port") or 8001
	port = tonumber(port)
	for i = 0,num-1 do
		local pid = startpid + i
		--print("pid:",pid)
		local client = skynet.newservice("script/service/client")
		local server = skynet.newservice("script/service/server")
		skynet.send(server,"lua","start",{
			ip = ip,
			port = port,
			client = client,
		})
		skynet.send(client,"lua","cmd","start",server,pid)
	end
	skynet.exit()
end)
<file_sep>local sprotoloader = require "sprotoloader"
local proto = require "script.proto.proto"
local skynet = require "skynet"
local sprotoparser = require "sprotoparser"

skynet.start(function ()
	--proto.dump()
	local bin_c2s = sprotoparser.parse(proto.c2s)
	local bin_s2c = sprotoparser.parse(proto.s2c)
	sprotoloader.save(bin_s2c,1)
	sprotoloader.save(bin_c2s,2)
	-- don't call skynet.exit() , because sproto.core may unload and the global slot become invalid
end)


<file_sep>local skynet = require "skynet"
require "script.proto.init"
require "script.base.init"
require "script.errcode"
require "script.robert"

skynet.start(function ()
	skynet.dispatch("lua",proto.dispatch)
end)
<file_sep>local skynet = require "skynet"
proto = proto or {}

local function onrequest(server,cmd,request)
	pprintf("%d onrequest:%s\n",proto.pid,{
		server = server,
		cmd = cmd,
		request = request,
	})
end

local function onresponse(server,session,response)
	pprintf("%d onresponse:%s\n",proto.pid,{
		server = server,
		session = session,
		response = response,
	})
	local ses = assert(proto.sessions[session],"error session id:%s" .. tostring(session))
	proto.sessions[session] = nil
	local callback = ses.onresponse
	if callback then
		callback(server,ses.request,response)
	end
end

local NORET = {} -- 返回NORET表示无须回复对方，调用者用send方式调用
local command = {}
function command.start(server,pid)
	proto.init(server,pid)
	local login = require "script.login"
	local account = string.format("#%d",pid)
	local passwd = "1"
	print("login",server,account,passwd)
	robert.server = server
	login(server,account,passwd,robert.run)
	return NORET
end

function command.exit()
	robert.server = nil
	proto.server = nil
	skynet.exit()
	return NORET
end

function proto.dispatch(session,source,cmd,typ,...)
	if cmd == "data" then
		if typ == "REQUEST" then
			local ok,result = pcall(onrequest,source,...)
			if ok then
				skynet.ret(skynet.pack(result))
			else
				skynet.error(result)
			end
		else
			assert(typ == "RESPONSE")
			onresponse(source,...)
		end
	elseif cmd == "cmd" then
		local func = command[typ]
		local isok,result = pcall(func,...)
		if isok then
			if result ~= NORET then
				skynet.ret(skynet.pack(result))
			end
		else
			skynet.error(result)
		end
	end
end

function proto.sendpackage(server,protoname,cmd,request,onresponse)
	local package = {
		protoname = protoname,
		cmd = cmd,
		request = request,
		onresponse = onresponse,
	}
	pprintf("%d sendpackage %s",proto.pid,package)
	proto.session = proto.session + 1
	proto.sessions[proto.session] = package
	skynet.send(server,"lua","send_request",protoname,cmd,request,proto.session)
end

function proto.init(server,pid)
	proto.server = server
	proto.pid = pid
	proto.session = 0
	proto.sessions = {}
end

return proto
<file_sep>unpack = unpack or table.unpack

function pretty_tostring(obj,indent)
	if type(obj) ~= "table" then
		return tostring(obj)
	end
	local cache = {}
	table.insert(cache,"{")
	indent = indent + 4
	for k,v in pairs(obj) do
		if type(k) == "number" then
			table.insert(cache,string.rep(" ",indent) .. string.format("[%d]=%s,",k,pretty_tostring(v,indent)))
		else
			local str = string.rep(" ",indent) .. string.format("%s=%s,",pretty_tostring(k,indent),pretty_tostring(v,indent))
			table.insert(cache,str)	
		end
	end
	indent = indent - 4
	table.insert(cache,string.rep(" ",indent) .. "}")
	return table.concat(cache,"\n")
end

function pretty_format(fmt,...)
	--local args = {...}	--无法处理nil值参数
	local args = table.pack(...)
	local len = math.max(#args,args.n or 0)
	for i = 1, len do
		if type(args[i]) == "table" then
			args[i] = pretty_tostring(args[i],0)
		elseif type(args[i]) ~= "number" then
			args[i] = tostring(args[i])
		end
	end
	return string.format(fmt,unpack(args))
end

function pprintf(fmt,...)
	local skynet = require "skynet"
	local mode = skynet.getenv("mode")
	if mode ~= "debug" then
		return
	end
	print(pretty_format(fmt,...))
end

function choosekey(dct)
	local sum = 0
	for _,ratio in pairs(dct) do
		sum = sum + ratio
	end
	local hit = math.random(1,sum)
	local limit = 0
	for key,ratio in pairs(dct) do
		limit = limit + ratio
		if hit <= limit then
			return key
		end
	end
	return nil
end


-- package
function sendpackage(server,protoname,cmd,request,onresponse)
	require "script.proto.init"	
	proto.sendpackage(server,protoname,cmd,request,onresponse)
end
