Commit 2cc864c5 authored by 神楽坂玲奈's avatar 神楽坂玲奈

nothing

parent 1d260837
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * text=auto
# Custom for Visual Studio *.rb text
*.cs diff=csharp *.yml text
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit *.html text
*.doc diff=astextplain *.js text
*.DOC diff=astextplain *.coffee text
*.docx diff=astextplain *.css text
*.DOCX diff=astextplain *.less text
*.dot diff=astextplain
*.DOT diff=astextplain *.png binary
*.pdf diff=astextplain *.jpg binary
*.PDF diff=astextplain \ No newline at end of file
*.rtf diff=astextplain
*.RTF diff=astextplain
#游戏适配器的抽象类 #游戏适配器的抽象类
require_relative 'game_event' require_relative 'game_event'
require_relative 'action' require_relative 'action'
require_relative 'user' require_relative 'user'
require_relative 'room' require_relative 'room'
require_relative 'server' require_relative 'server'
class Game class Game
attr_reader :users, :rooms, :servers, :filter attr_reader :users, :rooms, :servers, :filter
attr_accessor :user, :room, :player_field, :opponent_field, :turn, :turn_player, :phase attr_accessor :user, :room, :player_field, :opponent_field, :turn, :turn_player, :phase
def initialize def initialize
@users = [] @users = []
@rooms = [] @rooms = []
@servers = [] @servers = []
@filter = {servers: [], waiting_only: false, normal_only: false} @filter = {servers: [], waiting_only: false, normal_only: false}
end end
def login(username, password=nil) def login(username, password=nil)
end end
def refresh def refresh
end end
def host(room_name, room_config) def host(room_name, room_config)
end end
def join(room) def join(room)
end end
def watch(room) def watch(room)
end end
def leave def leave
end end
def action(action) def action(action)
end end
def chat(chatmessage) def chat(chatmessage)
end end
def exit def exit
$scene = Scene_Login.new if $scene $scene = Scene_Login.new if $scene
end end
def watching? def watching?
@room and @room.include? @user @room and @room.include? @user
end end
def self.deck_edit def self.deck_edit
require_relative 'window_deck' require_relative 'window_deck'
@deck_window = Window_Deck.new @deck_window = Window_Deck.new
end end
def refresh_interval def refresh_interval
5 5
end end
def show_chat_self def show_chat_self
false false
end end
end end
#!/usr/bin/env ruby #!/usr/bin/env ruby
begin begin
Windows = RUBY_PLATFORM["win"] || RUBY_PLATFORM["ming"] Windows = RUBY_PLATFORM["win"] || RUBY_PLATFORM["ming"]
Dir.glob('post_update_*.rb').sort.each { |file| load file } Dir.glob('post_update_*.rb').sort.each { |file| load file }
Thread.abort_on_exception = true Thread.abort_on_exception = true
require_relative 'resolution' require_relative 'resolution'
require_relative 'announcement' require_relative 'announcement'
require_relative 'config' require_relative 'config'
require_relative 'association' require_relative 'association'
#i18n #i18n
require 'i18n' require 'i18n'
require 'locale' require 'locale'
I18n.load_path += Dir['locales/*.yml'] I18n.load_path += Dir['locales/*.yml']
I18n::Backend::Simple.include(I18n::Backend::Fallbacks) I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
#读取配置文件 #读取配置文件
$config = Config.load $config = Config.load
Config.save Config.save
#读取命令行参数 #读取命令行参数
log = "log.log" log = "log.log"
log_level = "INFO" log_level = "INFO"
profile = nil profile = nil
ARGV.each do |arg| ARGV.each do |arg|
arg = arg.dup.force_encoding("UTF-8") arg = arg.dup.force_encoding("UTF-8")
arg.force_encoding("GBK") unless arg.valid_encoding? arg.force_encoding("GBK") unless arg.valid_encoding?
case arg case arg
when /--log=(.*)/ when /--log=(.*)/
log.replace $1 log.replace $1
when /--log-level=(.*)/ when /--log-level=(.*)/
log_level.replace $1 log_level.replace $1
when /--profile=(.*)/ when /--profile=(.*)/
profile = $1 profile = $1
when /^mycard:.*|\.ydk$|\.yrp$|\.deck$/ when /^mycard:.*|\.ydk$|\.yrp$|\.deck$/
require_relative 'quickstart' require_relative 'quickstart'
$scene = false $scene = false
when /register_association/ when /register_association/
Association.register Association.register
$scene = false $scene = false
end end
end end
unless $scene == false unless $scene == false
#加载文件 #加载文件
require 'logger' require 'logger'
require 'sdl' require 'sdl'
include SDL include SDL
require_relative 'dialog' require_relative 'dialog'
require_relative 'graphics' require_relative 'graphics'
require_relative 'window' require_relative 'window'
require_relative 'widget_msgbox' require_relative 'widget_msgbox'
#日志 #日志
if log == "STDOUT" #调试用 if log == "STDOUT" #调试用
log = STDOUT log = STDOUT
end end
$log = Logger.new(log, 1, 1024000) $log = Logger.new(log, 1, 1024000)
$log.level = Logger.const_get log_level $log.level = Logger.const_get log_level
#性能分析 #性能分析
if profile if profile
if profile == "STDOUT" if profile == "STDOUT"
profile = STDOUT profile = STDOUT
else else
profile = open(profile, 'w') profile = open(profile, 'w')
end end
require 'profiler' require 'profiler'
RubyVM::InstructionSequence.compile_option = { RubyVM::InstructionSequence.compile_option = {
:trace_instruction => true, :trace_instruction => true,
:specialized_instruction => false :specialized_instruction => false
} }
Profiler__::start_profile Profiler__::start_profile
end end
SDL::Event::APPMOUSEFOCUS = 1 SDL::Event::APPMOUSEFOCUS = 1
SDL::Event::APPINPUTFOCUS = 2 SDL::Event::APPINPUTFOCUS = 2
SDL::Event::APPACTIVE = 4 SDL::Event::APPACTIVE = 4
SDL.putenv ("SDL_VIDEO_CENTERED=1"); SDL.putenv ("SDL_VIDEO_CENTERED=1");
SDL.init(INIT_VIDEO) SDL.init(INIT_VIDEO)
WM::set_caption("MyCard", "MyCard") WM::set_caption("MyCard", "MyCard")
WM::icon = Surface.load("graphics/system/icon.gif") WM::icon = Surface.load("graphics/system/icon.gif")
$screen = Screen.open($config['screen']['width'], $config['screen']['height'], 0, HWSURFACE | ($config['screen']['fullscreen'] ? FULLSCREEN : 0)) $screen = Screen.open($config['screen']['width'], $config['screen']['height'], 0, HWSURFACE | ($config['screen']['fullscreen'] ? FULLSCREEN : 0))
TTF.init TTF.init
#声音 #声音
begin begin
SDL.init(INIT_AUDIO) SDL.init(INIT_AUDIO)
Mixer.open(Mixer::DEFAULT_FREQUENCY, Mixer::DEFAULT_FORMAT, Mixer::DEFAULT_CHANNELS, 1536) Mixer.open(Mixer::DEFAULT_FREQUENCY, Mixer::DEFAULT_FORMAT, Mixer::DEFAULT_CHANNELS, 1536)
Mixer.set_volume_music(60) Mixer.set_volume_music(60)
rescue rescue
nil nil
end end
#标题场景 #标题场景
require_relative 'scene_title' require_relative 'scene_title'
$scene = Scene_Title.new $scene = Scene_Title.new
#自动更新, 加载放到SDL前面会崩, 原因不明 #自动更新, 加载放到SDL前面会崩, 原因不明
require_relative 'update' require_relative 'update'
Update.start Update.start
WM::set_caption("MyCard v#{Update::Version}", "MyCard") WM::set_caption("MyCard v#{Update::Version}", "MyCard")
#文件关联 #文件关联
Association.start Association.start
#初始化完毕 #初始化完毕
$log.info("main") { "初始化成功" } $log.info("main") { "初始化成功" }
end end
rescue Exception => exception rescue Exception => exception
open('error-程序出错请到论坛反馈.txt', 'w') { |f| f.write [exception.inspect, *exception.backtrace].join("\n") } open('error-程序出错请到论坛反馈.txt', 'w') { |f| f.write [exception.inspect, *exception.backtrace].join("\n") }
$scene = false $scene = false
end end
#主循环 #主循环
begin begin
$scene.main while $scene $scene.main while $scene
rescue Exception => exception rescue Exception => exception
exception.backtrace.each { |backtrace| break if backtrace =~ /^(.*)\.rb:\d+:in `.*'"$/ } #由于脚本是从main.rb开始执行的,总会有个能匹配成功的文件 exception.backtrace.each { |backtrace| break if backtrace =~ /^(.*)\.rb:\d+:in `.*'"$/ } #由于脚本是从main.rb开始执行的,总会有个能匹配成功的文件
$log.fatal($1) { [exception.inspect, *exception.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") } $log.fatal($1) { [exception.inspect, *exception.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
$game.exit if $game $game.exit if $game
require_relative 'scene_error' require_relative 'scene_error'
$scene = Scene_Error.new $scene = Scene_Error.new
retry retry
ensure ensure
if profile if profile
Profiler__::print_profile(profile) Profiler__::print_profile(profile)
profile.close profile.close
end end
$log.close rescue nil $log.close rescue nil
end end
\ No newline at end of file
require 'open-uri' require 'open-uri'
require "fileutils" require "fileutils"
require_relative 'card' require_relative 'card'
module Update module Update
Version = '0.8.5' Version = '0.8.6'
URL = "http://my-card.in/mycard/update.json?version=#{Version}" URL = "http://my-card.in/mycard/update.json?version=#{Version}"
class <<self class <<self
attr_reader :thumbnails, :images, :status attr_reader :thumbnails, :images, :status
def start def start
Dir.glob("mycard-update-*-*.zip") do |file| Dir.glob("mycard-update-*-*.zip") do |file|
file =~ /mycard-update-(.+?)-(.+?)\.zip/ file =~ /mycard-update-(.+?)-(.+?)\.zip/
if $1 <= Version and $2 > Version if $1 <= Version and $2 > Version
$log.info('安装更新'){file} $log.info('安装更新'){file}
WM::set_caption("MyCard - 正在更新 #{Version} -> #{$2}", "MyCard") WM::set_caption("MyCard - 正在更新 #{Version} -> #{$2}", "MyCard")
require 'zip/zip' require 'zip/zip'
Zip::ZipFile::open(file) do |zip| Zip::ZipFile::open(file) do |zip|
zip.each do |f| zip.each do |f|
if !File.directory?(f.name) if !File.directory?(f.name)
FileUtils.mkdir_p(File.dirname(f.name)) FileUtils.mkdir_p(File.dirname(f.name))
end end
f.extract{true} f.extract{true}
end end
end rescue $log.error('安装更新出错'){file+$!.inspect+$!.backtrace.inspect} end rescue $log.error('安装更新出错'){file+$!.inspect+$!.backtrace.inspect}
Version.replace $2 Version.replace $2
File.delete file File.delete file
@updated = true @updated = true
end end
end end
if @updated if @updated
IO.popen('./mycard') IO.popen('./mycard')
$scene = nil $scene = nil
end end
@images = [] @images = []
@thumbnails = [] @thumbnails = []
@status = '正在检查更新' @status = '正在检查更新'
@updated = false @updated = false
Thread.new do Thread.new do
open(URL) do |file| open(URL) do |file|
require 'json' require 'json'
reply = file.read reply = file.read
$log.info('下载更新-服务器回传'){reply} $log.info('下载更新-服务器回传'){reply}
reply = JSON.parse(reply) reply = JSON.parse(reply)
$log.info('下载更新-解析后'){reply.inspect} $log.info('下载更新-解析后'){reply.inspect}
reply.each do |fil| reply.each do |fil|
name = File.basename fil name = File.basename fil
@status.replace "正在下载更新#{name}" @status.replace "正在下载更新#{name}"
open(fil, 'rb') do |fi| open(fil, 'rb') do |fi|
$log.info('下载完毕'){name} $log.info('下载完毕'){name}
@updated = true @updated = true
open(name, 'wb') do |f| open(name, 'wb') do |f|
f.write fi.read f.write fi.read
end end
end rescue $log.error('下载更新'){'下载更新失败'} end rescue $log.error('下载更新'){'下载更新失败'}
end end
end rescue $log.error('检查更新'){'检查更新失败'} end rescue $log.error('检查更新'){'检查更新失败'}
if @updated if @updated
require_relative 'widget_msgbox' require_relative 'widget_msgbox'
Widget_Msgbox.new('mycard', '下载更新完毕,点击确定重新运行mycard并安装更新', :ok => "确定"){IO.popen('./mycard'); $scene = nil} Widget_Msgbox.new('mycard', '下载更新完毕,点击确定重新运行mycard并安装更新', :ok => "确定"){IO.popen('./mycard'); $scene = nil}
end end
if File.file? "ygocore/cards.cdb" if File.file? "ygocore/cards.cdb"
require 'sqlite3' require 'sqlite3'
db = SQLite3::Database.new( "ygocore/cards.cdb" ) db = SQLite3::Database.new( "ygocore/cards.cdb" )
db.execute( "select id from datas" ) do |row| db.execute( "select id from datas" ) do |row|
@thumbnails << row[0] @thumbnails << row[0]
end end
@images.replace @thumbnails @images.replace @thumbnails
if !File.directory?('ygocore/pics/thumbnail') if !File.directory?('ygocore/pics/thumbnail')
FileUtils.mkdir_p('ygocore/pics/thumbnail') FileUtils.mkdir_p('ygocore/pics/thumbnail')
end end
existed_thumbnails = [] existed_thumbnails = []
Dir.foreach("ygocore/pics/thumbnail") do |file| Dir.foreach("ygocore/pics/thumbnail") do |file|
if file =~ /(\d+)\.jpg/ if file =~ /(\d+)\.jpg/
existed_thumbnails << $1.to_i existed_thumbnails << $1.to_i
end end
end end
@thumbnails -= existed_thumbnails @thumbnails -= existed_thumbnails
existed_images = [] existed_images = []
Dir.foreach("ygocore/pics") do |file| Dir.foreach("ygocore/pics") do |file|
if file =~ /(\d+)\.jpg/ if file =~ /(\d+)\.jpg/
existed_images << $1.to_i existed_images << $1.to_i
end end
end end
@images -= existed_images @images -= existed_images
existed_images = [] existed_images = []
if (!@images.empty? or !@thumbnails.empty?) and File.file?("#{Card::PicPath}/1.jpg") if (!@images.empty? or !@thumbnails.empty?) and File.file?("#{Card::PicPath}/1.jpg")
db_mycard = SQLite3::Database.new( "data/data.sqlite" ) db_mycard = SQLite3::Database.new( "data/data.sqlite" )
db_mycard.execute( "select id, number from `yu-gi-oh` where number in (#{(@images+@thumbnails).uniq.collect{|number|"'%08d'" % number}.join(',')})" ) do |row| db_mycard.execute( "select id, number from `yu-gi-oh` where number in (#{(@images+@thumbnails).uniq.collect{|number|"'%08d'" % number}.join(',')})" ) do |row|
id = row[0] id = row[0]
number = row[1].to_i number = row[1].to_i
src = "#{Card::PicPath}/#{id}.jpg" src = "#{Card::PicPath}/#{id}.jpg"
dest = "ygocore/pics/#{number}.jpg" dest = "ygocore/pics/#{number}.jpg"
dest_thumb = "ygocore/pics/thumbnail/#{number}.jpg" dest_thumb = "ygocore/pics/thumbnail/#{number}.jpg"
if File.file?(src) if File.file?(src)
@status.replace "检测到存在iDuel卡图 正在导入 #{id}.jpg" @status.replace "检测到存在iDuel卡图 正在导入 #{id}.jpg"
existed_images << number existed_images << number
if !File.exist?(dest) if !File.exist?(dest)
FileUtils.copy_file(src, dest) FileUtils.copy_file(src, dest)
FileUtils.copy_file(src, dest_thumb) FileUtils.copy_file(src, dest_thumb)
end end
end end
end end
end end
@images -= existed_images @images -= existed_images
@thumbnails -= existed_images @thumbnails -= existed_images
@thumbnails = (@thumbnails & @images) + (@thumbnails - @images) @thumbnails = (@thumbnails & @images) + (@thumbnails - @images)
unless @thumbnails.empty? and @images.empty? unless @thumbnails.empty? and @images.empty?
$log.info('待下载的完整卡图'){@images.inspect} $log.info('待下载的完整卡图'){@images.inspect}
$log.info('待下载的缩略卡图'){@thumbnails.inspect} $log.info('待下载的缩略卡图'){@thumbnails.inspect}
threads = 5.times.collect do threads = 5.times.collect do
thread = Thread.new do thread = Thread.new do
while number = @thumbnails.pop while number = @thumbnails.pop
@status.replace "正在下载缩略卡图 (剩余#{@thumbnails.size}张)" @status.replace "正在下载缩略卡图 (剩余#{@thumbnails.size}张)"
open("http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg", 'rb') do |remote| open("http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg", 'rb') do |remote|
next if File.file? "ygocore/pics/thumbnail/#{number}.jpg" next if File.file? "ygocore/pics/thumbnail/#{number}.jpg"
#$log.debug('下载缩略卡图'){"http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg 到 ygocore/pics/thumbnail/#{number}.jpg" } #$log.debug('下载缩略卡图'){"http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg 到 ygocore/pics/thumbnail/#{number}.jpg" }
open("ygocore/pics/thumbnail/#{number}.jpg", 'wb') do |local| open("ygocore/pics/thumbnail/#{number}.jpg", 'wb') do |local|
local.write remote.read local.write remote.read
end end
end rescue $log.error('下载缩略出错'){"http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg 到 ygocore/pics/thumbnail/#{number}.jpg" } end rescue $log.error('下载缩略出错'){"http://my-card.in/images/cards/ygocore/thumbnail/#{number}.jpg 到 ygocore/pics/thumbnail/#{number}.jpg" }
end end
while number = @images.pop while number = @images.pop
@status.replace "正在下载完整卡图 (剩余#{@images.size}张)" @status.replace "正在下载完整卡图 (剩余#{@images.size}张)"
#$log.debug('下载完整卡图'){"http://my-card.in/images/cards/ygocore/#{number}.jpg 到 ygocore/pics/#{number}.jpg" } #$log.debug('下载完整卡图'){"http://my-card.in/images/cards/ygocore/#{number}.jpg 到 ygocore/pics/#{number}.jpg" }
open("http://my-card.in/images/cards/ygocore/#{number}.jpg", 'rb') do |remote| open("http://my-card.in/images/cards/ygocore/#{number}.jpg", 'rb') do |remote|
next if File.file? "ygocore/pics/#{number}.jpg" next if File.file? "ygocore/pics/#{number}.jpg"
open("ygocore/pics/#{number}.jpg", 'wb') do |local| open("ygocore/pics/#{number}.jpg", 'wb') do |local|
local.write remote.read local.write remote.read
end end
end rescue $log.error('下载完整卡图出错'){"http://my-card.in/images/cards/ygocore/#{number}.jpg 到 ygocore/pics/#{number}.jpg" } end rescue $log.error('下载完整卡图出错'){"http://my-card.in/images/cards/ygocore/#{number}.jpg 到 ygocore/pics/#{number}.jpg" }
end end
end end
thread.priority = -1 thread.priority = -1
thread thread
end end
threads.each{|thread|thread.join} threads.each{|thread|thread.join}
end end
end rescue $log.error('卡图更新'){'找不到ygocore卡片数据库'} end rescue $log.error('卡图更新'){'找不到ygocore卡片数据库'}
@status = nil @status = nil
end.priority = -1 end.priority = -1
end end
end end
end end
#============================================================================== #==============================================================================
# ■ Scene_Title # ■ Scene_Title
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
#  title #  title
#============================================================================== #==============================================================================
require_relative 'widget_scrollbar' require_relative 'widget_scrollbar'
require_relative 'widget_inputbox' require_relative 'widget_inputbox'
require_relative 'chatmessage' require_relative 'chatmessage'
require_relative 'window_scrollable' require_relative 'window_scrollable'
class Window_Chat < Window_Scrollable class Window_Chat < Window_Scrollable
WLH=16 WLH=16
def initialize(x, y, width, height) def initialize(x, y, width, height)
super(x,y,width,height) super(x,y,width,height)
if @width > 600 #判断大厅还是房间,这个判据比较囧,待优化 if @width > 600 #判断大厅还是房间,这个判据比较囧,待优化
@chat_background = Surface.load("graphics/system/chat.png").display_format @chat_background = Surface.load("graphics/system/chat.png").display_format
else else
@chat_background = Surface.load("graphics/system/chat_room.png").display_format @chat_background = Surface.load("graphics/system/chat_room.png").display_format
end end
@background = @contents.copy_rect(0,0,@contents.w,@contents.h) #new而已。。 @background = @contents.copy_rect(0,0,@contents.w,@contents.h) #new而已。。
@background.fill_rect(0,0,@background.w, @background.h, 0xFFb2cefe) @background.fill_rect(0,0,@background.w, @background.h, 0xFFb2cefe)
@background.put(@chat_background,0,31-4) @background.put(@chat_background,0,31-4)
@tab = Surface.load "graphics/system/tab.png" @tab = Surface.load "graphics/system/tab.png"
@chat_input = Widget_InputBox.new(@x+8, @y+@height-24-10, @width-14, 24) do |key| @chat_input = Widget_InputBox.new(@x+8, @y+@height-24-10, @width-14, 24) do |key|
case key case key
when :ENTER when :ENTER
if !@chat_input.value.empty? if !@chat_input.value.empty?
chatmessage = ChatMessage.new($game.user, @chat_input.value, @channel) chatmessage = ChatMessage.new($game.user, @chat_input.value, @channel)
$game.chat chatmessage $game.chat chatmessage
Game_Event.push Game_Event::Chat.new(chatmessage) if !$game.is_a? Ygocore Game_Event.push Game_Event::Chat.new(chatmessage) if !$game.is_a? Ygocore
true true
end end
end end
end end
@chat_input.refresh @chat_input.refresh
@font = TTF.open("fonts/wqy-microhei.ttc", 14) @font = TTF.open("fonts/wqy-microhei.ttc", 14)
@scrollbar = Widget_ScrollBar.new(self,@x+@width-20-8,@y+31+3,@height-68) @scrollbar = Widget_ScrollBar.new(self,@x+@width-20-8,@y+31+3,@height-68)
@page_size = (@height-68)/WLH @page_size = (@height-68)/WLH
@@list ||= {} @@list ||= {}
@list_splited = {} @list_splited = {}
@@list.each_pair do |channel, chatmessages| @@list.each_pair do |channel, chatmessages|
chatmessages.each do |chatmessage| chatmessages.each do |chatmessage|
add_split(chatmessage) add_split(chatmessage)
end end
end end
@channels = [] @channels = []
self.channel = :lobby self.channel = :lobby
end end
def add(chatmessage) def add(chatmessage)
@@list[chatmessage.channel] ||= [] @@list[chatmessage.channel] ||= []
unless @channels.include? chatmessage.channel unless @channels.include? chatmessage.channel
@channels << chatmessage.channel @channels << chatmessage.channel
refresh refresh
end end
@@list[chatmessage.channel] << chatmessage @@list[chatmessage.channel] << chatmessage
scroll_bottom = @items.size - self.scroll <= @page_size scroll_bottom = @items.size - self.scroll <= @page_size
add_split(chatmessage) add_split(chatmessage)
if chatmessage.channel == @channel if chatmessage.channel == @channel
@scroll = [@items.size - @page_size, 0].max if scroll_bottom @scroll = [@items.size - @page_size, 0].max if scroll_bottom
refresh refresh
end end
end end
def add_split(chatmessage) def add_split(chatmessage)
@list_splited[chatmessage.channel] ||= [] @list_splited[chatmessage.channel] ||= []
@list_splited[chatmessage.channel] << [chatmessage, ""] @list_splited[chatmessage.channel] << [chatmessage, ""]
width = name_width(chatmessage) width = name_width(chatmessage)
line = 0 line = 0
chatmessage.message.each_char do |char| chatmessage.message.each_char do |char|
if char == "\n" if char == "\n"
line += 1 line += 1
width = 0 width = 0
@list_splited[chatmessage.channel] << [chatmessage.message_color, ""] @list_splited[chatmessage.channel] << [chatmessage.message_color, ""]
else else
char_width = @font.text_size(char)[0] char_width = @font.text_size(char)[0]
if char_width + width > @width-14-20 if char_width + width > @width-14-20
line += 1 line += 1
width = char_width width = char_width
@list_splited[chatmessage.channel] << [chatmessage.message_color, char] @list_splited[chatmessage.channel] << [chatmessage.message_color, char]
else else
@list_splited[chatmessage.channel].last[1] << char @list_splited[chatmessage.channel].last[1] << char
width += char_width width += char_width
end end
end end
end end
end end
def mousemoved(x,y) def mousemoved(x,y)
if y-@y < 31 and (x-@x) < @channels.size * 100 if y-@y < 31 and (x-@x) < @channels.size * 100
self.index = @channels[(x-@x) / 100] self.index = @channels[(x-@x) / 100]
else else
self.index = nil self.index = nil
end end
end end
def clicked def clicked
case @index case @index
when nil when nil
when Integer when Integer
else else
self.channel = @index self.channel = @index
end end
end end
def channel=(channel) def channel=(channel)
return if @channel == channel return if @channel == channel
@channel = channel @channel = channel
@channels << channel unless @channels.include? channel @channels << channel unless @channels.include? channel
@list_splited[channel] ||= [] @list_splited[channel] ||= []
@items = @list_splited[channel] @items = @list_splited[channel]
@scroll = [@items.size - @page_size, 0].max @scroll = [@items.size - @page_size, 0].max
refresh refresh
end end
def draw_item(index, status=0) def draw_item(index, status=0)
case index case index
when nil when nil
when Integer #描绘聊天消息 when Integer #描绘聊天消息
draw_item_chatmessage(index, status) draw_item_chatmessage(index, status)
else #描绘频道标签 else #描绘频道标签
draw_item_channel(index, status) draw_item_channel(index, status)
end end
end end
def draw_item_channel(channel, status) def draw_item_channel(channel, status)
index = @channels.index(channel) index = @channels.index(channel)
Surface.blit(@tab,0,@channel == channel ? 0 : 31,100,31,@contents,index*100+3,0) Surface.blit(@tab,0,@channel == channel ? 0 : 31,100,31,@contents,index*100+3,0)
channel_name = ChatMessage.channel_name channel channel_name = ChatMessage.channel_name channel
x = index*100+(100 - @font.text_size(channel_name)[0])/2 x = index*100+(100 - @font.text_size(channel_name)[0])/2
draw_stroked_text(channel_name,x,8,1,@font, [255,255,255], ChatMessage.channel_color(channel)) draw_stroked_text(channel_name,x,8,1,@font, [255,255,255], ChatMessage.channel_color(channel))
end end
def draw_item_chatmessage(index, status) def draw_item_chatmessage(index, status)
x,y = item_rect_chatmessage(index) x,y = item_rect_chatmessage(index)
chatmessage, message = @items[index] chatmessage, message = @items[index]
if chatmessage.is_a? ChatMessage if chatmessage.is_a? ChatMessage
@font.draw_blended_utf8(@contents, chatmessage.user.name+':', x, y, *chatmessage.name_color) if chatmessage.name_visible? @font.draw_blended_utf8(@contents, chatmessage.user.name+':', x, y, *chatmessage.name_color) if chatmessage.name_visible?
@font.draw_blended_utf8(@contents, message, x+name_width(chatmessage), y, *chatmessage.message_color) unless chatmessage.message.empty? @font.draw_blended_utf8(@contents, message, x+name_width(chatmessage), y, *chatmessage.message_color) unless chatmessage.message.empty?
else else
@font.draw_blended_utf8(@contents, message, x, y, *chatmessage) unless message.empty? @font.draw_blended_utf8(@contents, message, x, y, *chatmessage) unless message.empty?
end end
end end
def item_rect(index) def item_rect(index)
case index case index
when nil when nil
when Integer #描绘聊天消息 when Integer #描绘聊天消息
item_rect_chatmessage(index) item_rect_chatmessage(index)
else #描绘频道标签 else #描绘频道标签
item_rect_channel(index) item_rect_channel(index)
end end
end end
def item_rect_channel(channel) def item_rect_channel(channel)
[@channels.index(channel)*100+3, 0, 100, 31] [@channels.index(channel)*100+3, 0, 100, 31]
end end
def item_rect_chatmessage(index) def item_rect_chatmessage(index)
[8, (index-@scroll)*WLH+31+3, @width, self.class::WLH] [8, (index-@scroll)*WLH+31+3, @width, self.class::WLH]
end end
def refresh def refresh
super super
@channels.each {|channel|draw_item_channel(channel, @index==channel)} @channels.each {|channel|draw_item_channel(channel, @index==channel)}
end end
def name_width(chatmessage) def name_width(chatmessage)
chatmessage.name_visible? ? @font.text_size(chatmessage.user.name+':')[0] : 0 chatmessage.name_visible? ? @font.text_size(chatmessage.user.name+':')[0] : 0
end end
def index_legal?(index) def index_legal?(index)
case index case index
when nil,Integer when nil,Integer
super super
else else
@channels.include? index @channels.include? index
end end
end end
def scroll_up def scroll_up
self.scroll -= 1 self.scroll -= 1
end end
def scroll_down def scroll_down
self.scroll += 1 self.scroll += 1
end end
def update def update
@chat_input.update @chat_input.update
end end
end end
\ No newline at end of file
require_relative 'window_host' require_relative 'window_host'
class Window_LobbyButtons < Window_List class Window_LobbyButtons < Window_List
def initialize(x, y) def initialize(x, y)
@items = [I18n.t('lobby.faq'), I18n.t('lobby.filter'), I18n.t('lobby.editdeck'), I18n.t('lobby.newroom')] @items = [I18n.t('lobby.faq'), I18n.t('lobby.filter'), I18n.t('lobby.editdeck'), I18n.t('lobby.newroom')]
@button = Surface.load("graphics/lobby/button.png") @button = Surface.load("graphics/lobby/button.png")
super(x, y, @items.size*@button.w/3+@items.size*4, 30) super(x, y, @items.size*@button.w/3+@items.size*4, 30)
@font = TTF.open("fonts/wqy-microhei.ttc", 15) @font = TTF.open("fonts/wqy-microhei.ttc", 15)
refresh refresh
end end
def draw_item(index, status=0) def draw_item(index, status=0)
x, y, width=item_rect(index) x, y, width=item_rect(index)
Surface.blit(@button, status*@button.w/3, 0, @button.w/3, @button.h, @contents, x, y) Surface.blit(@button, status*@button.w/3, 0, @button.w/3, @button.h, @contents, x, y)
draw_stroked_text(@items[index], x+center_margin(@items[index],width,@font), y+3, 2, @font, [0xdf, 0xf1, 0xff], [0x27, 0x43, 0x59]) draw_stroked_text(@items[index], x+center_margin(@items[index],width,@font), y+3, 2, @font, [0xdf, 0xf1, 0xff], [0x27, 0x43, 0x59])
end end
def item_rect(index) def item_rect(index)
[index*@button.w/3+(index)*4, 0, @button.w/3, @height] [index*@button.w/3+(index)*4, 0, @button.w/3, @height]
end end
def mousemoved(x, y) def mousemoved(x, y)
if (x-@x) % (@button.w/3+4) >= @button.w/3 if (x-@x) % (@button.w/3+4) >= @button.w/3
self.index = nil self.index = nil
else else
self.index = (x-@x)/(@button.w/3+4) self.index = (x-@x)/(@button.w/3+4)
end end
end end
def lostfocus(active_window = nil) def lostfocus(active_window = nil)
self.index = nil self.index = nil
end end
def clicked def clicked
case @index case @index
when 0 #常见问题 when 0 #常见问题
require_relative 'dialog' require_relative 'dialog'
Dialog.web "http://my-card.in/login?user[name]=#{CGI.escape $game.user.name}&user[password]=#{CGI.escape $game.password}&continue=/topics/1453" Dialog.web "http://my-card.in/login?user[name]=#{CGI.escape $game.user.name}&user[password]=#{CGI.escape $game.password}&continue=/topics/1453"
when 1 #房间筛选 when 1 #房间筛选
if @filter_window and !@filter_window.destroyed? if @filter_window and !@filter_window.destroyed?
@filter_window.destroy @filter_window.destroy
else else
@filter_window = Window_Filter.new(678, 44) @filter_window = Window_Filter.new(678, 44)
end end
when 2 #卡组编辑 when 2 #卡组编辑
require_relative 'deck' require_relative 'deck'
$game.class.deck_edit $game.class.deck_edit
when 3 #建立房间 when 3 #建立房间
@host_window = Window_Host.new(300, 200) @host_window = Window_Host.new(300, 200)
end end
end end
def update def update
@host_window.update if @host_window and !@host_window.destroyed? @host_window.update if @host_window and !@host_window.destroyed?
end end
end end
#encoding: UTF-8 #encoding: UTF-8
#============================================================================== #==============================================================================
# Window_UserInfo # Window_UserInfo
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# 游戏大厅显示用户信息的类 # 游戏大厅显示用户信息的类
#============================================================================== #==============================================================================
class Window_UserInfo < Window class Window_UserInfo < Window
def initialize(x, y, user) def initialize(x, y, user)
@avatar_boarder = Surface.load("graphics/lobby/avatar_boader.png") @avatar_boarder = Surface.load("graphics/lobby/avatar_boader.png")
super(x,y,280,144) super(x,y,280,144)
@font = TTF.open('fonts/wqy-microhei.ttc', 16) @font = TTF.open('fonts/wqy-microhei.ttc', 16)
@user = user @user = user
@background = Surface.load("graphics/lobby/userinfo.png").display_format @background = Surface.load("graphics/lobby/userinfo.png").display_format
refresh refresh
end end
def refresh def refresh
@contents.put(@background, 0, 0) @contents.put(@background, 0, 0)
@thread = @user.avatar(:middle) do |avatar| @thread = @user.avatar(:middle) do |avatar|
clear(0,0,@avatar_boarder.w, @avatar_boarder.h) clear(0,0,@avatar_boarder.w, @avatar_boarder.h)
@contents.put(avatar, 12, 12) @contents.put(avatar, 12, 12)
@contents.put(@avatar_boarder, 0, 0) @contents.put(@avatar_boarder, 0, 0)
end end
@font.draw_blended_utf8(@contents, @user.name, 160, 12, 0x00,0x00,0x00) unless @user.name.empty? @font.draw_blended_utf8(@contents, @user.name, 160, 12, 0x00,0x00,0x00) unless @user.name.empty?
@font.draw_blended_utf8(@contents, @user.id.to_s , 160, 12+16*2, 0x00,0x00,0x00) unless @user.id.to_s.empty? @font.draw_blended_utf8(@contents, @user.id.to_s , 160, 12+16*2, 0x00,0x00,0x00) unless @user.id.to_s.empty?
@font.draw_blended_utf8(@contents, "Lv: #{@user.level}" , 160, 12+16*3, 0x00,0x00,0x00) if @user.respond_to? :level and @user.level #TODO:规范化,level是iduel专属的,但是又不太想让iduel来重定义这个window @font.draw_blended_utf8(@contents, "Lv: #{@user.level}" , 160, 12+16*3, 0x00,0x00,0x00) if @user.respond_to? :level and @user.level #TODO:规范化,level是iduel专属的,但是又不太想让iduel来重定义这个window
@font.draw_blended_utf8(@contents, "经验: #{@user.exp}", 160, 12+16*4, 0x00,0x00,0x00) if @user.respond_to? :exp and @user.exp @font.draw_blended_utf8(@contents, "经验: #{@user.exp}", 160, 12+16*4, 0x00,0x00,0x00) if @user.respond_to? :exp and @user.exp
end end
def dispose def dispose
@thread.exit @thread.exit
super super
end end
end end
#encoding: UTF-8 #encoding: UTF-8
load 'lib/ygocore/window_login.rb' load 'lib/ygocore/window_login.rb'
require 'eventmachine' require 'eventmachine'
require 'em-http' require 'em-http'
require 'websocket' require 'websocket'
require 'open-uri' require 'open-uri'
require 'yaml' require 'yaml'
class Ygocore < Game class Ygocore < Game
attr_reader :username attr_reader :username
attr_accessor :password attr_accessor :password
@@config = YAML.load_file("lib/ygocore/server.yml") @@config = YAML.load_file("lib/ygocore/server.yml")
def initialize def initialize
super super
load 'lib/ygocore/event.rb' load 'lib/ygocore/event.rb'
load 'lib/ygocore/user.rb' load 'lib/ygocore/user.rb'
load 'lib/ygocore/room.rb' load 'lib/ygocore/room.rb'
load 'lib/ygocore/scene_lobby.rb' load 'lib/ygocore/scene_lobby.rb'
require 'json' require 'json'
require 'xmpp4r/client' require 'xmpp4r/client'
require 'xmpp4r/muc' require 'xmpp4r/muc'
end end
def refresh_interval def refresh_interval
60 60
end end
def login(username, password) def login(username, password)
@username = username @username = username
@password = password @password = password
@nickname_conflict = [] @nickname_conflict = []
@@im = Jabber::Client.new(Jabber::JID::new(@username, 'my-card.in', 'mycard')) matched = @username.match Jabber::JID::PATTERN
@@im_room = Jabber::MUC::MUCClient.new(@@im) if matched[1] && matched[2]
Jabber.logger = $log @username = matched[1]
Jabber.debug = true jid = Jabber::JID::new @username, matched[2], matched[3] || 'mycard'
else
@@im.on_exception do |exception, c, where| jid = Jabber::JID::new @username, 'my-card.in', 'mycard'
$log.error('聊天出错') { [exception, c, where] } end
if where == :close
Game_Event.push(Game_Event::Chat.new(ChatMessage.new(User.new(:system, 'System'), '聊天服务连接中断'))) @@im = Jabber::Client.new(jid)
else @@im_room = Jabber::MUC::MUCClient.new(@@im)
Game_Event.push(Game_Event::Chat.new(ChatMessage.new(User.new(:system, 'System'), '聊天服务连接中断.1'))) Jabber.logger = $log
#sleep 5 Jabber.debug = true
#im_connect
end @@im.on_exception do |exception, c, where|
end $log.error('聊天出错') { [exception, c, where] }
@@im_room.add_message_callback do |m| Game_Event.push(Game_Event::Chat.new(ChatMessage.new(User.new(:system, 'System'), '聊天服务连接中断: ' + exception.to_s)))
user = m.from.resource == nickname ? @user : User.new(m.from.resource.to_sym, m.from.resource) end
Game_Event.push Game_Event::Chat.new ChatMessage.new(user, m.body, :lobby) rescue $log.error('收到聊天消息') { $! } @@im_room.add_message_callback do |m|
end user = m.from.resource == nickname ? @user : User.new(m.from.resource.to_sym, m.from.resource)
@@im_room.add_private_message_callback do |m| Game_Event.push Game_Event::Chat.new ChatMessage.new(user, m.body, :lobby) rescue $log.error('收到聊天消息') { $! }
if m.body #忽略无消息的正在输入等内容 end
user = m.from.resource == nickname ? @user : User.new(m.from.resource.to_sym, m.from.resource) @@im_room.add_private_message_callback do |m|
Game_Event.push Game_Event::Chat.new ChatMessage.new(user, m.body, user) rescue $log.error('收到私聊消息') { $! } if m.body #忽略无消息的正在输入等内容
end user = m.from.resource == nickname ? @user : User.new(m.from.resource.to_sym, m.from.resource)
end Game_Event.push Game_Event::Chat.new ChatMessage.new(user, m.body, user) rescue $log.error('收到私聊消息') { $! }
@@im_room.add_join_callback do |m| end
Game_Event.push Game_Event::NewUser.new User.new m.from.resource.to_sym, m.from.resource end
end @@im_room.add_join_callback do |m|
@@im_room.add_leave_callback do |m| Game_Event.push Game_Event::NewUser.new User.new m.from.resource.to_sym, m.from.resource
Game_Event.push Game_Event::MissingUser.new User.new m.from.resource.to_sym, m.from.resource end
end @@im_room.add_leave_callback do |m|
connect Game_Event.push Game_Event::MissingUser.new User.new m.from.resource.to_sym, m.from.resource
im_connect end
end connect
im_connect
def nickname end
return @nickname if @nickname
if @nickname_conflict.include? @username def nickname
1.upto(9) do |i| return @nickname if @nickname
result = "#{@username}-#{i}" if @nickname_conflict.include? @username
return result unless @nickname_conflict.include? result 1.upto(9) do |i|
end result = "#{@username}-#{i}"
raise 'can`t get available nickname' return result unless @nickname_conflict.include? result
else end
@username raise 'can`t get available nickname'
end else
end @username
end
def connect end
@recv = Thread.new do
EventMachine::run { def connect
http = EM::HttpRequest.new("http://my-card.in/servers.json").get @recv = Thread.new do
http.callback { EventMachine::run {
begin http = EM::HttpRequest.new("http://my-card.in/servers.json").get
self.servers.replace JSON.parse(http.response).collect {|data| Server.new(data['id'], data['name'], data['ip'], data['port'], data['auth'])} http.callback {
self.filter[:servers] = self.servers.clone begin
rescue self.servers.replace JSON.parse(http.response).collect {|data| Server.new(data['id'], data['name'], data['ip'], data['port'], data['auth'])}
Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败', true) self.filter[:servers] = self.servers.clone
end rescue
Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败.1', true)
#EventMachine::connect "mycard-server.my-card.in", 9997, Client end
ws = WebSocket::EventMachine::Client.connect(:host => "mycard-server.my-card.in", :port => 9998);
ws.onmessage do |msg, type| #EventMachine::connect "mycard-server.my-card.in", 9997, Client
$log.info('收到websocket消息'){msg.force_encoding("UTF-8")} ws = WebSocket::EventMachine::Client.connect(:host => "mycard-server.my-card.in", :port => 9998);
Game_Event.push Game_Event::RoomsUpdate.new JSON.parse(msg).collect { |room| Game_Event.parse_room(room) } ws.onmessage do |msg, type|
end $log.info('收到websocket消息'){msg.force_encoding("UTF-8")}
ws.onclose do Game_Event.push Game_Event::RoomsUpdate.new JSON.parse(msg).collect { |room| Game_Event.parse_room(room) }
$log.info('websocket连接断开') end
Game_Event.push Game_Event::Error.new('ygocore', '网络连接中断.1', true) ws.onclose do
end $log.info('websocket连接断开')
Game_Event.push Game_Event::Error.new('ygocore', '网络连接中断.1', true)
} end
http.errback{
Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败', true) }
} http.errback{
} Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败', true)
end }
end }
end
def im_connect end
Thread.new {
begin def im_connect
@@im.allow_tls = false Thread.new {
@@im.use_ssl = true begin
@@im.connect('chat.my-card.in', 5223) #ruby19/windows下 使用tls连接时会卡住 @@im.allow_tls = false
@@im.use_ssl = true
begin
@@im.auth(@password) #由于XMPP4r在windows
rescue Jabber::ClientAuthenticationFailure srv = []
Game_Event.push Game_Event::Error.new('登录', '用户名或密码错误') Resolv::DNS.open { |dns|
Thread.exit # If ruby version is too old and SRV is unknown, this will raise a NameError
end # which is caught below
Game_Event.push Game_Event::Login.new User.new(@@im.jid, @username, true) Jabber::debuglog("RESOLVING:\n_xmpp-client._tcp.#{@@im.jid.domain} (SRV)")
@@im.send(Jabber::Presence.new.set_type(:available)) srv = dns.getresources("_xmpp-client._tcp.#{@@im.jid.domain}", Resolv::DNS::Resource::IN::SRV)
begin }
nickname = nickname() # Sort SRV records: lowest priority first, highest weight first
#@@im_room.join(Jabber::JID.new(I18n.t('lobby.room'), I18n.t('lobby.server'), nickname)) srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
@@im_room.join(Jabber::JID.new('mycard', 'conference.my-card.in', nickname))
rescue Jabber::ServerError => exception srv.each { |record|
if exception.error.error == 'conflict' begin
@nickname_conflict << nickname @@im.connect(record.target.to_s, 5223)
retry # Success
end break
end rescue SocketError, Errno::ECONNREFUSED
Game_Event.push Game_Event::AllUsers.new @@im_room.roster.keys.collect { |nick| User.new(nick.to_sym, nick) } rescue p $! # Try next SRV record
rescue StandardError => exception end
$log.error('聊天连接出错') { exception } }
Game_Event.push(Game_Event::Chat.new(ChatMessage.new(User.new(:system, 'System'), '聊天服务器连接失败')))
end begin
} @@im.auth(@password)
end rescue Jabber::ClientAuthenticationFailure
Game_Event.push Game_Event::Error.new('登录', '用户名或密码错误')
def chat(chatmessage) Thread.exit
case chatmessage.channel end
when :lobby Game_Event.push Game_Event::Login.new User.new(@@im.jid, @username, true)
msg = Jabber::Message::new(nil, chatmessage.message) @@im.send(Jabber::Presence.new.set_type(:available))
@@im_room.send msg begin
when User nickname = nickname()
msg = Jabber::Message::new(nil, chatmessage.message) #@@im_room.join(Jabber::JID.new(I18n.t('lobby.room'), I18n.t('lobby.server'), nickname))
@@im_room.send msg, chatmessage.channel.id @@im_room.join(Jabber::JID.new('mycard', 'conference.my-card.in', nickname))
#send(:chat, channel: chatmessage.channel.id, message: chatmessage.message, time: chatmessage.time) rescue Jabber::ServerError => exception
end if exception.error.error == 'conflict'
end @nickname_conflict << nickname
#def chat(chatmessage) retry
# case chatmessage.channel end
# when :lobby end
# send(:chat, channel: :lobby, message: chatmessage.message, time: chatmessage.time) Game_Event.push Game_Event::AllUsers.new @@im_room.roster.keys.collect { |nick| User.new(nick.to_sym, nick) } rescue p $!
# when User rescue StandardError => exception
# send(:chat, channel: chatmessage.channel.id, message: chatmessage.message, time: chatmessage.time) $log.error('聊天连接出错') { exception }
# end Game_Event.push(Game_Event::Chat.new(ChatMessage.new(User.new(:system, 'System'), '聊天服务器连接失败')))
#end end
}
def host(room_name, room_config) end
room = Room.new(0, room_name)
room.pvp = room_config[:pvp] def chat(chatmessage)
room.match = room_config[:match] case chatmessage.channel
room.tag = room_config[:tag] when :lobby
room.password = room_config[:password] msg = Jabber::Message::new(nil, chatmessage.message)
room.ot = room_config[:ot] @@im_room.send msg
room.lp = room_config[:lp] when User
msg = Jabber::Message::new(nil, chatmessage.message)
room.host_server @@im_room.send msg, chatmessage.channel.id
#send(:chat, channel: chatmessage.channel.id, message: chatmessage.message, time: chatmessage.time)
if $game.rooms.any? { |game_room| game_room.name == room_name } end
Widget_Msgbox.new("建立房间", "房间名已存在", :ok => "确定") end
else #def chat(chatmessage)
Game_Event.push Game_Event::Join.new(room) # case chatmessage.channel
end # when :lobby
end # send(:chat, channel: :lobby, message: chatmessage.message, time: chatmessage.time)
# when User
def watch(room) # send(:chat, channel: chatmessage.channel.id, message: chatmessage.message, time: chatmessage.time)
Widget_Msgbox.new("加入房间", "游戏已经开始", :ok => "确定") # end
end #end
def join(room) def host(room_name, room_config)
Game_Event.push Game_Event::Join.new(room) room = Room.new(0, room_name)
end room.pvp = room_config[:pvp]
room.match = room_config[:match]
def refresh room.tag = room_config[:tag]
#send(:refresh) room.password = room_config[:password]
end room.ot = room_config[:ot]
room.lp = room_config[:lp]
def send(header, data=nil)
#$log.info('发送消息') { {header: header, data: data} } room.host_server
#Client::MycardChannel.push header: header, data: data
end if $game.rooms.any? { |game_room| game_room.name == room_name }
Widget_Msgbox.new("建立房间", "房间名已存在", :ok => "确定")
def exit else
@recv.exit if @recv Game_Event.push Game_Event::Join.new(room)
@recv = nil end
end end
def ygocore_path def watch(room)
"ygocore/ygopro_vs.exe" Widget_Msgbox.new("加入房间", "游戏已经开始", :ok => "确定")
end end
def self.register def join(room)
Dialog.web @@config['register'] Game_Event.push Game_Event::Join.new(room)
end end
def server def refresh
@@config['server'] #send(:refresh)
end end
def port def send(header, data=nil)
@@config['port'] #$log.info('发送消息') { {header: header, data: data} }
end #Client::MycardChannel.push header: header, data: data
end
def server=(server)
@@config['server'] = server def exit
end @recv.exit if @recv
@recv = nil
def port=(port) end
@@config['port'] = port
end def ygocore_path
"ygocore/ygopro_vs.exe"
def self.run_ygocore(option, image_downloading=false) end
if !image_downloading and !Update.images.empty?
return Widget_Msgbox.new("加入房间", "卡图正在下载中,可能显示不出部分卡图", :ok => "确定") { run_ygocore(option, true) } def self.register
end Dialog.web @@config['register']
path = 'ygocore/ygopro_vs.exe' end
Widget_Msgbox.new("ygocore", "正在启动ygocore") rescue nil
#写入配置文件并运行ygocore def server
Dir.chdir(File.dirname(path)) do @@config['server']
case option end
when Room
room = option def port
room_name = if room.ot != 0 or room.lp != 8000 @@config['port']
mode = case when room.match? then end
1; when room.tag? then
2 def server=(server)
else @@config['server'] = server
0 end
end
room_name = "#{room.ot}#{mode}FFF#{room.lp},5,1,#{room.name}" def port=(port)
elsif room.tag? @@config['port'] = port
"T#" + room.name end
elsif room.pvp? and room.match?
"PM#" + room.name def self.run_ygocore(option, image_downloading=false)
elsif room.pvp? if !image_downloading and !Update.images.empty?
"P#" + room.name return Widget_Msgbox.new("加入房间", "卡图正在下载中,可能显示不出部分卡图", :ok => "确定") { run_ygocore(option, true) }
elsif room.match? end
"M#" + room.name path = 'ygocore/ygopro_vs.exe'
else Widget_Msgbox.new("ygocore", "正在启动ygocore") rescue nil
room.name #写入配置文件并运行ygocore
end Dir.chdir(File.dirname(path)) do
if room.password and !room.password.empty? case option
room_name += "$" + room.password when Room
end room = option
system_conf = {} room_name = if room.ot != 0 or room.lp != 8000
begin mode = case when room.match? then
IO.readlines('system.conf').each do |line| 1; when room.tag? then
line.force_encoding "UTF-8" 2
next if line[0, 1] == '#' else
field, contents = line.chomp.split(' = ', 2) 0
system_conf[field] = contents end
end room_name = "#{room.ot}#{mode}FFF#{room.lp},5,1,#{room.name}"
rescue elsif room.tag?
system_conf['antialias'] = 2 "T#" + room.name
system_conf['textfont'] = 'c:/windows/fonts/simsun.ttc 14' elsif room.pvp? and room.match?
system_conf['numfont'] = 'c:/windows/fonts/arialbd.ttf' "PM#" + room.name
end elsif room.pvp?
system_conf['nickname'] = $game.user.name "P#" + room.name
system_conf['nickname'] += '$' + $game.password if $game.password and !$game.password.empty? and room.server.auth elsif room.match?
$log.info room "M#" + room.name
system_conf['lastip'] = room.server.ip else
system_conf['lastport'] = room.server.port.to_s room.name
system_conf['roompass'] = room_name end
open('system.conf', 'w') { |file| file.write system_conf.collect { |key, value| "#{key} = #{value}" }.join("\n") } if room.password and !room.password.empty?
args = '-j' room_name += "$" + room.password
when :replay end
args = '-r' system_conf = {}
when :deck begin
args = '-d' IO.readlines('system.conf').each do |line|
when String line.force_encoding "UTF-8"
system_conf = {} next if line[0, 1] == '#'
begin field, contents = line.chomp.split(' = ', 2)
IO.readlines('system.conf').each do |line| system_conf[field] = contents
line.force_encoding "UTF-8" end
next if line[0, 1] == '#' rescue
field, contents = line.chomp.split(' = ', 2) system_conf['antialias'] = 2
system_conf[field] = contents system_conf['textfont'] = 'c:/windows/fonts/simsun.ttc 14'
end system_conf['numfont'] = 'c:/windows/fonts/arialbd.ttf'
rescue end
system_conf['antialias'] = 2 system_conf['nickname'] = $game.user.name
system_conf['textfont'] = 'c:/windows/fonts/simsun.ttc 14' system_conf['nickname'] += '$' + $game.password if $game.password and !$game.password.empty? and room.server.auth
system_conf['numfont'] = 'c:/windows/fonts/arialbd.ttf' $log.info room
end system_conf['lastip'] = room.server.ip
system_conf['lastdeck'] = option system_conf['lastport'] = room.server.port.to_s
open('system.conf', 'w') { |file| file.write system_conf.collect { |key, value| "#{key} = #{value}" }.join("\n") } system_conf['roompass'] = room_name
args = '-d' open('system.conf', 'w') { |file| file.write system_conf.collect { |key, value| "#{key} = #{value}" }.join("\n") }
end args = '-j'
IO.popen("ygopro_vs.exe #{args}") when :replay
WM.iconify rescue nil args = '-r'
end when :deck
Widget_Msgbox.destroy rescue nil args = '-d'
end when String
system_conf = {}
def self.replay(file, skip_image_downloading = false) begin
require 'fileutils' IO.readlines('system.conf').each do |line|
FileUtils.mv Dir.glob('ygocore/replay/*.yrp'), 'replay/' line.force_encoding "UTF-8"
FileUtils.copy_file(file, "ygocore/replay/#{File.basename(file)}") next if line[0, 1] == '#'
run_ygocore(:replay, skip_image_downloading) field, contents = line.chomp.split(' = ', 2)
end system_conf[field] = contents
end
private rescue
system_conf['antialias'] = 2
def self.get_announcements system_conf['textfont'] = 'c:/windows/fonts/simsun.ttc 14'
#公告 system_conf['numfont'] = 'c:/windows/fonts/arialbd.ttf'
$config['ygocore'] ||= {} end
$config['ygocore']['announcements'] ||= [Announcement.new("开放注册", nil, nil)] system_conf['lastdeck'] = option
#Thread.new do open('system.conf', 'w') { |file| file.write system_conf.collect { |key, value| "#{key} = #{value}" }.join("\n") }
# begin args = '-d'
# open(@@config['api']) do |file| end
# file.set_encoding "GBK" IO.popen("ygopro_vs.exe #{args}")
# announcements = [] WM.iconify rescue nil
# file.read.encode("UTF-8").scan(/<div style="color:red" >公告:(.*?)<\/div>/).each do |title, others| end
# announcements << Announcement.new(title, @@config['index'], nil) Widget_Msgbox.destroy rescue nil
# end end
# $config['ygocore']['announcements'].replace announcements
# Config.save def self.replay(file, skip_image_downloading = false)
# end require 'fileutils'
# rescue Exception => exception FileUtils.mv Dir.glob('ygocore/replay/*.yrp'), 'replay/'
# $log.error('公告读取失败') { [exception.inspect, *exception.backtrace].collect { |str| str.encode("UTF-8") }.join("\n") } FileUtils.copy_file(file, "ygocore/replay/#{File.basename(file)}")
# end run_ygocore(:replay, skip_image_downloading)
#end end
end
private
#module Client
# MycardChannel = EM::Channel.new def self.get_announcements
# include EM::P::ObjectProtocol #公告
# $config['ygocore'] ||= {}
# def post_init $config['ygocore']['announcements'] ||= [Announcement.new("开放注册", nil, nil)]
# send_object header: :login, data: {name: $game.username, password: $game.password} #Thread.new do
# MycardChannel.subscribe { |msg| send_object(msg) } # begin
# end # open(@@config['api']) do |file|
# # file.set_encoding "GBK"
# def receive_object obj # announcements = []
# $log.info('收到消息') { obj.inspect } # file.read.encode("UTF-8").scan(/<div style="color:red" >公告:(.*?)<\/div>/).each do |title, others|
# Game_Event.push Game_Event.parse obj[:header], obj[:data] # announcements << Announcement.new(title, @@config['index'], nil)
# end # end
# # $config['ygocore']['announcements'].replace announcements
# def unbind # Config.save
# Game_Event.push Game_Event::Error.new('ygocore', '网络连接中断', true) # end
# end # rescue Exception => exception
#end # $log.error('公告读取失败') { [exception.inspect, *exception.backtrace].collect { |str| str.encode("UTF-8") }.join("\n") }
get_announcements # end
end #end
end
# websocket, due to the author hasn't release separate gem yet #module Client
#https://github.com/imanel/websocket-ruby/issues/12 # MycardChannel = EM::Channel.new
# include EM::P::ObjectProtocol
module WebSocket #
module EventMachine # def post_init
class Base < ::EventMachine::Connection # send_object header: :login, data: {name: $game.username, password: $game.password}
# MycardChannel.subscribe { |msg| send_object(msg) }
########### # end
### API ### #
########### # def receive_object obj
# $log.info('收到消息') { obj.inspect }
def onopen(&blk) # Game_Event.push Game_Event.parse obj[:header], obj[:data]
; @onopen = blk; # end
end #
# def unbind
# Called when connection is opened # Game_Event.push Game_Event::Error.new('ygocore', '网络连接中断', true)
def onclose(&blk) # end
; @onclose = blk; #end
end get_announcements
end
# Called when connection is closed
def onerror(&blk)
; @onerror = blk; # websocket, due to the author hasn't release separate gem yet
end #https://github.com/imanel/websocket-ruby/issues/12
# Called when error occurs module WebSocket
def onmessage(&blk) module EventMachine
; @onmessage = blk; class Base < ::EventMachine::Connection
end
###########
# Called when message is received from server ### API ###
def onping(&blk) ###########
; @onping = blk;
end def onopen(&blk)
; @onopen = blk;
# Called when ping message is received from server end
def onpong(&blk)
; @onpong = blk; # Called when connection is opened
end def onclose(&blk)
; @onclose = blk;
# Called when pond message is received from server end
# Send data to client # Called when connection is closed
# @param data [String] Data to send def onerror(&blk)
# @param args [Hash] Arguments for send ; @onerror = blk;
# @option args [String] :type Type of frame to send - available types are "text", "binary", "ping", "pong" and "close" end
# @return [Boolean] true if data was send, otherwise call on_error if needed
def send(data, args = {}) # Called when error occurs
type = args[:type] || :text def onmessage(&blk)
unless type == :plain ; @onmessage = blk;
frame = outgoing_frame.new(:version => @handshake.version, :data => data, :type => type) end
if !frame.supported?
trigger_onerror("Frame type '#{type}' is not supported in protocol version #{@handshake.version}") # Called when message is received from server
return false def onping(&blk)
elsif !frame.require_sending? ; @onping = blk;
return false end
end
data = frame.to_s # Called when ping message is received from server
end def onpong(&blk)
# debug "Sending raw: ", data ; @onpong = blk;
send_data(data) end
true
end # Called when pond message is received from server
# Close connection # Send data to client
# @return [Boolean] true if connection is closed immediately, false if waiting for server to close connection # @param data [String] Data to send
def close # @param args [Hash] Arguments for send
if @state == :open # @option args [String] :type Type of frame to send - available types are "text", "binary", "ping", "pong" and "close"
@state = :closing # @return [Boolean] true if data was send, otherwise call on_error if needed
return false if send('', :type => :close) def send(data, args = {})
else type = args[:type] || :text
send('', :type => :close) if @state == :closing unless type == :plain
@state = :closed frame = outgoing_frame.new(:version => @handshake.version, :data => data, :type => type)
end if !frame.supported?
close_connection_after_writing trigger_onerror("Frame type '#{type}' is not supported in protocol version #{@handshake.version}")
true return false
end elsif !frame.require_sending?
return false
# Send ping message to client end
# @return [Boolean] false if protocol version is not supporting ping requests data = frame.to_s
def ping(data = '') end
send(data, :type => :ping) # debug "Sending raw: ", data
end send_data(data)
true
# Send pong message to client end
# @return [Boolean] false if protocol version is not supporting pong requests
def pong(data = '') # Close connection
send(data, :type => :pong) # @return [Boolean] true if connection is closed immediately, false if waiting for server to close connection
end def close
if @state == :open
############################ @state = :closing
### EventMachine methods ### return false if send('', :type => :close)
############################ else
send('', :type => :close) if @state == :closing
def receive_data(data) @state = :closed
# debug "Received raw: ", data end
case @state close_connection_after_writing
when :connecting then true
handle_connecting(data) end
when :open then
handle_open(data) # Send ping message to client
when :closing then # @return [Boolean] false if protocol version is not supporting ping requests
handle_closing(data) def ping(data = '')
end send(data, :type => :ping)
end end
def unbind # Send pong message to client
unless @state == :closed # @return [Boolean] false if protocol version is not supporting pong requests
@state = :closed def pong(data = '')
close send(data, :type => :pong)
trigger_onclose('') end
end
end ############################
### EventMachine methods ###
####################### ############################
### Private methods ###
####################### def receive_data(data)
# debug "Received raw: ", data
private case @state
when :connecting then
['onopen'].each do |m| handle_connecting(data)
define_method "trigger_#{m}" do when :open then
callback = instance_variable_get("@#{m}") handle_open(data)
callback.call if callback when :closing then
end handle_closing(data)
end end
end
['onerror', 'onping', 'onpong', 'onclose'].each do |m|
define_method "trigger_#{m}" do |data| def unbind
callback = instance_variable_get("@#{m}") unless @state == :closed
callback.call(data) if callback @state = :closed
end close
end trigger_onclose('')
end
def trigger_onmessage(data, type) end
@onmessage.call(data, type) if @onmessage
end #######################
### Private methods ###
def handle_connecting(data) #######################
@handshake << data
return unless @handshake.finished? private
if @handshake.valid?
send(@handshake.to_s, :type => :plain) if @handshake.should_respond? ['onopen'].each do |m|
@frame = incoming_frame.new(:version => @handshake.version) define_method "trigger_#{m}" do
@state = :open callback = instance_variable_get("@#{m}")
trigger_onopen callback.call if callback
handle_open(@handshake.leftovers) if @handshake.leftovers end
else end
trigger_onerror(@handshake.error)
close ['onerror', 'onping', 'onpong', 'onclose'].each do |m|
end define_method "trigger_#{m}" do |data|
end callback = instance_variable_get("@#{m}")
callback.call(data) if callback
def handle_open(data) end
@frame << data end
while frame = @frame.next
case frame.type def trigger_onmessage(data, type)
when :close @onmessage.call(data, type) if @onmessage
@state = :closing end
close
trigger_onclose(frame.to_s) def handle_connecting(data)
when :ping @handshake << data
pong(frame.to_s) return unless @handshake.finished?
trigger_onping(frame.to_s) if @handshake.valid?
when :pong send(@handshake.to_s, :type => :plain) if @handshake.should_respond?
trigger_onpong(frame.to_s) @frame = incoming_frame.new(:version => @handshake.version)
when :text @state = :open
trigger_onmessage(frame.to_s, :text) trigger_onopen
when :binary handle_open(@handshake.leftovers) if @handshake.leftovers
trigger_onmessage(frame.to_s, :binary) else
end trigger_onerror(@handshake.error)
end close
unbind if @frame.error? end
end end
def handle_closing(data) def handle_open(data)
@state = :closed @frame << data
close while frame = @frame.next
trigger_onclose case frame.type
end when :close
@state = :closing
def debug(description, data) close
puts(description + data.bytes.to_a.collect { |b| '\x' + b.to_s(16).rjust(2, '0') }.join) unless @state == :connecting trigger_onclose(frame.to_s)
end when :ping
pong(frame.to_s)
end trigger_onping(frame.to_s)
end when :pong
end trigger_onpong(frame.to_s)
# Example WebSocket Client (using EventMachine) when :text
# @example trigger_onmessage(frame.to_s, :text)
# ws = WebSocket::EventMachine::Client.connect(:host => "0.0.0.0", :port => 8080) when :binary
# ws.onmessage { |msg| ws.send "Pong: #{msg}" } trigger_onmessage(frame.to_s, :binary)
# ws.send "data" end
module WebSocket end
module EventMachine unbind if @frame.error?
class Client < Base end
# Connect to websocket server def handle_closing(data)
# @param args [Hash] The request arguments @state = :closed
# @option args [String] :host The host IP/DNS name close
# @option args [Integer] :port The port to connect too(default = 80) trigger_onclose
# @option args [Integer] :version Version of protocol to use(default = 13) end
def self.connect(args = {})
host = nil def debug(description, data)
port = nil puts(description + data.bytes.to_a.collect { |b| '\x' + b.to_s(16).rjust(2, '0') }.join) unless @state == :connecting
if args[:uri] end
uri = URI.parse(args[:uri])
host = uri.host end
port = uri.port end
end end
host = args[:host] if args[:host] # Example WebSocket Client (using EventMachine)
port = args[:port] if args[:port] # @example
port ||= 80 # ws = WebSocket::EventMachine::Client.connect(:host => "0.0.0.0", :port => 8080)
# ws.onmessage { |msg| ws.send "Pong: #{msg}" }
::EventMachine.connect host, port, self, args # ws.send "data"
end module WebSocket
module EventMachine
# Initialize connection class Client < Base
# @param args [Hash] Arguments for connection
# @option args [String] :host The host IP/DNS name # Connect to websocket server
# @option args [Integer] :port The port to connect too(default = 80) # @param args [Hash] The request arguments
# @option args [Integer] :version Version of protocol to use(default = 13) # @option args [String] :host The host IP/DNS name
def initialize(args) # @option args [Integer] :port The port to connect too(default = 80)
@args = args # @option args [Integer] :version Version of protocol to use(default = 13)
end def self.connect(args = {})
host = nil
############################ port = nil
### EventMachine methods ### if args[:uri]
############################ uri = URI.parse(args[:uri])
host = uri.host
# Called after initialize of connection, but before connecting to server port = uri.port
def post_init end
@state = :connecting host = args[:host] if args[:host]
@handshake = WebSocket::Handshake::Client.new(@args) port = args[:port] if args[:port]
end port ||= 80
# Called by EventMachine after connecting. ::EventMachine.connect host, port, self, args
# Sends handshake to server end
def connection_completed
send(@handshake.to_s, :type => :plain) # Initialize connection
end # @param args [Hash] Arguments for connection
# @option args [String] :host The host IP/DNS name
private # @option args [Integer] :port The port to connect too(default = 80)
# @option args [Integer] :version Version of protocol to use(default = 13)
def incoming_frame def initialize(args)
WebSocket::Frame::Incoming::Client @args = args
end end
def outgoing_frame ############################
WebSocket::Frame::Outgoing::Client ### EventMachine methods ###
end ############################
end # Called after initialize of connection, but before connecting to server
end def post_init
end @state = :connecting
@handshake = WebSocket::Handshake::Client.new(@args)
end
# Called by EventMachine after connecting.
# Sends handshake to server
def connection_completed
send(@handshake.to_s, :type => :plain)
end
private
def incoming_frame
WebSocket::Frame::Incoming::Client
end
def outgoing_frame
WebSocket::Frame::Outgoing::Client
end
end
end
end
class Room class Room
attr_accessor :pvp attr_accessor :pvp
attr_accessor :match attr_accessor :match
attr_accessor :tag attr_accessor :tag
attr_accessor :ot attr_accessor :ot
attr_accessor :lp attr_accessor :lp
attr_accessor :status attr_accessor :status
attr_accessor :server attr_accessor :server
alias pvp? pvp alias pvp? pvp
alias match? match alias match? match
alias tag? tag alias tag? tag
def lp def lp
@lp ||= 8000 @lp ||= 8000
end end
def ot def ot
@ot ||= 0 @ot ||= 0
end end
def full? def full?
$game.is_a?(Ygocore) ? (@status == :start) : player2 #不规范修正iduel房间识别问题 $game.is_a?(Ygocore) ? (@status == :start) : player2 #不规范修正iduel房间识别问题
end end
def extra def extra
result = {} result = {}
if pvp? if pvp?
result["[竞技场]"] = [255,0,0] result["[竞技场]"] = [255,0,0]
end end
if tag? if tag?
result["[TAG双打]"] = [128,0,255] result["[TAG双打]"] = [128,0,255]
elsif match? elsif match?
result["[三回决斗]"] = [0xff,0x72,0] result["[三回决斗]"] = [0xff,0x72,0]
end end
if ot == 1 if ot == 1
result["[TCG]"] = [255,0,0] result["[TCG]"] = [255,0,0]
elsif ot == 2 elsif ot == 2
result["[O/T混]"] = [255,0,0] result["[O/T混]"] = [255,0,0]
end end
if lp != 8000 if lp != 8000
result["[LP: #{lp}]"] = [255,0,0] result["[LP: #{lp}]"] = [255,0,0]
end end
result result
end end
def host_server def host_server
servers = $game.servers servers = $game.servers
servers.select!{|server|server.auth} if @pvp servers.select!{|server|server.auth} if @pvp
s = servers & $game.filter[:servers] s = servers & $game.filter[:servers]
servers = s if !s.empty? servers = s if !s.empty?
server = servers.min_by{|server|$game.rooms.select{|room|room.server == server}.size} server = servers.min_by{|server|$game.rooms.select{|room|room.server == server}.size}
p server p server
server ||= Server.new(nil, "", $game.server, $game.port, true) server ||= Server.new(nil, "", $game.server, $game.port, true)
self.server = server self.server = server
server server
end end
end end
ja: ja:
name: "日本語" name: "日本語"
\ No newline at end of file
zh-OS: zh-OS:
name: "中文(OcgSoft)" name: "中文(OcgSoft)"
\ No newline at end of file
zh-TW: zh-TW:
name: "中文(繁体)" name: "中文(繁体)"
\ No newline at end of file
en: en:
lang: "中文" lang: "中文"
chat: chat:
room: "lobby.zh" room: "lobby.zh"
server: "conference.my-card.in" server: "conference.my-card.in"
login: login:
name: "用户名" name: "用户名"
password: "密码" password: "密码"
login: "登录" login: "登录"
register: "注册" register: "注册"
remember: "记住密码" remember: "记住密码"
replay: "录像" replay: "录像"
lobby: lobby:
faq: "常见问题" faq: "常见问题"
editdeck: "卡组编辑" editdeck: "卡组编辑"
newroom: "建立房间" newroom: "建立房间"
lobby: "大厅" lobby: "大厅"
filter: "房间筛选" filter: "房间筛选"
waiting_only: "仅等待中" waiting_only: "仅等待中"
normal_only: "仅标准房" normal_only: "仅标准房"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment