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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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