ruby实战手册(9)

发布时间 2023-09-08 17:50:40作者: 水宝石

简单的MUD服务器

main.rb

#!/usr/bin/ruby 
#encoding:UTF-8
require 'eventmachine'
require_relative 'MudGameServer'
require_relative 'GmCmd'
require 'time'
VERSION =0.01

EventMachine.run {
  $client_count=0
  $action={}
  puts "waterRbMud server V#{VERSION} start..."
  host, port,mg_port = get_server_ip_info()
  puts "[a mud server written with ruby.]"
  EventMachine.start_server host, port, MudGameServer
  EventMachine.start_server(host, mg_port, GmCmd)
  puts  DateTime.now  
  puts "waterRbMud server was running." 
  puts "接受player连接: #{host}: #{port}..."
  puts "接受GM连接: #{host}: #{mg_port}..."
}




MudGameServer

#encoding:UTF-8
#!/usr/bin/ruby

require 'json'
 

def get_server_ip_info
    main_port=2023
    manager_port=9999
	ip_info=`ifconfig -a`
	ip_info=~/inet\s+(?!127\.0\.0\.1)([0-9\.]+)/
	[$1,main_port,manager_port]
end

module MudGameServer
	def post_init
	    init_game_data
		puts "第#{$client_count}个客户端已经连接到服务器![#{DateTime.now}]"
		send_data "login 用户名  密码:\n"
		send_data "#"
	end

	def receive_data data
	        if !data || data.chomp.strip=="" 
			    send_data "#"
			    return 
	        end
	        data_utf8=data.strip.force_encoding('utf-8')
	        begin
				@received_data=data_utf8.split(/\s+/)
				client_cmd=@received_data[0]
				player_cmd(client_cmd)
			rescue  ArgumentError=>e
				@@game_client.delete(@user)
				close_connection				
			end		    		 
	end

	def unbind
	    $client_count-=1
		puts "1个客户端退出,还有#{$client_count}个客户端连接中![#{DateTime.now}]"
		if $client_count==0
			puts "当前无客户端连接!"
		end
	end

	def init_game_data
	    @@game_client={}
	    @scene_act={}
	    @current_room_id=0
	    @current_order_id=0
		$client_count+=1
	    @now_story_id="0-0"
	    $action["think"]="想:"
	    $action["talk_to_myself"]="自言自语:"
	    $action["plot"]=":"	   
	    #now_story_id
		File.open("gameData_#{@now_story_id}.json", "r") do |json_file|
		   	@json_obj = JSON.parse json_file.read
		end
	end
	
	def player_cmd(cmd_str)
		p_cmd=cmd_str.downcase
		if p_cmd=="now"
			send_data ">>>#{@user},#{DateTime.now}\n#"
		elsif p_cmd=="login"
			@user,@passwd=@received_data[1..2]	   
			@@game_client[@user]=self
			send_data ">>>#{@user},欢迎您光临\n#"
			out_str=get_scene_output(@current_room_id,@current_order_id)
			if out_str
				send_data "\n#{out_str}" 		
			end		   
		elsif 	p_cmd=="quit"
			@@game_client.delete(@user)
			close_connection
		elsif p_cmd=="talkto"
		 	user,message=@received_data[1..2]	
		 	send_data "#"  
		 	if   @@game_client.has_key?(user)
		     	@@game_client[user].send_data ">>>#{@user}对#{user}说:\n#{message}\n#"    
		 	end	
		elsif @scene_act.has_key?(p_cmd)
			case @scene_act[p_cmd].split[0]
			   when  "next"
					@current_order_id+=1	
					@scene_act.clear	
			   when "go_order_id"
					@current_order_id=@scene_act[p_cmd].split[1].to_i
					@scene_act.clear						
			end
			out_str=get_scene_output(@current_room_id,@current_order_id)
			if out_str
				send_data out_str 
			else
				 @current_order_id-=1
				 send_data ">>>#{@user},无效指令:#{cmd_str}\n#"  			
			end			
		else
	    	*params=@received_data[1..-1]	
			send_data ">>>#{@user},无效指令:#{cmd_str},无效参数:#{params.join(" ")}\n#"      
		end	
	end

	def get_scene_output(c_room_id,c_order_id)
		now_scene_data=get_game_scene(c_room_id,c_order_id)
		if now_scene_data
			sel_str=""		    	    
			@scene_act={}
			now_scene_data[:action_sel].each do |sel,act|
				sel_kb=sel.split('-|')[0]
				sel_str+=sel+"\n"
				@scene_act[sel_kb]=act.strip
			end
			out_str=">>>#{@user}现在在#{now_scene_data[:room_name]}\n"
			out_str+="#{@user}#{now_scene_data[:action_name]}\n"
			out_str+="#{now_scene_data[:action_data].join("\n")}\n"
			out_str.gsub!('#player_user#',@user)
			out_str+=sel_str+"\n#"
			return out_str
		else
			return nil
		end	    
	end

	def get_game_scene(room_id,order_id)
			room_name=""
			action_type=""
			action_name=""
			action_data=""  
			action_sel={}
			sub_scene=@json_obj["data"]
			sub_scene.each do |player_info|
				if player_info["id"].to_i==room_id
					room_name=player_info["name"]
					player_info["data"].each do |player_data|
						if player_data["order_id"].to_i==order_id
							action_type=player_data["type"].strip
							action_name=$action[action_type]
							action_data= player_data["data"]
							action_sel= player_data["select"]
							return {"room_name":room_name,"action_type":action_type,"action_name":action_name,"action_data":action_data,"action_sel":action_sel}
						end
					end
				end 
			end
			return nil
	  end
end

test.rb

require 'eventmachine'

 module MudGameServer
    @@client_count=0
	def post_init
	    @@client_count+=1
		puts "第#{@@client_count}个客户端已经连接到服务器!"
	end

	def receive_data data
	    mud_data=data.gsub(" ","").force_encoding('utf-8')
		send_data "#你发送的消息: #{mud_data}"
		close_connection if data =~ /quit/i
	end

	def unbind
	    @@client_count-=1
		puts "1个客户端退出,还有#{@@client_count}个客户端连接中!"
		if @client_count==0
			puts "当前无客户端连接!"
		end
	end

	def query_client_count
	     puts "当前#{@@client_count}个客户端连接!"
	end
end
# Note that this will block current thread.
EventMachine.run {
  EventMachine.start_server "127.0.0.1", 8081, MudGameServer
}

GmCmd.rb

#encoding:UTF-8

require_relative 'EncryStr'
module GmCmd
     @@gm_count=0
     @@gm_passwd=['a29b0@*^','z-=?2#\;','~#3-sr|l']
	def post_init
	    init_gm_command
	    @@gm_count+=1
		puts "第#{@@gm_count}个gm客户端已经连接到服务器!"
	end

	def receive_data data
	        if !data || data.chomp.strip==""
			    send_data ">>>"
			else
			    data=data.chomp
				begin
					data=decry_str(data,@@gm_passwd)
					@received_data=data.strip.force_encoding('utf-8').split(/\s+/)
					client_cmd=@received_data[0]
					game_master_cmd(client_cmd)
				rescue  ArgumentError=>e
					close_connection
				end
	        end		 
	end

	def unbind
	    @@gm_count-=1
		puts "1个gm客户端退出,还有#{@@gm_count}个gm客户端连接中![#{DateTime.now}]"
		if @@gm_count==0
			puts "当前无gm客户端连接!"
		end
	end

	def init_gm_command
	        @@gm_command={}
			@@gm_command["version"]=Proc.new do 
				send_data ">>>#{VERSION}\n###"
			end
			@@gm_command["gmlogin"]=Proc.new do 	    
				@user,@passwd=@received_data[1..2]	
				puts "gm客户端#{@user}已经登录[#{DateTime.now}]"    
				send_data ">>>#{@user},欢迎您光临\n###"   
			end
			@@gm_command["ccount"] =Proc.new do 
			   send_data ">>>当前#{$client_count}个客户端连接![#{DateTime.now}]\n###"
			end
			@@gm_command["gcount"] =Proc.new do 
			   send_data ">>>当前#{@@gm_count}个gm客户端连接![#{DateTime.now}]\n###"
			end
			@@gm_command["now"]=Proc.new do 
				send_data ">>>#{@user},#{DateTime.now}\n###"
			end
			@@gm_command["quit"]=Proc.new do  
				close_connection
			end
	end

	def game_master_cmd(cmd_str)
		gm_cmd=cmd_str.downcase
        if  @@gm_command.has_key?(gm_cmd)
			@@gm_command[gm_cmd].call()			
		else
	    	*params=@received_data[1..-1]	
			send_data ">>>#{@user},无效指令:#{gm_cmd},无效参数:#{params.join(" ")}\n###s"    
		end		
	end 
