Commit 59421bd9 authored by 神楽坂玲奈's avatar 神楽坂玲奈

stable

parent ef1b2058
_ = require 'underscore'
_.str = require 'underscore.string'
_.mixin(_.str.exports());
spawn = require('child_process').spawn
ygopro = require './ygopro.js'
class Room
#name
#port
#players: [client]
#process
#established
#alive
@all = []
@find_or_create_by_name: (name)->
result = @find_by_name(name) ? new Room(name)
@find_by_name: (name)->
_.find @all, (room)->
room.name == name
@find_by_port: (port)->
_.find @all, (room)->
room.port == port
constructor: (name) ->
@name = name
@alive = true
@players = []
@status = 'starting'
Room.all.push this
if name[0...2] == 'M#'
param = [0, 0, 0, 1, 'F', 'F', 'F', 8000, 5, 1]
else if name[0...2] == 'T#'
param = [0, 0, 0, 2, 'F', 'F', 'F', 8000, 5, 1]
else if (param = name.match /^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i)
param.shift()
param.unshift(0, 0)
else
param = [0, 0, 0, 0, 'F', 'F', 'F', 8000, 5, 1]
@process = spawn './ygopro', param, cwd: 'ygocore'
@process.on 'exit', (code)=>
console.log "room process #{@port} exited with code #{code}"
this.delete()
@process.stdout.setEncoding('utf8')
@process.stdout.once 'data', (data)=>
@established = true
@port = parseInt data
#setTimeout =>
_.each @players, (player)=>
player.server.connect @port, '127.0.0.1',=>
player.server.write buffer for buffer in player.pre_establish_buffers
player.established = true
delete: (room)->
Room.all.splice(_.indexOf(Room.all, room), 1)
toString: ->
"room: #{@name} #{@port} #{@alive ? 'alive' : 'not-alive'} #{@dueling ? 'dueling' : 'not-dueling'} [#{("client #{typeof player.client} server #{typeof player.server} #{player.name} #{player.pos}. " for player in @players)}] #{JSON.stringify @pos_name}"
connect: (client)->
@players.push client
if @established
client.server.connect @port, '127.0.0.1', ->
client.server.write buffer for buffer in client.pre_establish_buffers
client.established = true
disconnect: (client, error)->
@players = _.reject @players, (player)->
player is client
for player in @players
ygopro.stoc_send_chat(player, "#{client.name} 离开了游戏#{if error then ": #{error}" else ''}")
module.exports = Room
\ No newline at end of file
// Generated by CoffeeScript 1.6.3
(function() {
var Room, spawn, ygopro, _;
_ = require('underscore');
_.str = require('underscore.string');
_.mixin(_.str.exports());
spawn = require('child_process').spawn;
ygopro = require('./ygopro.js');
Room = (function() {
Room.all = [];
Room.find_or_create_by_name = function(name) {
var result, _ref;
return result = (_ref = this.find_by_name(name)) != null ? _ref : new Room(name);
};
Room.find_by_name = function(name) {
return _.find(this.all, function(room) {
return room.name === name;
});
};
Room.find_by_port = function(port) {
return _.find(this.all, function(room) {
return room.port === port;
});
};
function Room(name) {
var param,
_this = this;
this.name = name;
this.alive = true;
this.players = [];
this.status = 'starting';
Room.all.push(this);
if (name.slice(0, 2) === 'M#') {
param = [0, 0, 0, 1, 'F', 'F', 'F', 8000, 5, 1];
} else if (name.slice(0, 2) === 'T#') {
param = [0, 0, 0, 2, 'F', 'F', 'F', 8000, 5, 1];
} else if ((param = name.match(/^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
param.shift();
param.unshift(0, 0);
} else {
param = [0, 0, 0, 0, 'F', 'F', 'F', 8000, 5, 1];
}
this.process = spawn('./ygopro', param, {
cwd: 'ygocore'
});
this.process.on('exit', function(code) {
console.log("room process " + _this.port + " exited with code " + code);
return _this["delete"]();
});
this.process.stdout.setEncoding('utf8');
this.process.stdout.once('data', function(data) {
_this.established = true;
_this.port = parseInt(data);
return _.each(_this.players, function(player) {
return player.server.connect(_this.port, '127.0.0.1', function() {
var buffer, _i, _len, _ref;
_ref = player.pre_establish_buffers;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
buffer = _ref[_i];
player.server.write(buffer);
}
return player.established = true;
});
});
});
}
Room.prototype["delete"] = function(room) {
return Room.all.splice(_.indexOf(Room.all, room), 1);
};
Room.prototype.toString = function() {
var player, _ref, _ref1;
return "room: " + this.name + " " + this.port + " " + ((_ref = this.alive) != null ? _ref : {
'alive': 'not-alive'
}) + " " + ((_ref1 = this.dueling) != null ? _ref1 : {
'dueling': 'not-dueling'
}) + " [" + ((function() {
var _i, _len, _ref2, _results;
_ref2 = this.players;
_results = [];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
player = _ref2[_i];
_results.push("client " + (typeof player.client) + " server " + (typeof player.server) + " " + player.name + " " + player.pos + ". ");
}
return _results;
}).call(this)) + "] " + (JSON.stringify(this.pos_name));
};
Room.prototype.connect = function(client) {
this.players.push(client);
if (this.established) {
return client.server.connect(this.port, '127.0.0.1', function() {
var buffer, _i, _len, _ref;
_ref = client.pre_establish_buffers;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
buffer = _ref[_i];
client.server.write(buffer);
}
return client.established = true;
});
}
};
Room.prototype.disconnect = function(client, error) {
var player, _i, _len, _ref, _results;
this.players = _.reject(this.players, function(player) {
return player === client;
});
_ref = this.players;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
player = _ref[_i];
_results.push(ygopro.stoc_send_chat(player, "" + client.name + " 离开了游戏" + (error ? ": " + error : '')));
}
return _results;
};
return Room;
})();
module.exports = Room;
}).call(this);
/*
//@ sourceMappingURL=room.map
*/
{
"version": 3,
"file": "room.js",
"sourceRoot": "",
"sources": [
"room.coffee"
],
"names": [],
"mappings": "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"
}
\ No newline at end of file
#官方库
#标准库
net = require 'net'
http = require 'http'
url = require 'url'
path = require 'path'
fs = require 'fs'
spawn = require('child_process').spawn
#三方库
freeport = require 'freeport'
Struct = require('struct').Struct
_ = require 'underscore'
_.str = require 'underscore.string'
_.mixin(_.str.exports());
_.str.include('Underscore.string', 'string');
Inotify = require('inotify').Inotify
request = require 'request'
#常量/类型声明
structs_declaration = require './structs.json' #结构体声明
typedefs = require './typedefs.json' #类型声明
proto_structs = require './proto_structs.json' #消息与结构体的对应,未完成,对着duelclient.cpp加
constants = require './constants.json' #network.h里定义的常量
#组件
ygopro = require './ygopro.js'
Room = require './room.js'
#配置文件
settings = require './config.json' #本机IP端口设置
class Room
@all = []
#name
#port
#players: [{client, server, name, pos}]
#process
#established
#alive
constructor: (name, port, client) ->
@name = name
@port = port
@alive = true
@players = []
@dueling = false
@established = false
@pos_name = {}#重构
@add_client(client)
Room.all.push this #这个故事告诉我们没事不要乱new Room
delete: (room)->
Room.all.splice(_.indexOf(Room.all, room), 1)
add_client: (client)->
@players.push {client: client, name: client.player}
remove_client: (client, error)->
@players = _.reject @players, (player)->
player.client is client
for player in @players
stoc_send_chat(player.client, "#{client.player} 离开了游戏#{if error then ": #{error}" else ''}")
toString: ->
"room: #{@name} #{@port} #{@alive ? 'alive' : 'not-alive'} #{@dueling ? 'dueling' : 'not-dueling'} [#{("client #{typeof player.client} server #{typeof player.server} #{player.name} #{player.pos}. " for player in @players)}] #{JSON.stringify @pos_name}"
#需要性能优化,建立个索引
@find_by_name: (name)->
_.find @all, (room)->
room.name == name
@find_by_port: (port)->
_.find @all, (room)->
room.name == port
@find_by_client: (client)->
_.find @all, (room)->
_.some room.players, (player)->
player.client == client
@find_by_server: (server)->
_.find @all, (room)->
_.some room.players, (player)->
player.server == server
#debug模式 端口号+1
debug = false
if process.argv[2] == '--debug'
settings.port++
settings.http_port++
#结构体定义
structs = {}
for name, declaration of structs_declaration
result = Struct()
for field in declaration
if field.encoding
switch field.encoding
when "UTF-16LE" then result.chars field.name, field.length*2, field.encoding
else throw "unsupported encoding: #{file.encoding}"
else
type = field.type
type = typedefs[type] if typedefs[type]
if field.length
result.array field.name, field.length, type #不支持结构体
else
if structs[type]
result.struct field.name, structs[type]
else
result[type] field.name
structs[name] = result
#消息跟踪函数 需要重构, 另暂时只支持异步, 同步没做.
stoc_follows = {}
ctos_follows = {}
stoc_follow = (proto, synchronous, callback)->
if typeof proto == 'string'
for key, value of constants.STOC
if value == proto
proto = key
break
throw "unknown proto" if !constants.STOC[proto]
stoc_follows[proto] = {callback: callback, synchronous: synchronous}
ctos_follow = (proto, synchronous, callback)->
if typeof proto == 'string'
for key, value of constants.CTOS
if value == proto
proto = key
break
throw "unknown proto" if !constants.CTOS[proto]
ctos_follows[proto] = {callback: callback, synchronous: synchronous}
#消息发送函数,至少要把俩合起来....
stoc_send = (socket, proto, info)->
#console.log proto, proto_structs.STOC[proto], structs[proto_structs.STOC[proto]]
if typeof info == 'undefined'
buffer = ""
else if Buffer.isBuffer(info)
buffer = info
else
struct = structs[proto_structs.STOC[proto]]
struct.allocate()
struct.set info
buffer = struct.buffer()
if typeof proto == 'string' #需要重构
for key, value of constants.STOC
if value == proto
proto = key
break
throw "unknown proto" if !constants.STOC[proto]
header = new Buffer(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
ctos_send = (socket, proto, info)->
#console.log proto, proto_structs.CTOS[proto], structs[proto_structs.CTOS[proto]]
if typeof info == 'undefined'
buffer = ""
else if Buffer.isBuffer(info)
buffer = info
else
struct = structs[proto_structs.CTOS[proto]]
struct.allocate()
struct.set info
buffer = struct.buffer()
if typeof proto == 'string' #需要重构
for key, value of constants.CTOS
if value == proto
proto = key
break
throw "unknown proto" if !constants.CTOS[proto]
header = new Buffer(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
#util
stoc_send_chat = (client, msg, player = 8)->
stoc_send client, 'CHAT', {
player: player
msg: msg
}
#服务器端消息监听函数
server_listener = (port, client, server)->
client.connected = true
console.log "connected #{port}"
stoc_buffer = new Buffer(0)
stoc_message_length = 0
stoc_proto = 0
for buffer in client.pre_connecion_buffers
server.write buffer
server.on "data", (data) ->
stoc_buffer = Buffer.concat([stoc_buffer, data], stoc_buffer.length + data.length)
#buffer的错误使用方式,好孩子不要学
while true
if stoc_message_length == 0
if stoc_buffer.length >= 2
stoc_message_length = stoc_buffer.readUInt16LE(0)
else
break
else if stoc_proto == 0
if stoc_buffer.length >= 3
stoc_proto = stoc_buffer.readUInt8(2)
else
break
else
if stoc_buffer.length >= 2 + stoc_message_length
if stoc_follows[stoc_proto]
b = stoc_buffer.slice(3, stoc_message_length - 1 + 3)
if struct = structs[proto_structs.STOC[constants.STOC[stoc_proto]]]
struct._setBuff(b)
setImmediate stoc_follows[stoc_proto].callback, b, struct.fields, client, server
else
setImmediate stoc_follows[stoc_proto].callback, b, null, client, server
stoc_buffer = stoc_buffer.slice(2 + stoc_message_length)
stoc_message_length = 0
stoc_proto = 0
else
break
#网络连接
net.createServer (client) ->
server = new net.Socket()
client.server = server
unless stoc_follows[stoc_proto] and stoc_follows[stoc_proto].synchronous
client.write data
#释放处理
client.on 'close', (had_error) ->
console.log "client closed #{had_error}"
unless client.closed
client.room.disconnect(client) if client.room
client.closed = true
server.end()
server.on "error", (e) ->
console.log "server error #{e}"
client.end()
client.on 'error', (error)->
console.log "client error #{error}"
unless client.closed
client.room.disconnect(client, error) if client.room
client.closed = error
server.end()
server.on "close", (had_error) ->
server.on 'close', (had_error) ->
console.log "server closed #{had_error}"
server.closed = true unless server.closed
unless client.closed
ygopro.stoc_send_chat(client, "服务器关闭了连接")
client.closed = true
client.end()
server.on 'error', (error)->
console.log "server error #{error}"
server.closed = error
unless client.closed
ygopro.stoc_send_chat(client, "服务器错误: #{error}")
client.closed = true
client.end()
#main
listener = net.createServer (client) ->
client.connected = false
#需要重构
#客户端到服务端(ctos)协议分析
ctos_buffer = new Buffer(0)
ctos_message_length = 0
ctos_proto = 0
client.pre_connecion_buffers = new Array()
server = new net.Socket()
server.on "error", (e) ->
stoc_send_chat(client, "服务器错误")
console.log "server error #{e}"
client.pre_establish_buffers = new Array()
client.on "data", (data) ->
client.on 'data', (data) ->
ctos_buffer = Buffer.concat([ctos_buffer, data], ctos_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
#console.log data
while true
if ctos_message_length == 0
if ctos_buffer.length >= 2
......@@ -274,13 +86,13 @@ listener = net.createServer (client) ->
break
else
if ctos_buffer.length >= 2 + ctos_message_length
if ctos_follows[ctos_proto]
if ygopro.ctos_follows[ctos_proto]
b = ctos_buffer.slice(3, ctos_message_length-1+3)
if struct = structs[proto_structs.CTOS[constants.CTOS[ctos_proto]]]
if struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]
struct._setBuff(b)
setTimeout ctos_follows[ctos_proto].callback, 0, b, struct.fields, client, server
setTimeout ygopro.ctos_follows[ctos_proto].callback, 0, b, _.clone(struct.fields), client, server
else
setTimeout ctos_follows[ctos_proto].callback, 0, b, null, client, server
setTimeout ygopro.ctos_follows[ctos_proto].callback, 0, b, null, client, server
ctos_buffer = ctos_buffer.slice(2 + ctos_message_length)
ctos_message_length = 0
......@@ -288,117 +100,97 @@ listener = net.createServer (client) ->
else
break
unless ctos_follows[ctos_proto] and ctos_follows[ctos_proto].synchronous
if client.connected
unless ygopro.ctos_follows[ctos_proto] and ygopro.ctos_follows[ctos_proto].synchronous
if client.established
server.write data
else
client.pre_connecion_buffers.push data
client.pre_establish_buffers.push data
client.on "error", (e) ->
room = Room.find_by_client(client)
room.remove_client(client, e) if room
#服务端到客户端(stoc)
stoc_buffer = new Buffer(0)
stoc_message_length = 0
stoc_proto = 0
console.log "client error #{e}"
server.end()
server.on 'data', (data)->
stoc_buffer = Buffer.concat([stoc_buffer, data], stoc_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
client.on "close", (had_error) ->
console.log "client closed #{had_error}"
return if had_error
while true
if stoc_message_length == 0
if stoc_buffer.length >= 2
stoc_message_length = stoc_buffer.readUInt16LE(0)
else
break
else if stoc_proto == 0
if stoc_buffer.length >= 3
stoc_proto = stoc_buffer.readUInt8(2)
else
break
else
if stoc_buffer.length >= 2 + stoc_message_length
if ygopro.stoc_follows[stoc_proto]
b = stoc_buffer.slice(3, stoc_message_length - 1 + 3)
if struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]
struct._setBuff(b)
setImmediate ygopro.stoc_follows[stoc_proto].callback, b, _.clone(struct.fields), client, server
else
setImmediate ygopro.stoc_follows[stoc_proto].callback, b, null, client, server
room = Room.find_by_client(client)
room.remove_client(client) if room
server.end()
stoc_buffer = stoc_buffer.slice(2 + stoc_message_length)
stoc_message_length = 0
stoc_proto = 0
else
break
.listen settings.port, null, null, ->
#unless ygopro.stoc_follows[stoc_proto] and ygopro.stoc_follows[stoc_proto].synchronous
client.write data
.listen settings.port, ->
console.log "server started on #{settings.ip}:#{settings.port}"
ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server)->
client.player = info.name
#功能模块
ctos_follow 'JOIN_GAME', false, (buffer, info, client, server)->
room_name = info.pass
ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server)->
client.name = info.name #在创建room之前暂存
ygopro.ctos_follow 'JOIN_GAME', false, (buffer, info, client, server)->
if info.version != settings.version
stoc_send client, 'ERROR_MSG',{
ygopro.stoc_send client, 'ERROR_MSG',{
msg: 4
code: settings.version
}
client.end()
else if !room_name.length
stoc_send_chat(client,"房间为空,请修改房间名")
stoc_send client, 'ERROR_MSG',{
else if !info.pass.length
ygopro.stoc_send_chat(client,"房间为空,请修改房间名")
ygopro.stoc_send client, 'ERROR_MSG',{
msg: 1
code: 2
}
else if room_name == '[INCORRECT]' #房间密码验证
stoc_send client, 'ERROR_MSG',{
client.end()
else if info.pass == '[INCORRECT]' #模拟房间密码验证
ygopro.stoc_send client, 'ERROR_MSG',{
msg: 1
code: 1 #这返错有问题,直接双ygopro直连怎么都正常,在服务器上就经常弹不出提示
}
client.end()
else
if client.player != '[INCORRECT]' #用户验证
room = Room.find_by_name(room_name)
console.log "[join]find_by_room #{room_name} #{room}"
if room
room.add_client client
if room.established
server.connect room.port, '127.0.0.1', ->
server_listener(room.port, client, server)
else
freeport (err, port)->
room = Room.find_by_name(room_name)
console.log "[join freeport]find_by_room #{room_name} #{room}"
if room #如果等freeport的时间差又来了个.....
room.add_client client
if room.established
server.connect room.port, '127.0.0.1', ->
server_listener(room.port, client, server)
else
if(err)
stoc_send client, 'ERROR_MSG',{
else if client.name == '[INCORRECT]' #模拟用户验证
ygopro.stoc_send client, 'ERROR_MSG',{
msg: 1
code: 2
}
client.end()
else
room = new Room(room_name, port, client)
if room_name[0...2] == 'M#'
param = [0, 0, 1, 'F', 'F', 'F', 8000, 5, 1]
else if room_name[0...2] == 'T#'
param = [0, 0, 2, 'F', 'F', 'F', 8000, 5, 1]
else if (param = room_name.match /^(\d)?(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i)
param.shift()
param[0] == parseInt(param[0])
else
param = [0, 0, 0, 'F', 'F', 'F', 8000, 5, 1]
param.unshift port
process = spawn './ygopro', param, cwd: 'ygocore'
room.process = process
process.on 'exit', (code)->
console.log "room process #{port} exited with code #{code}"
room.delete()
process.stdout.once 'data', (data)->
room.established = true
_.each room.players, (player)->
server.connect port, '127.0.0.1', ->
server_listener(port, player.client, server)
else
stoc_send client, 'ERROR_MSG',{
msg: 1
code: 2
}
client.end()
client.room = Room.find_or_create_by_name(info.pass)
client.room.connect(client)
######################################################################################################################
#欢迎信息
stoc_follow 'JOIN_GAME', false, (buffer, info, client, server)->
stoc_send client, 'CHAT', {
ygopro.stoc_follow 'JOIN_GAME', false, (buffer, info, client, server)->
ygopro.stoc_send client, 'CHAT', {
player: 8
msg: "Mycard Debugging Server"
}
stoc_send client, 'CHAT', {
ygopro.stoc_send client, 'CHAT', {
player: 8
msg: "这里是测试中的新服务器, 还不稳定, 随时可能崩溃, 遇到意外请淡定\n ˉˉˉˉˉ"
}
......@@ -409,18 +201,23 @@ request
url: 'https://my-card.in/dialogues.json'
json: true
, (error, response, body)->
dialogues = body
if _.isString body
console.log "[WARN]dialogues bad json #{body}"
else
console.log "loaded #{_.size body} dialogues"
dialogues = body
stoc_follow 'GAME_MSG', false, (buffer, info, client, server)->
ygopro.stoc_follow 'GAME_MSG', false, (buffer, info, client, server)->
msg = buffer.readInt8(0)
if constants.MSG[msg] == 'SUMMONING' or constants.MSG[msg] == 'SPSUMMONING'
if ygopro.constants.MSG[msg] == 'SUMMONING' or ygopro.constants.MSG[msg] == 'SPSUMMONING'
card = buffer.readUInt32LE(1)
if dialogues[card]
for line in _.lines dialogues[card][Math.floor(Math.random() * dialogues[card].length)]
stoc_send_chat client, line
ygopro.stoc_send_chat client, line
#积分
if constants.MSG[msg] == 'WIN'
###
if ygopro.constants.MSG[msg] == 'WIN'
room = Room.find_by_client(client)
if !room
console.log "[WARN]win: can't find room by player #{client.player}"
......@@ -451,32 +248,61 @@ stoc_follow 'GAME_MSG', false, (buffer, info, client, server)->
console.log "#{loser} 减少5点积分,现在有#{loser.points}点"
stoc_follow 'HS_PLAYER_CHANGE', false, (buffer, info, client, server)->
client.ready = info.status & 0xF != 0
client.pos = info.status >> 4
console.log client.ready, client.pos
mongoose = require 'mongoose'
mongoose.connect('mongodb://localhost/mycard');
User = mongoose.model 'User',
name: String
points: Number
#mongoose = require 'mongoose'
#mongoose.connect('mongodb://localhost/mycard');
#User = mongoose.model 'User',
# name: String
# points: Number
#stoc_follow 'HS_PLAYER_CHANGE', false, (buffer, info, client, server)->
#ygopro.stoc_follow 'HS_PLAYER_CHANGE', false, (buffer, info, client, server)->
# console.log 'HS_PLAYER_CHANGE', info
###
#房间管理
stoc_follow 'HS_PLAYER_ENTER', false, (buffer, info, client, server)->
room = Room.find_by_client(client)
if !room
console.log "[WARN]player_enter: can't find room by player #{client.player}"
return
room.pos_name[info.pos] = info.name
ygopro.stoc_follow 'HS_PLAYER_ENTER', false, (buffer, info, client, server)->
console.log "PLAYER_ENTER to #{client.name}: #{info.name}, #{info.pos}"
#room = client.room
#if !room
# console.log "[WARN]player_enter: can't find room by player #{client.player}"
# return
#room.pos_name[info.pos] = info.name
ygopro.stoc_follow 'HS_PLAYER_CHANGE', false, (buffer, info, client, server)->
#client.ready = info.status & 0xF != 0
#client.pos = info.status >> 4
console.log "PLAYER_CHANGE to #{client.name}: #{info.status & 0xF != 0}, #{info.status >> 4}"
ygopro.stoc_follow 'TYPE_CHANGE', false, (buffer, info, client, server)->
selftype = info.type & 0xf;
is_host = ((info.type >> 4) & 0xf) != 0;
client.is_host = is_host
client.pos = selftype
console.log "TYPE_CHANGE to #{client.name}:", info, selftype, is_host
#房间数量
http.createServer (request, response)->
if url.parse(request.url).pathname == '/count.json'
#http://122.0.65.70:7922/?operation=getroomjson
url = url.parse(request.url)
if url.pathname == '/count.json'
response.writeHead(200);
response.end(Room.all.length.toString())
else if url.pathname == '/rooms.json'
response.writeHead(404);
response.end();
if url.query == 'operation=getroomjson'
response.writeHead(200);
response.end JSON.stringify rooms: (for room in Room.all
roomid: room.port.toString(),
roomname: room.name,
needpass: false.toString(),
users: (for player in room.players
id: (-1).toString(),
name: player.name,
pos: player.pos
),
istart: "wait"
)
else
response.writeHead(404);
response.end();
......@@ -507,18 +333,20 @@ setInterval ()->
room.alive = false
else
console.log "kill room #{room.port}"
for player in room.players
ygopro.stoc_send_chat(player, "由于长时间没有活动被关闭") unless player.closed
room.process.kill()
, 900000
#tip
stoc_send_tip = (client, tip)->
ygopro.stoc_send_tip = (client, tip)->
lines = _.lines(tip)
stoc_send_chat(client, "Tip: #{lines[0]}")
ygopro.stoc_send_chat(client, "Tip: #{lines[0]}")
for line in lines.slice(1)
stoc_send_chat(client, line)
ygopro.stoc_send_chat(client, line)
stoc_send_random_tip = (client)->
stoc_send_tip client, tips[Math.floor(Math.random() * tips.length)] if tips
ygopro.stoc_send_random_tip = (client)->
ygopro.stoc_send_tip client, tips[Math.floor(Math.random() * tips.length)] if tips
tips = null
request
......@@ -528,9 +356,10 @@ request
tips = body
console.log "loaded #{tips.length} tips"
stoc_follow 'DUEL_START', false, (buffer, info, client, server)->
stoc_send_random_tip(client)
ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server)->
ygopro.stoc_send_random_tip(client)
###
room = Room.find_by_client(client)
if !room
console.log "[WARN]duel start: can't find room by player #{client.player}"
......@@ -542,11 +371,11 @@ stoc_follow 'DUEL_START', false, (buffer, info, client, server)->
if !user
user = new User({name: client.player, points: 0})
user.save()
stoc_send_chat(client, "积分系统测试中,你现在有#{user.points}点积分,这些积分以后可能会重置")
ctos_follow 'CHAT', false, (buffer, info, client, server)->
ygopro.stoc_send_chat(client, "积分系统测试中,你现在有#{user.points}点积分,这些积分以后可能会重置")
###
ygopro.ctos_follow 'CHAT', false, (buffer, info, client, server)->
if _.trim(info.msg) == '/tip'
stoc_send_random_tip(client)
ygopro.stoc_send_random_tip(client)
###
# 开包大战
......@@ -560,8 +389,8 @@ for pack, cards of require './packs.json'
console.log packs_weighted_cards
ctos_follow 'UPDATE_DECK', false, (buffer, info, client, server)->
ctos_send server, 'HS_NOTREADY'
ygopro.ctos_follow 'UPDATE_DECK', false, (buffer, info, client, server)->
ygopro.ctos_send server, 'HS_NOTREADY'
deck = []
for pack in client.player
......@@ -569,12 +398,12 @@ ctos_follow 'UPDATE_DECK', false, (buffer, info, client, server)->
deck.push packs_weighted_cards[pack][Math.floor(Math.random()*packs_weighted_cards[pack].length)]
ctos_send server, 'UPDATE_DECK', {
ygopro.ctos_send server, 'UPDATE_DECK', {
mainc: deck.length,
sidec: 0,
deckbuf: deck
}
ctos_send server, 'HS_READY'
ygopro.ctos_send server, 'HS_READY'
###
// Generated by CoffeeScript 1.6.3
(function() {
var Inotify, Room, Struct, User, constants, ctos_follow, ctos_follows, ctos_send, debug, declaration, dialogues, field, freeport, fs, http, inotify, listener, mongoose, name, net, path, proto_structs, request, result, server_listener, settings, spawn, stoc_follow, stoc_follows, stoc_send, stoc_send_chat, stoc_send_random_tip, stoc_send_tip, structs, structs_declaration, tips, type, typedefs, url, _, _i, _len;
var Inotify, Room, debug, dialogues, fs, http, inotify, net, path, request, settings, tips, url, ygopro, _;
net = require('net');
......@@ -12,124 +12,22 @@
fs = require('fs');
spawn = require('child_process').spawn;
freeport = require('freeport');
Struct = require('struct').Struct;
_ = require('underscore');
_.str = require('underscore.string');
_.mixin(_.str.exports());
_.str.include('Underscore.string', 'string');
Inotify = require('inotify').Inotify;
request = require('request');
structs_declaration = require('./structs.json');
ygopro = require('./ygopro.js');
typedefs = require('./typedefs.json');
proto_structs = require('./proto_structs.json');
constants = require('./constants.json');
Room = require('./room.js');
settings = require('./config.json');
Room = (function() {
Room.all = [];
function Room(name, port, client) {
this.name = name;
this.port = port;
this.alive = true;
this.players = [];
this.dueling = false;
this.established = false;
this.pos_name = {};
this.add_client(client);
Room.all.push(this);
}
Room.prototype["delete"] = function(room) {
return Room.all.splice(_.indexOf(Room.all, room), 1);
};
Room.prototype.add_client = function(client) {
return this.players.push({
client: client,
name: client.player
});
};
Room.prototype.remove_client = function(client, error) {
var player, _i, _len, _ref, _results;
this.players = _.reject(this.players, function(player) {
return player.client === client;
});
_ref = this.players;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
player = _ref[_i];
_results.push(stoc_send_chat(player.client, "" + client.player + " 离开了游戏" + (error ? ": " + error : '')));
}
return _results;
};
Room.prototype.toString = function() {
var player, _ref, _ref1;
return "room: " + this.name + " " + this.port + " " + ((_ref = this.alive) != null ? _ref : {
'alive': 'not-alive'
}) + " " + ((_ref1 = this.dueling) != null ? _ref1 : {
'dueling': 'not-dueling'
}) + " [" + ((function() {
var _i, _len, _ref2, _results;
_ref2 = this.players;
_results = [];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
player = _ref2[_i];
_results.push("client " + (typeof player.client) + " server " + (typeof player.server) + " " + player.name + " " + player.pos + ". ");
}
return _results;
}).call(this)) + "] " + (JSON.stringify(this.pos_name));
};
Room.find_by_name = function(name) {
return _.find(this.all, function(room) {
return room.name === name;
});
};
Room.find_by_port = function(port) {
return _.find(this.all, function(room) {
return room.name === port;
});
};
Room.find_by_client = function(client) {
return _.find(this.all, function(room) {
return _.some(room.players, function(player) {
return player.client === client;
});
});
};
Room.find_by_server = function(server) {
return _.find(this.all, function(room) {
return _.some(room.players, function(player) {
return player.server === server;
});
});
};
return Room;
})();
debug = false;
if (process.argv[2] === '--debug') {
......@@ -137,177 +35,101 @@
settings.http_port++;
}
structs = {};
for (name in structs_declaration) {
declaration = structs_declaration[name];
result = Struct();
for (_i = 0, _len = declaration.length; _i < _len; _i++) {
field = declaration[_i];
if (field.encoding) {
switch (field.encoding) {
case "UTF-16LE":
result.chars(field.name, field.length * 2, field.encoding);
break;
default:
throw "unsupported encoding: " + file.encoding;
}
} else {
type = field.type;
if (typedefs[type]) {
type = typedefs[type];
}
if (field.length) {
result.array(field.name, field.length, type);
} else {
if (structs[type]) {
result.struct(field.name, structs[type]);
} else {
result[type](field.name);
}
}
net.createServer(function(client) {
var ctos_buffer, ctos_message_length, ctos_proto, server, stoc_buffer, stoc_message_length, stoc_proto;
server = new net.Socket();
client.server = server;
client.on('close', function(had_error) {
console.log("client closed " + had_error);
if (!client.closed) {
if (client.room) {
client.room.disconnect(client);
}
client.closed = true;
}
structs[name] = result;
return server.end();
});
client.on('error', function(error) {
console.log("client error " + error);
if (!client.closed) {
if (client.room) {
client.room.disconnect(client, error);
}
stoc_follows = {};
ctos_follows = {};
stoc_follow = function(proto, synchronous, callback) {
var key, value, _ref;
if (typeof proto === 'string') {
_ref = constants.STOC;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
client.closed = error;
}
return server.end();
});
server.on('close', function(had_error) {
console.log("server closed " + had_error);
if (!server.closed) {
server.closed = true;
}
if (!constants.STOC[proto]) {
throw "unknown proto";
if (!client.closed) {
ygopro.stoc_send_chat(client, "服务器关闭了连接");
client.closed = true;
return client.end();
}
});
server.on('error', function(error) {
console.log("server error " + error);
server.closed = error;
if (!client.closed) {
ygopro.stoc_send_chat(client, "服务器错误: " + error);
client.closed = true;
return client.end();
}
return stoc_follows[proto] = {
callback: callback,
synchronous: synchronous
};
};
ctos_follow = function(proto, synchronous, callback) {
var key, value, _ref;
if (typeof proto === 'string') {
_ref = constants.CTOS;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
});
ctos_buffer = new Buffer(0);
ctos_message_length = 0;
ctos_proto = 0;
client.pre_establish_buffers = new Array();
client.on('data', function(data) {
var b, struct;
ctos_buffer = Buffer.concat([ctos_buffer, data], ctos_buffer.length + data.length);
while (true) {
if (ctos_message_length === 0) {
if (ctos_buffer.length >= 2) {
ctos_message_length = ctos_buffer.readUInt16LE(0);
} else {
break;
}
}
if (!constants.CTOS[proto]) {
throw "unknown proto";
}
}
return ctos_follows[proto] = {
callback: callback,
synchronous: synchronous
};
};
stoc_send = function(socket, proto, info) {
var buffer, header, key, struct, value, _ref;
if (typeof info === 'undefined') {
buffer = "";
} else if (Buffer.isBuffer(info)) {
buffer = info;
} else if (ctos_proto === 0) {
if (ctos_buffer.length >= 3) {
ctos_proto = ctos_buffer.readUInt8(2);
} else {
struct = structs[proto_structs.STOC[proto]];
struct.allocate();
struct.set(info);
buffer = struct.buffer();
}
if (typeof proto === 'string') {
_ref = constants.STOC;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
} else {
if (ctos_buffer.length >= 2 + ctos_message_length) {
if (ygopro.ctos_follows[ctos_proto]) {
b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
if (struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]) {
struct._setBuff(b);
setTimeout(ygopro.ctos_follows[ctos_proto].callback, 0, b, _.clone(struct.fields), client, server);
} else {
setTimeout(ygopro.ctos_follows[ctos_proto].callback, 0, b, null, client, server);
}
if (!constants.STOC[proto]) {
throw "unknown proto";
}
}
header = new Buffer(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
return socket.write(buffer);
}
};
ctos_send = function(socket, proto, info) {
var buffer, header, key, struct, value, _ref;
if (typeof info === 'undefined') {
buffer = "";
} else if (Buffer.isBuffer(info)) {
buffer = info;
ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
ctos_message_length = 0;
ctos_proto = 0;
} else {
struct = structs[proto_structs.CTOS[proto]];
struct.allocate();
struct.set(info);
buffer = struct.buffer();
}
if (typeof proto === 'string') {
_ref = constants.CTOS;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
}
if (!constants.CTOS[proto]) {
throw "unknown proto";
}
if (!(ygopro.ctos_follows[ctos_proto] && ygopro.ctos_follows[ctos_proto].synchronous)) {
if (client.established) {
return server.write(data);
} else {
return client.pre_establish_buffers.push(data);
}
header = new Buffer(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
return socket.write(buffer);
}
};
stoc_send_chat = function(client, msg, player) {
if (player == null) {
player = 8;
}
return stoc_send(client, 'CHAT', {
player: player,
msg: msg
});
};
server_listener = function(port, client, server) {
var buffer, stoc_buffer, stoc_message_length, stoc_proto, _j, _len1, _ref;
client.connected = true;
console.log("connected " + port);
stoc_buffer = new Buffer(0);
stoc_message_length = 0;
stoc_proto = 0;
_ref = client.pre_connecion_buffers;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
buffer = _ref[_j];
server.write(buffer);
}
server.on("data", function(data) {
return server.on('data', function(data) {
var b, struct;
stoc_buffer = Buffer.concat([stoc_buffer, data], stoc_buffer.length + data.length);
while (true) {
......@@ -325,13 +147,13 @@
}
} else {
if (stoc_buffer.length >= 2 + stoc_message_length) {
if (stoc_follows[stoc_proto]) {
if (ygopro.stoc_follows[stoc_proto]) {
b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
if (struct = structs[proto_structs.STOC[constants.STOC[stoc_proto]]]) {
if (struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]) {
struct._setBuff(b);
setImmediate(stoc_follows[stoc_proto].callback, b, struct.fields, client, server);
setImmediate(ygopro.stoc_follows[stoc_proto].callback, b, _.clone(struct.fields), client, server);
} else {
setImmediate(stoc_follows[stoc_proto].callback, b, null, client, server);
setImmediate(ygopro.stoc_follows[stoc_proto].callback, b, null, client, server);
}
}
stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
......@@ -342,204 +164,54 @@
}
}
}
if (!(stoc_follows[stoc_proto] && stoc_follows[stoc_proto].synchronous)) {
return client.write(data);
}
});
server.on("error", function(e) {
console.log("server error " + e);
return client.end();
});
return server.on("close", function(had_error) {
console.log("server closed " + had_error);
return client.end();
});
};
listener = net.createServer(function(client) {
var ctos_buffer, ctos_message_length, ctos_proto, server;
client.connected = false;
ctos_buffer = new Buffer(0);
ctos_message_length = 0;
ctos_proto = 0;
client.pre_connecion_buffers = new Array();
server = new net.Socket();
server.on("error", function(e) {
stoc_send_chat(client, "服务器错误");
return console.log("server error " + e);
});
client.on("data", function(data) {
var b, struct;
ctos_buffer = Buffer.concat([ctos_buffer, data], ctos_buffer.length + data.length);
while (true) {
if (ctos_message_length === 0) {
if (ctos_buffer.length >= 2) {
ctos_message_length = ctos_buffer.readUInt16LE(0);
} else {
break;
}
} else if (ctos_proto === 0) {
if (ctos_buffer.length >= 3) {
ctos_proto = ctos_buffer.readUInt8(2);
} else {
break;
}
} else {
if (ctos_buffer.length >= 2 + ctos_message_length) {
if (ctos_follows[ctos_proto]) {
b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
if (struct = structs[proto_structs.CTOS[constants.CTOS[ctos_proto]]]) {
struct._setBuff(b);
setTimeout(ctos_follows[ctos_proto].callback, 0, b, struct.fields, client, server);
} else {
setTimeout(ctos_follows[ctos_proto].callback, 0, b, null, client, server);
}
}
ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
ctos_message_length = 0;
ctos_proto = 0;
} else {
break;
}
}
}
if (!(ctos_follows[ctos_proto] && ctos_follows[ctos_proto].synchronous)) {
if (client.connected) {
return server.write(data);
} else {
return client.pre_connecion_buffers.push(data);
}
}
});
client.on("error", function(e) {
var room;
room = Room.find_by_client(client);
if (room) {
room.remove_client(client, e);
}
console.log("client error " + e);
return server.end();
});
return client.on("close", function(had_error) {
var room;
console.log("client closed " + had_error);
if (had_error) {
return;
}
room = Room.find_by_client(client);
if (room) {
room.remove_client(client);
}
return server.end();
});
}).listen(settings.port, null, null, function() {
}).listen(settings.port, function() {
return console.log("server started on " + settings.ip + ":" + settings.port);
});
ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server) {
return client.player = info.name;
ygopro.ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server) {
return client.name = info.name;
});
ctos_follow('JOIN_GAME', false, function(buffer, info, client, server) {
var room, room_name;
room_name = info.pass;
ygopro.ctos_follow('JOIN_GAME', false, function(buffer, info, client, server) {
if (info.version !== settings.version) {
stoc_send(client, 'ERROR_MSG', {
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 4,
code: settings.version
});
return client.end();
} else if (!room_name.length) {
stoc_send_chat(client, "房间为空,请修改房间名");
return stoc_send(client, 'ERROR_MSG', {
} else if (!info.pass.length) {
ygopro.stoc_send_chat(client, "房间为空,请修改房间名");
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 1,
code: 2
});
} else if (room_name === '[INCORRECT]') {
stoc_send(client, 'ERROR_MSG', {
return client.end();
} else if (info.pass === '[INCORRECT]') {
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 1,
code: 1
});
return client.end();
} else {
if (client.player !== '[INCORRECT]') {
room = Room.find_by_name(room_name);
console.log("[join]find_by_room " + room_name + " " + room);
if (room) {
room.add_client(client);
if (room.established) {
return server.connect(room.port, '127.0.0.1', function() {
return server_listener(room.port, client, server);
});
}
} else {
return freeport(function(err, port) {
var param, process;
room = Room.find_by_name(room_name);
console.log("[join freeport]find_by_room " + room_name + " " + room);
if (room) {
room.add_client(client);
if (room.established) {
return server.connect(room.port, '127.0.0.1', function() {
return server_listener(room.port, client, server);
});
}
} else {
if (err) {
stoc_send(client, 'ERROR_MSG', {
} else if (client.name === '[INCORRECT]') {
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 1,
code: 2
});
return client.end();
} else {
room = new Room(room_name, port, client);
if (room_name.slice(0, 2) === 'M#') {
param = [0, 0, 1, 'F', 'F', 'F', 8000, 5, 1];
} else if (room_name.slice(0, 2) === 'T#') {
param = [0, 0, 2, 'F', 'F', 'F', 8000, 5, 1];
} else if ((param = room_name.match(/^(\d)?(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
param.shift();
param[0] === parseInt(param[0]);
} else {
param = [0, 0, 0, 'F', 'F', 'F', 8000, 5, 1];
}
param.unshift(port);
process = spawn('./ygopro', param, {
cwd: 'ygocore'
});
room.process = process;
process.on('exit', function(code) {
console.log("room process " + port + " exited with code " + code);
return room["delete"]();
});
return process.stdout.once('data', function(data) {
room.established = true;
return _.each(room.players, function(player) {
return server.connect(port, '127.0.0.1', function() {
return server_listener(port, player.client, server);
});
});
});
}
}
});
}
} else {
stoc_send(client, 'ERROR_MSG', {
msg: 1,
code: 2
});
return client.end();
}
client.room = Room.find_or_create_by_name(info.pass);
return client.room.connect(client);
}
});
stoc_follow('JOIN_GAME', false, function(buffer, info, client, server) {
stoc_send(client, 'CHAT', {
ygopro.stoc_follow('JOIN_GAME', false, function(buffer, info, client, server) {
ygopro.stoc_send(client, 'CHAT', {
player: 8,
msg: "Mycard Debugging Server"
});
return stoc_send(client, 'CHAT', {
return ygopro.stoc_send(client, 'CHAT', {
player: 8,
msg: "这里是测试中的新服务器, 还不稳定, 随时可能崩溃, 遇到意外请淡定\n ˉˉˉˉˉ"
});
......@@ -551,92 +223,134 @@
url: 'https://my-card.in/dialogues.json',
json: true
}, function(error, response, body) {
dialogues = body;
return console.log("loaded " + (_.size(body)) + " dialogues");
if (_.isString(body)) {
return console.log("[WARN]dialogues bad json " + body);
} else {
console.log("loaded " + (_.size(body)) + " dialogues");
return dialogues = body;
}
});
stoc_follow('GAME_MSG', false, function(buffer, info, client, server) {
var card, line, loser_name, msg, room, winner_name, _j, _len1, _ref;
ygopro.stoc_follow('GAME_MSG', false, function(buffer, info, client, server) {
var card, line, msg, _i, _len, _ref, _results;
msg = buffer.readInt8(0);
if (constants.MSG[msg] === 'SUMMONING' || constants.MSG[msg] === 'SPSUMMONING') {
if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING') {
card = buffer.readUInt32LE(1);
if (dialogues[card]) {
_ref = _.lines(dialogues[card][Math.floor(Math.random() * dialogues[card].length)]);
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
line = _ref[_j];
stoc_send_chat(client, line);
}
}
}
if (constants.MSG[msg] === 'WIN') {
room = Room.find_by_client(client);
if (!room) {
console.log("[WARN]win: can't find room by player " + client.player);
return;
}
if (_.startsWith(room.name, 'M#') && room.dueling) {
room.dueling = false;
loser_name = room.pos_name[buffer.readUInt8(1)];
winner_name = room.pos_name[1 - buffer.readUInt8(1)];
return User.findOne({
name: winner_name
}, function(err, winner) {
if (err) {
return console.log("" + err + " when finding user " + winner_name);
} else if (!winner) {
return console.log("user " + winner_name + " not exist");
} else {
return User.findOne({
name: loser_name
}, function(err, loser) {
if (err) {
return console.log("" + err + " when finding user " + loser_name);
} else if (!loser) {
return console.log("user " + loser_name + " not exist");
} else {
winner.points += 10;
loser.points -= 5;
winner.save();
loser.save();
console.log("" + winner + " 增加10点积分,现在有" + winner.points + "");
return console.log("" + loser + " 减少5点积分,现在有" + loser.points + "");
}
});
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
_results.push(ygopro.stoc_send_chat(client, line));
}
});
return _results;
}
}
});
stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server) {
client.ready = info.status & 0xF !== 0;
client.pos = info.status >> 4;
return console.log(client.ready, client.pos);
});
/*
if ygopro.constants.MSG[msg] == 'WIN'
room = Room.find_by_client(client)
if !room
console.log "[WARN]win: can't find room by player #{client.player}"
return
if _.startsWith(room.name, 'M#') and room.dueling
room.dueling = false
loser_name = room.pos_name[buffer.readUInt8(1)]
winner_name = room.pos_name[1 - buffer.readUInt8(1)]
#type = buffer.readUInt8(2)
User.findOne { name: winner_name }, (err, winner)->
if(err)
console.log "#{err} when finding user #{winner_name}"
else if(!winner)
console.log "user #{winner_name} not exist"
else
User.findOne { name: loser_name }, (err, loser)->
if(err)
console.log "#{err} when finding user #{loser_name}"
else if(!loser)
console.log "user #{loser_name} not exist"
else
winner.points += 10
loser.points -= 5
winner.save()
loser.save()
console.log "#{winner} 增加10点积分,现在有#{winner.points}点"
console.log "#{loser} 减少5点积分,现在有#{loser.points}点"
#mongoose = require 'mongoose'
#mongoose.connect('mongodb://localhost/mycard');
#User = mongoose.model 'User',
# name: String
# points: Number
#ygopro.stoc_follow 'HS_PLAYER_CHANGE', false, (buffer, info, client, server)->
# console.log 'HS_PLAYER_CHANGE', info
*/
mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mycard');
ygopro.stoc_follow('HS_PLAYER_ENTER', false, function(buffer, info, client, server) {
return console.log("PLAYER_ENTER to " + client.name + ": " + info.name + ", " + info.pos);
});
User = mongoose.model('User', {
name: String,
points: Number
ygopro.stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server) {
return console.log("PLAYER_CHANGE to " + client.name + ": " + (info.status & 0xF !== 0) + ", " + (info.status >> 4));
});
stoc_follow('HS_PLAYER_ENTER', false, function(buffer, info, client, server) {
var room;
room = Room.find_by_client(client);
if (!room) {
console.log("[WARN]player_enter: can't find room by player " + client.player);
return;
}
return room.pos_name[info.pos] = info.name;
ygopro.stoc_follow('TYPE_CHANGE', false, function(buffer, info, client, server) {
var is_host, selftype;
selftype = info.type & 0xf;
is_host = ((info.type >> 4) & 0xf) !== 0;
client.is_host = is_host;
client.pos = selftype;
return console.log("TYPE_CHANGE to " + client.name + ":", info, selftype, is_host);
});
http.createServer(function(request, response) {
if (url.parse(request.url).pathname === '/count.json') {
var player, room;
url = url.parse(request.url);
if (url.pathname === '/count.json') {
response.writeHead(200);
response.end(Room.all.length.toString());
} else if (url.pathname === '/rooms.json') {
response.writeHead(404);
response.end();
}
if (url.query === 'operation=getroomjson') {
response.writeHead(200);
return response.end(Room.all.length.toString());
return response.end(JSON.stringify({
rooms: (function() {
var _i, _len, _ref, _results;
_ref = Room.all;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
room = _ref[_i];
_results.push({
roomid: room.port.toString(),
roomname: room.name,
needpass: false.toString(),
users: (function() {
var _j, _len1, _ref1, _results1;
_ref1 = room.players;
_results1 = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
player = _ref1[_j];
_results1.push({
id: (-1).toString(),
name: player.name,
pos: player.pos
});
}
return _results1;
})(),
istart: "wait"
});
}
return _results;
})()
}));
} else {
response.writeHead(404);
return response.end();
......@@ -670,37 +384,44 @@
});
setInterval(function() {
var room, _j, _len1, _ref, _results;
var player, room, _i, _j, _len, _len1, _ref, _ref1, _results;
_ref = Room.all;
_results = [];
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
room = _ref[_j];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
room = _ref[_i];
if (room.alive) {
_results.push(room.alive = false);
} else {
console.log("kill room " + room.port);
_ref1 = room.players;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
player = _ref1[_j];
if (!player.closed) {
ygopro.stoc_send_chat(player, "由于长时间没有活动被关闭");
}
}
_results.push(room.process.kill());
}
}
return _results;
}, 900000);
stoc_send_tip = function(client, tip) {
var line, lines, _j, _len1, _ref, _results;
ygopro.stoc_send_tip = function(client, tip) {
var line, lines, _i, _len, _ref, _results;
lines = _.lines(tip);
stoc_send_chat(client, "Tip: " + lines[0]);
ygopro.stoc_send_chat(client, "Tip: " + lines[0]);
_ref = lines.slice(1);
_results = [];
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
line = _ref[_j];
_results.push(stoc_send_chat(client, line));
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
_results.push(ygopro.stoc_send_chat(client, line));
}
return _results;
};
stoc_send_random_tip = function(client) {
ygopro.stoc_send_random_tip = function(client) {
if (tips) {
return stoc_send_tip(client, tips[Math.floor(Math.random() * tips.length)]);
return ygopro.stoc_send_tip(client, tips[Math.floor(Math.random() * tips.length)]);
}
};
......@@ -714,34 +435,28 @@
return console.log("loaded " + tips.length + " tips");
});
stoc_follow('DUEL_START', false, function(buffer, info, client, server) {
var room;
stoc_send_random_tip(client);
room = Room.find_by_client(client);
if (!room) {
console.log("[WARN]duel start: can't find room by player " + client.player);
return;
}
room.dueling = true;
if (_.startsWith(room.name, 'M#')) {
return User.findOne({
name: client.player
}, function(err, user) {
if (!user) {
user = new User({
name: client.player,
points: 0
});
user.save();
}
return stoc_send_chat(client, "积分系统测试中,你现在有" + user.points + "点积分,这些积分以后可能会重置");
});
}
ygopro.stoc_follow('DUEL_START', false, function(buffer, info, client, server) {
return ygopro.stoc_send_random_tip(client);
/*
room = Room.find_by_client(client)
if !room
console.log "[WARN]duel start: can't find room by player #{client.player}"
return
room.dueling = true
if _.startsWith(room.name, 'M#')
User.findOne { name: client.player }, (err, user)->
if !user
user = new User({name: client.player, points: 0})
user.save()
ygopro.stoc_send_chat(client, "积分系统测试中,你现在有#{user.points}点积分,这些积分以后可能会重置")
*/
});
ctos_follow('CHAT', false, function(buffer, info, client, server) {
ygopro.ctos_follow('CHAT', false, function(buffer, info, client, server) {
if (_.trim(info.msg) === '/tip') {
return stoc_send_random_tip(client);
return ygopro.stoc_send_random_tip(client);
}
});
......@@ -757,8 +472,8 @@
console.log packs_weighted_cards
ctos_follow 'UPDATE_DECK', false, (buffer, info, client, server)->
ctos_send server, 'HS_NOTREADY'
ygopro.ctos_follow 'UPDATE_DECK', false, (buffer, info, client, server)->
ygopro.ctos_send server, 'HS_NOTREADY'
deck = []
for pack in client.player
......@@ -766,12 +481,12 @@
deck.push packs_weighted_cards[pack][Math.floor(Math.random()*packs_weighted_cards[pack].length)]
ctos_send server, 'UPDATE_DECK', {
ygopro.ctos_send server, 'UPDATE_DECK', {
mainc: deck.length,
sidec: 0,
deckbuf: deck
}
ctos_send server, 'HS_READY'
ygopro.ctos_send server, 'HS_READY'
*/
......
......@@ -6,5 +6,5 @@
"ygopro-server.coffee"
],
"names": [],
"mappings": "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"
"mappings": "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"
}
\ No newline at end of file
Struct = require('struct').Struct
#常量/类型声明
structs_declaration = require './structs.json' #结构体声明
typedefs = require './typedefs.json' #类型声明
@proto_structs = require './proto_structs.json' #消息与结构体的对应,未完成,对着duelclient.cpp加
@constants = require './constants.json' #network.h里定义的常量
#结构体定义
@structs = {}
for name, declaration of structs_declaration
result = Struct()
for field in declaration
if field.encoding
switch field.encoding
when "UTF-16LE" then result.chars field.name, field.length*2, field.encoding
else throw "unsupported encoding: #{field.encoding}"
else
type = field.type
type = typedefs[type] if typedefs[type]
if field.length
result.array field.name, field.length, type #不支持结构体
else
if @structs[type]
result.struct field.name, @structs[type]
else
result[type] field.name
@structs[name] = result
#消息跟踪函数 需要重构, 另暂时只支持异步, 同步没做.
@stoc_follows = {}
@ctos_follows = {}
@stoc_follow = (proto, synchronous, callback)->
if typeof proto == 'string'
for key, value of @constants.STOC
if value == proto
proto = key
break
throw "unknown proto" if !@constants.STOC[proto]
@stoc_follows[proto] = {callback: callback, synchronous: synchronous}
@ctos_follow = (proto, synchronous, callback)->
if typeof proto == 'string'
for key, value of @constants.CTOS
if value == proto
proto = key
break
throw "unknown proto" if !@constants.CTOS[proto]
@ctos_follows[proto] = {callback: callback, synchronous: synchronous}
#消息发送函数,至少要把俩合起来....
@stoc_send = (socket, proto, info)->
#console.log proto, proto_structs.STOC[proto], structs[proto_structs.STOC[proto]]
if typeof info == 'undefined'
buffer = ""
else if Buffer.isBuffer(info)
buffer = info
else
struct = @structs[@proto_structs.STOC[proto]]
struct.allocate()
struct.set info
buffer = struct.buffer()
if typeof proto == 'string' #需要重构
for key, value of @constants.STOC
if value == proto
proto = key
break
throw "unknown proto" if !@constants.STOC[proto]
header = new Buffer(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
@ctos_send = (socket, proto, info)->
#console.log proto, proto_structs.CTOS[proto], structs[proto_structs.CTOS[proto]]
if typeof info == 'undefined'
buffer = ""
else if Buffer.isBuffer(info)
buffer = info
else
struct = @structs[@proto_structs.CTOS[proto]]
struct.allocate()
struct.set info
buffer = struct.buffer()
if typeof proto == 'string' #需要重构
for key, value of @constants.CTOS
if value == proto
proto = key
break
throw "unknown proto" if !@constants.CTOS[proto]
header = new Buffer(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
#util
@stoc_send_chat = (client, msg, player = 8)->
@stoc_send client, 'CHAT', {
player: player
msg: msg
}
// Generated by CoffeeScript 1.6.3
(function() {
var Struct, declaration, field, name, result, structs_declaration, type, typedefs, _i, _len;
Struct = require('struct').Struct;
structs_declaration = require('./structs.json');
typedefs = require('./typedefs.json');
this.proto_structs = require('./proto_structs.json');
this.constants = require('./constants.json');
this.structs = {};
for (name in structs_declaration) {
declaration = structs_declaration[name];
result = Struct();
for (_i = 0, _len = declaration.length; _i < _len; _i++) {
field = declaration[_i];
if (field.encoding) {
switch (field.encoding) {
case "UTF-16LE":
result.chars(field.name, field.length * 2, field.encoding);
break;
default:
throw "unsupported encoding: " + field.encoding;
}
} else {
type = field.type;
if (typedefs[type]) {
type = typedefs[type];
}
if (field.length) {
result.array(field.name, field.length, type);
} else {
if (this.structs[type]) {
result.struct(field.name, this.structs[type]);
} else {
result[type](field.name);
}
}
}
}
this.structs[name] = result;
}
this.stoc_follows = {};
this.ctos_follows = {};
this.stoc_follow = function(proto, synchronous, callback) {
var key, value, _ref;
if (typeof proto === 'string') {
_ref = this.constants.STOC;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
}
if (!this.constants.STOC[proto]) {
throw "unknown proto";
}
}
return this.stoc_follows[proto] = {
callback: callback,
synchronous: synchronous
};
};
this.ctos_follow = function(proto, synchronous, callback) {
var key, value, _ref;
if (typeof proto === 'string') {
_ref = this.constants.CTOS;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
}
if (!this.constants.CTOS[proto]) {
throw "unknown proto";
}
}
return this.ctos_follows[proto] = {
callback: callback,
synchronous: synchronous
};
};
this.stoc_send = function(socket, proto, info) {
var buffer, header, key, struct, value, _ref;
if (typeof info === 'undefined') {
buffer = "";
} else if (Buffer.isBuffer(info)) {
buffer = info;
} else {
struct = this.structs[this.proto_structs.STOC[proto]];
struct.allocate();
struct.set(info);
buffer = struct.buffer();
}
if (typeof proto === 'string') {
_ref = this.constants.STOC;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
}
if (!this.constants.STOC[proto]) {
throw "unknown proto";
}
}
header = new Buffer(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
return socket.write(buffer);
}
};
this.ctos_send = function(socket, proto, info) {
var buffer, header, key, struct, value, _ref;
if (typeof info === 'undefined') {
buffer = "";
} else if (Buffer.isBuffer(info)) {
buffer = info;
} else {
struct = this.structs[this.proto_structs.CTOS[proto]];
struct.allocate();
struct.set(info);
buffer = struct.buffer();
}
if (typeof proto === 'string') {
_ref = this.constants.CTOS;
for (key in _ref) {
value = _ref[key];
if (value === proto) {
proto = key;
break;
}
}
if (!this.constants.CTOS[proto]) {
throw "unknown proto";
}
}
header = new Buffer(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
return socket.write(buffer);
}
};
this.stoc_send_chat = function(client, msg, player) {
if (player == null) {
player = 8;
}
return this.stoc_send(client, 'CHAT', {
player: player,
msg: msg
});
};
}).call(this);
/*
//@ sourceMappingURL=ygopro.map
*/
{
"version": 3,
"file": "ygopro.js",
"sourceRoot": "",
"sources": [
"ygopro.coffee"
],
"names": [],
"mappings": "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"
}
\ No newline at end of file
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