end


gmclient.rb

#!/usr/bin/ruby 
#encoding:UTF-8
require 'eventmachine'
require_relative 'EncryStr'

$gm_port=9999
$gm_server='192.168.1.105'
$gm_passwd=['a29b0@*^','z-=?2#\;','~#3-sr|l']
$user="gm"
$passwd="124321"

module GmCmdClient
  def post_init
     puts "开始连接服务器[#{$gm_server}:#{$gm_port}]...."
     login_data=encry_str("gmlogin #{$user} #{$passwd}",$gm_passwd)
     send_data login_data
  end

  def receive_data data
	 print data
	 input_data=""
	 loop do
		begin
			input_data=gets.chomp.strip
			if input_data!=""
				break
			else
				print "###"
			end
		rescue Exception=>e
		    puts "error!"
		    p e
			print "###"
		end
	 end
     input_data=encry_str(input_data,$gm_passwd)
     send_data input_data
  end

  def unbind
    EventMachine::stop_event_loop
  end
end

 EventMachine.run do
   EventMachine.connect $gm_server, $gm_port, GmCmdClient
end


EncryStr.rb

#!/usr/bin/ruby 
#encoding:UTF-8
require 'des'
def encry_str(data,passwd)
	des_encry(des_decry(des_encry(data,passwd[0]),passwd[1]),passwd[2])
end
def decry_str(data,passwd)
	des_decry(des_encry(des_decry(data,passwd[2]),passwd[1]),passwd[0])	
end
def des_encry(data,passwd)
	ec_data=""
	pad_data=""
	data_length=data.length
	for i in (0...data.length).step 8
		 s_data=data[i,8]
		 if data_length < 8
			for i in 0...8-data_length
			   pad_data+=" "
			end
			s_data+=pad_data		
		 end
		 ec_data+=DES.encrypt(s_data, passwd).to_s
		 data_length-=8
	end	
	return ec_data
end

def des_decry(data,passwd)
	dc_data=""
	for i in (0...data.length).step 8
		 s_data=data[i,8]
		 dc_data+=DES.decrypt(DES::Block.new(s_data), passwd).to_s
	end	
	dc_data.slice!(/\*+$/)
	return dc_data
end

def test
    passwd=["aqsw1234",'a-=?2##;','~#0-sr|l']
	s1=encry_str("gmlogin sss 325 ",passwd)
	s2=decry_str(s1,passwd)
	puts s1
	puts s2
end

#test


gameData_0-0.json

{ 
    "id":"0-0",
    "type":"scene",
	"data":
	[
		{"id":0	,
		 "type":"room",
		 "name":"自己家里",
		 "data":
			[ 
				{
				   "order_id":0,
				   "type":"think",
				   "data": [
					   "我这是在哪呢?\n原来是在自己家里,又是平静的一个周日。",
						"快盛夏了,昨天天气预报,今天气温38度,天气就这么热了。",
						"现在几点了?\n还只有9点。"
					],
					"select":{"1-|继续":"next"}
				},  
				{
					"order_id":1,
					"type":"talk_to_myself",
					"data": ["再睡会觉,时间还早呢!",
					          "外面怎么这么吵!又是那些跳广场舞的大妈。",
					          "唉!还让不让我睡觉了!"],
					 "select":{"1-|继续":"next"}
				},
				{
					"order_id":2,
					"type":"plot",
					"data": [
					"我拉开窗帘,外面的阳光比以前更加耀眼,天上好像有两个太阳,这咋回事?",
					"跳广场舞的音乐继续放着,可是外面那些的大妈也没有在跳广场舞,都在指着天上的太阳,好像在议论着什么。"],
					"select":{"1-|继续":"next"}
				},
				{
					"order_id":3,
					"type":"think",
					"data": [
					"这咋回事,可能真的两太阳?",
					"这个天文自然现象百年不遇,不管它了,实在太困了。",
					"对,先睡觉,起床后,再看看怎么回事!"],
					"select":{"1-|继续":"next"}
				},
				{
					"order_id":4,
					"type":"plot",
					"data": [
					"我拉上窗帘,睡了不知道多久,被外面的敲门声吵醒",
					"这谁呀?一般没有人周日这时候来到我家找我?",
					"我大学毕业后,就来这个城市打工也有好几年了,这个曾经陌生的城市,现在已经很熟悉了。",
					"现在我一个住在这租来的房子里,小区位置偏远了一些,但环境不错,租金也不贵。"
					],
					"select":{"1-|继续":"next"}
				},
				{
					"order_id":5,
					"type":"think",
	                "data": 
	                ["同事一般来我家玩,都要和我预约时间,这谁呢?!",
	                "这么早来打扰我的美梦。敲门声还在继续,而且越敲越重。",
	                "要不要打开门看看呢?"],
	                "select":{"1-|不开门":"next","2-|开门":"go_order_id 7"}
				},
				{
					"order_id":6,
					"type":"plot",
	                "data": 
	                ["一个厚重的男声说:‘开门,我们有要事找您,您不开门会后悔一辈子的。’",
	                "一个清脆的女声说:‘先生,我们是好人,请您打开门。这样吧,我们把信放在门口,请您一定要看。’"
	                ],
	                "select":{"1-|开门":"next"}
				},
				{
					"order_id":7,
					"type":"plot",
	                "data": 
	                ["我迟疑了许久,才打开门。",
	                "门外已经没有人了,那些敲门的人肯定离开了。",
	                "我捡起门口的信封,回到家里。"
	                ],
	                "select":{"1-|阅信":"next"}
				},
				{
					"order_id":8,
					"type":"plot",
	                "data": 
	                ["我打开信封,里面有一张卡片,上面写着:",
	                "尊敬的#player_user#,请您于今天下午4点,到本市的白蛋酒店集合,晚上参加会餐", 
	                "会议重要,请勿缺席,会后您将参加一个长期旅行团,请您携带可以长期生活的一切必要行李", 
	                "此次旅行将很漫长,请做好充足的准备,感谢您的参加",
	                "卡片下面画了一个红色的小球,外面包围着很多银色的小球。"
	                ],
	                "select":{"1-|继续":"next"}
				},	
				{
					"order_id":9,
					"type":"think",
	                "data": 
	                ["这是个什么样的会议,很奇怪?!",
	                "卡片下面绘制的图案很精美,只是不知道代表了什么特殊的含义。",
	                "参加会议免费,还可以有晚餐,还可以免费旅行。",
	                "只是不知道这次旅行好玩不,去哪此地方玩",
	                "还要带上长期生活的行李,如果参加会议,肯定暂时回来不了,去不去呢?",
	                "反正吃喝玩乐免费,万一有危险,我离开酒店就可以了,这个酒店我去过,是一个大型正规酒店。",
	                "还是去吧!就这么决定了,现在就开始清理行李,随便做个中饭就出发",
	                "走之前,我还得把房间处理好,暂时回不来了,把水电和天然气都关好。"
	                ],
	                "select":{"1-|吃完中饭":"next"}
				}										
			]
		}
	]
}