Commit cce4b17f authored by nanahira's avatar nanahira

use srvpro2 message lib

parent bb037bee
"use strict";
const Struct = require('./struct.js').Struct;
const fs = require("fs");
const _ = require("underscore");
function loadJSON(path) {
return JSON.parse(fs.readFileSync(path, "utf8"));
}
class Handler {
constructor(handler, synchronous) {
this.handler = handler;
this.synchronous = synchronous || false;
}
async handle(buffer, info, datas, params) {
if (this.synchronous) {
return !!(await this.handler(buffer, info, datas, params));
} else {
const newBuffer = Buffer.from(buffer);
const newDatas = datas.map(b => Buffer.from(b));
this.handler(newBuffer, info, newDatas, params);
return false;
}
}
}
class YGOProMessagesHelper {
constructor() {
this.initDatas();
this.initStructs();
}
initDatas() {
this.structs_declaration = loadJSON('./data/structs.json');
this.typedefs = loadJSON('./data/typedefs.json');
this.proto_structs = loadJSON('./data/proto_structs.json');
this.constants = loadJSON('./data/constants.json');
}
initStructs() {
for (let name in this.structs_declaration ) {
const declaration = this.structs_declaration [name];
let result = Struct();
for (let field of declaration) {
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 {
let type = field.type;
if (this.typedefs[type]) {
type = this.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;
}
}
getDirectionAndProto(protoStr) {
const protoStrMatch = protoStr.match(/^(STOC|CTOS)_([_A-Z]+)$/);
if (!protoStrMatch) {
throw `Invalid proto string: ${protoStr}`
}
return {
direction: protoStrMatch[1].toUpperCase(),
proto: protoStrMatch[2].toUpperCase()
}
}
translateProto(proto, direction) {
const directionProtoList = this.constants[direction];
if (typeof proto !== "string") {
return proto;
}
let translatedProto = _.find(Object.keys(directionProtoList), p => {
return directionProtoList[p] === proto;
});
if (!translatedProto) {
throw `unknown proto ${direction} ${proto}`;
}
return translatedProto;
}
sendMessage(socket, protostr, info) {
const {
direction,
proto
} = this.getDirectionAndProto(protostr);
let buffer;
if (socket.closed) {
return;
}
//console.log(proto, this.proto_structs[direction][proto]);
//const directionProtoList = this.constants[direction];
if (typeof info === 'undefined') {
buffer = "";
} else if (Buffer.isBuffer(info)) {
buffer = info;
} else {
let struct = this.structs[this.proto_structs[direction][proto]];
struct.allocate();
struct.set(info);
buffer = struct.buffer();
}
const translatedProto = this.translateProto(proto, direction);
let header = Buffer.allocUnsafe(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(translatedProto, 2);
socket.write(header);
if (buffer.length) {
socket.write(buffer);
}
}
addHandler(protostr, handler, synchronous, priority) {
if (priority < 0 || priority > 4) {
throw "Invalid priority: " + priority;
}
let {
direction,
proto
} = this.getDirectionAndProto(protostr);
synchronous = synchronous || false;
priority = priority || 1;
const handlerObj = new Handler(handler, synchronous);
let handlerCollection = this.handlers[direction][priority];
const translatedProto = this.translateProto(proto, direction);
if (!handlerCollection[translatedProto]) {
handlerCollection[translatedProto] = [];
}
handlerCollection[translatedProto].push(handlerObj);
}
async handleBuffer(messageBuffer, direction, protoFilter, params) {
let feedback = null;
let messageLength = 0;
let bufferProto = 0;
let datas = [];
for (let l = 0; l < 1000; ++l) {
if (messageLength === 0) {
if (messageBuffer.length >= 2) {
messageLength = messageBuffer.readUInt16LE(0);
} else {
if (messageBuffer.length !== 0) {
feedback = {
type: "BUFFER_LENGTH",
message: `Bad ${direction} buffer length`
};
}
break;
}
} else if (bufferProto === 0) {
if (messageBuffer.length >= 3) {
bufferProto = messageBuffer.readUInt8(2);
} else {
feedback = {
type: "PROTO_LENGTH",
message: `Bad ${direction} proto length`
};
break;
}
} else {
if (messageBuffer.length >= 2 + messageLength) {
const proto = this.constants[direction][bufferProto];
let cancel = proto && protoFilter && _.indexOf(protoFilter, proto) === -1;
let buffer = messageBuffer.slice(3, 2 + messageLength);
console.log(l, direction, proto, cancel);
for (let priority = 0; priority < 4; ++priority) {
if (cancel) {
break;
}
const handlerCollection = this.handlers[direction][priority];
if (proto && handlerCollection[bufferProto]) {
let struct = this.structs[this.proto_structs[direction][proto]];
let info = null;
if (struct) {
struct._setBuff(buffer);
info = _.clone(struct.fields);
}
for (let handler of handlerCollection[bufferProto]) {
cancel = await handler.handle(buffer, info, datas, params);
if (cancel) {
break;
}
}
}
}
if (!cancel) {
datas.push(messageBuffer.slice(0, 2 + messageLength));
}
messageBuffer = messageBuffer.slice(2 + messageLength);
messageLength = 0;
bufferProto = 0;
} else {
if (direction === "STOC" || messageLength !== 17735) {
feedback = {
type: "MESSAGE_LENGTH",
message: `Bad ${direction} message length`
};
}
break;
}
}
if (l === 999) {
feedback = {
type: "OVERSIZE",
message: `Oversized ${direction}`
};
}
}
return {
datas,
feedback
};
}
}
YGOProMessagesHelper.prototype.structs = {}
YGOProMessagesHelper.prototype.handlers = {
STOC: [{},
{},
{},
{},
{},
],
CTOS: [{},
{},
{},
{},
{},
]
}
module.exports = YGOProMessagesHelper;
......@@ -1734,161 +1734,43 @@ net.createServer (client) ->
room=ROOM_all[client.rid]
room.watcher.write ctos_buffer if room and !CLIENT_is_banned_by_mc(client)
else
#ctos_buffer = Buffer.alloc(0)
ctos_message_length = 0
ctos_proto = 0
#ctos_buffer = Buffer.concat([ctos_buffer, data], ctos_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
datas = []
looplimit = 0
while true
if ctos_message_length == 0
if ctos_buffer.length >= 2
ctos_message_length = ctos_buffer.readUInt16LE(0)
else
log.warn("bad ctos_buffer length", client.ip) unless ctos_buffer.length == 0
break
else if ctos_proto == 0
if ctos_buffer.length >= 3
ctos_proto = ctos_buffer.readUInt8(2)
else
log.warn("bad ctos_proto length", client.ip)
break
else
if ctos_buffer.length >= 2 + ctos_message_length
#console.log client.pos, "CTOS", ygopro.constants.CTOS[ctos_proto]
cancel = false
if settings.modules.reconnect.enabled and client.pre_reconnecting and ygopro.constants.CTOS[ctos_proto] != 'UPDATE_DECK'
cancel = true
b = ctos_buffer.slice(3, ctos_message_length - 1 + 3)
info = null
struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.ctos_follows_before[ctos_proto] and !cancel
for ctos_event in ygopro.ctos_follows_before[ctos_proto]
result = ctos_event.callback b, info, client, client.server, datas
if result and ctos_event.synchronous
cancel = true
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.ctos_follows[ctos_proto] and !cancel
result = ygopro.ctos_follows[ctos_proto].callback b, info, client, client.server, datas
if result and ygopro.ctos_follows[ctos_proto].synchronous
cancel = true
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.ctos_follows_after[ctos_proto] and !cancel
for ctos_event in ygopro.ctos_follows_after[ctos_proto]
result = ctos_event.callback b, info, client, client.server, datas
if result and ctos_event.synchronous
cancel = true
datas.push ctos_buffer.slice(0, 2 + ctos_message_length) unless cancel
ctos_buffer = ctos_buffer.slice(2 + ctos_message_length)
ctos_message_length = 0
ctos_proto = 0
else
log.warn("bad ctos_message length", client.ip, ctos_buffer.length, ctos_message_length, ctos_proto) if ctos_message_length != 17735
break
looplimit++
#log.info(looplimit)
if looplimit > 800 or ROOM_bad_ip[client.ip] > 5
log.info("error ctos", client.name, client.ip)
ctos_filter = if settings.modules.reconnect.enabled and client.pre_reconnecting then ["UPDATE_DECK"] else null
handle_data = await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
client: client,
server: client.server
})
if handle_data.feedback
log.warn(handle_data.feedback.message, client.name, client.ip)
if handle_data.feedback.type == "OVERSIZE" or ROOM_bad_ip[client.ip] > 5
bad_ip_count = ROOM_bad_ip[client.ip]
if bad_ip_count
ROOM_bad_ip[client.ip] = bad_ip_count + 1
else
ROOM_bad_ip[client.ip] = 1
CLIENT_kick(client)
break
return
if !client.server
return
if client.established
client.server.write buffer for buffer in datas
client.server.write buffer for buffer in handle_data.datas
else
client.pre_establish_buffers.push buffer for buffer in datas
client.pre_establish_buffers.push buffer for buffer in handle_data.datas
return
# 服务端到客户端(stoc)
server.on 'data', (stoc_buffer)->
#stoc_buffer = Buffer.alloc(0)
stoc_message_length = 0
stoc_proto = 0
#stoc_buffer = Buffer.concat([stoc_buffer, data], stoc_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
#unless ygopro.stoc_follows[stoc_proto] and ygopro.stoc_follows[stoc_proto].synchronous
#server.client.write data
datas = []
looplimit = 0
while true
if stoc_message_length == 0
if stoc_buffer.length >= 2
stoc_message_length = stoc_buffer.readUInt16LE(0)
else
log.warn("bad stoc_buffer length", server.client.ip) unless stoc_buffer.length == 0
break
else if stoc_proto == 0
if stoc_buffer.length >= 3
stoc_proto = stoc_buffer.readUInt8(2)
else
log.warn("bad stoc_proto length", server.client.ip)
break
else
if stoc_buffer.length >= 2 + stoc_message_length
#console.log client.pos, "STOC", ygopro.constants.STOC[stoc_proto]
cancel = false
b = stoc_buffer.slice(3, stoc_message_length - 1 + 3)
info = null
struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.stoc_follows_before[stoc_proto] and !cancel
for stoc_event in ygopro.stoc_follows_before[stoc_proto]
result = stoc_event.callback b, info, server.client, server, datas
if result and stoc_event.synchronous
cancel = true
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.stoc_follows[stoc_proto] and !cancel
result = ygopro.stoc_follows[stoc_proto].callback b, info, server.client, server, datas
if result and ygopro.stoc_follows[stoc_proto].synchronous
cancel = true
if struct and !cancel
struct._setBuff(b)
info = _.clone(struct.fields)
if ygopro.stoc_follows_after[stoc_proto] and !cancel
for stoc_event in ygopro.stoc_follows_after[stoc_proto]
result = stoc_event.callback b, info, server.client, server, datas
if result and stoc_event.synchronous
cancel = true
datas.push stoc_buffer.slice(0, 2 + stoc_message_length) unless cancel
stoc_buffer = stoc_buffer.slice(2 + stoc_message_length)
stoc_message_length = 0
stoc_proto = 0
else
log.warn("bad stoc_message length", server.client.ip)
break
looplimit++
#log.info(looplimit)
if looplimit > 800
log.info("error stoc", server.client.name)
handle_data = await ygopro.helper.handleBuffer(stoc_buffer, "STOC", null, {
client: server.client,
server: server
})
if handle_data.feedback
log.warn(handle_data.feedback.message, server.client.name, server.client.ip)
if handle_data.feedback.type == "OVERSIZE"
server.destroy()
break
return
if server.client and !server.client.closed
server.client.write buffer for buffer in datas
server.client.write buffer for buffer in handle_data.datas
return
return
......
......@@ -2325,102 +2325,22 @@
// 需要重构
// 客户端到服务端(ctos)协议分析
client.pre_establish_buffers = new Array();
client.on('data', function(ctos_buffer) {
var b, bad_ip_count, buffer, cancel, ctos_event, ctos_message_length, ctos_proto, datas, info, len3, len4, len5, len6, looplimit, n, o, p, q, ref3, ref4, result, room, struct;
client.on('data', async function(ctos_buffer) {
var bad_ip_count, buffer, ctos_filter, handle_data, len3, len4, n, o, ref3, ref4, room;
if (client.is_post_watcher) {
room = ROOM_all[client.rid];
if (room && !CLIENT_is_banned_by_mc(client)) {
room.watcher.write(ctos_buffer);
}
} else {
//ctos_buffer = Buffer.alloc(0)
ctos_message_length = 0;
ctos_proto = 0;
//ctos_buffer = Buffer.concat([ctos_buffer, data], ctos_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
datas = [];
looplimit = 0;
while (true) {
if (ctos_message_length === 0) {
if (ctos_buffer.length >= 2) {
ctos_message_length = ctos_buffer.readUInt16LE(0);
} else {
if (ctos_buffer.length !== 0) {
log.warn("bad ctos_buffer length", client.ip);
}
break;
}
} else if (ctos_proto === 0) {
if (ctos_buffer.length >= 3) {
ctos_proto = ctos_buffer.readUInt8(2);
} else {
log.warn("bad ctos_proto length", client.ip);
break;
}
} else {
if (ctos_buffer.length >= 2 + ctos_message_length) {
//console.log client.pos, "CTOS", ygopro.constants.CTOS[ctos_proto]
cancel = false;
if (settings.modules.reconnect.enabled && client.pre_reconnecting && ygopro.constants.CTOS[ctos_proto] !== 'UPDATE_DECK') {
cancel = true;
}
b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
info = null;
struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]];
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.ctos_follows_before[ctos_proto] && !cancel) {
ref3 = ygopro.ctos_follows_before[ctos_proto];
for (n = 0, len3 = ref3.length; n < len3; n++) {
ctos_event = ref3[n];
result = ctos_event.callback(b, info, client, client.server, datas);
if (result && ctos_event.synchronous) {
cancel = true;
}
}
}
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.ctos_follows[ctos_proto] && !cancel) {
result = ygopro.ctos_follows[ctos_proto].callback(b, info, client, client.server, datas);
if (result && ygopro.ctos_follows[ctos_proto].synchronous) {
cancel = true;
}
}
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.ctos_follows_after[ctos_proto] && !cancel) {
ref4 = ygopro.ctos_follows_after[ctos_proto];
for (o = 0, len4 = ref4.length; o < len4; o++) {
ctos_event = ref4[o];
result = ctos_event.callback(b, info, client, client.server, datas);
if (result && ctos_event.synchronous) {
cancel = true;
}
}
}
if (!cancel) {
datas.push(ctos_buffer.slice(0, 2 + ctos_message_length));
}
ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
ctos_message_length = 0;
ctos_proto = 0;
} else {
if (ctos_message_length !== 17735) {
log.warn("bad ctos_message length", client.ip, ctos_buffer.length, ctos_message_length, ctos_proto);
}
break;
}
}
looplimit++;
//log.info(looplimit)
if (looplimit > 800 || ROOM_bad_ip[client.ip] > 5) {
log.info("error ctos", client.name, client.ip);
ctos_filter = settings.modules.reconnect.enabled && client.pre_reconnecting ? ["UPDATE_DECK"] : null;
handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
client: client,
server: client.server
}));
if (handle_data.feedback) {
log.warn(handle_data.feedback, client.name, client.ip);
if (handle_data.feedback.type === "OVERSIZE" || ROOM_bad_ip[client.ip] > 5) {
bad_ip_count = ROOM_bad_ip[client.ip];
if (bad_ip_count) {
ROOM_bad_ip[client.ip] = bad_ip_count + 1;
......@@ -2428,121 +2348,45 @@
ROOM_bad_ip[client.ip] = 1;
}
CLIENT_kick(client);
break;
return;
}
}
if (!client.server) {
return;
}
if (client.established) {
for (p = 0, len5 = datas.length; p < len5; p++) {
buffer = datas[p];
ref3 = handle_data.datas;
for (n = 0, len3 = ref3.length; n < len3; n++) {
buffer = ref3[n];
client.server.write(buffer);
}
} else {
for (q = 0, len6 = datas.length; q < len6; q++) {
buffer = datas[q];
ref4 = handle_data.datas;
for (o = 0, len4 = ref4.length; o < len4; o++) {
buffer = ref4[o];
client.pre_establish_buffers.push(buffer);
}
}
}
});
// 服务端到客户端(stoc)
server.on('data', function(stoc_buffer) {
var b, buffer, cancel, datas, info, len3, len4, len5, looplimit, n, o, p, ref3, ref4, result, stoc_event, stoc_message_length, stoc_proto, struct;
//stoc_buffer = Buffer.alloc(0)
stoc_message_length = 0;
stoc_proto = 0;
//stoc_buffer = Buffer.concat([stoc_buffer, data], stoc_buffer.length + data.length) #buffer的错误使用方式,好孩子不要学
//unless ygopro.stoc_follows[stoc_proto] and ygopro.stoc_follows[stoc_proto].synchronous
//server.client.write data
datas = [];
looplimit = 0;
while (true) {
if (stoc_message_length === 0) {
if (stoc_buffer.length >= 2) {
stoc_message_length = stoc_buffer.readUInt16LE(0);
} else {
if (stoc_buffer.length !== 0) {
log.warn("bad stoc_buffer length", server.client.ip);
}
break;
}
} else if (stoc_proto === 0) {
if (stoc_buffer.length >= 3) {
stoc_proto = stoc_buffer.readUInt8(2);
} else {
log.warn("bad stoc_proto length", server.client.ip);
break;
}
} else {
if (stoc_buffer.length >= 2 + stoc_message_length) {
//console.log client.pos, "STOC", ygopro.constants.STOC[stoc_proto]
cancel = false;
b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
info = null;
struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]];
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.stoc_follows_before[stoc_proto] && !cancel) {
ref3 = ygopro.stoc_follows_before[stoc_proto];
for (n = 0, len3 = ref3.length; n < len3; n++) {
stoc_event = ref3[n];
result = stoc_event.callback(b, info, server.client, server, datas);
if (result && stoc_event.synchronous) {
cancel = true;
}
}
}
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.stoc_follows[stoc_proto] && !cancel) {
result = ygopro.stoc_follows[stoc_proto].callback(b, info, server.client, server, datas);
if (result && ygopro.stoc_follows[stoc_proto].synchronous) {
cancel = true;
}
}
if (struct && !cancel) {
struct._setBuff(b);
info = _.clone(struct.fields);
}
if (ygopro.stoc_follows_after[stoc_proto] && !cancel) {
ref4 = ygopro.stoc_follows_after[stoc_proto];
for (o = 0, len4 = ref4.length; o < len4; o++) {
stoc_event = ref4[o];
result = stoc_event.callback(b, info, server.client, server, datas);
if (result && stoc_event.synchronous) {
cancel = true;
}
}
}
if (!cancel) {
datas.push(stoc_buffer.slice(0, 2 + stoc_message_length));
}
stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
stoc_message_length = 0;
stoc_proto = 0;
} else {
log.warn("bad stoc_message length", server.client.ip);
break;
}
}
looplimit++;
//log.info(looplimit)
if (looplimit > 800) {
log.info("error stoc", server.client.name);
server.on('data', async function(stoc_buffer) {
var buffer, handle_data, len3, n, ref3;
handle_data = (await ygopro.helper.handleBuffer(stoc_buffer, "STOC", null, {
client: server.client,
server: server
}));
if (handle_data.feedback) {
log.warn(handle_data.feedback, server.client.name, server.client.ip);
if (handle_data.feedback.type === "OVERSIZE") {
server.destroy();
break;
return;
}
}
if (server.client && !server.client.closed) {
for (p = 0, len5 = datas.length; p < len5; p++) {
buffer = datas[p];
ref3 = handle_data.datas;
for (n = 0, len3 = ref3.length; n < len3; n++) {
buffer = ref3[n];
server.client.write(buffer);
}
}
......
......@@ -7,142 +7,44 @@ loadJSON = require('load-json-file').sync
@i18ns = loadJSON './data/i18n.json'
#常量/类型声明
structs_declaration = loadJSON './data/structs.json' #结构体声明
typedefs = loadJSON './data/typedefs.json' #类型声明
@proto_structs = loadJSON './data/proto_structs.json' #消息与结构体的对应,未完成,对着duelclient.cpp加
@constants = loadJSON './data/constants.json' #network.h里定义的常量
YGOProMessageHelper = require("./YGOProMessages.js") # 为 SRVPro2 准备的库,这里拿这个库只用来测试,SRVPro1 对异步支持不是特别完善,因此不会有很多异步优化
@helper = new YGOProMessageHelper()
#结构体定义
@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
@structs = @helper.structs
@structs_declaration = @helper.structs_declaration
@typedefs = @helper.typedefs
@proto_structs = @helper.proto_structs
@constants = @helper.constants
#消息跟踪函数 需要重构, 另暂时只支持异步, 同步没做.
@stoc_follows = {}
@stoc_follows_before = {}
@stoc_follows_after = {}
@ctos_follows = {}
@ctos_follows_before = {}
@ctos_follows_after = {}
@replace_proto = (proto, tp) ->
if typeof(proto) != "string"
return proto
changed_proto = proto
for key, value of @constants[tp]
if value == proto
changed_proto = key
break
throw "unknown proto" if !@constants[tp][changed_proto]
return changed_proto
translateHandler = (handler) ->
return (buffer, info, datas, params)->
await return handler(buffer, info, params.client, params.server, datas)
@stoc_follow = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "STOC")
@stoc_follows[changed_proto] = {callback: callback, synchronous: synchronous}
@helper.addHandler("STOC_#{proto}", translateHandler(callback), synchronous, 1)
return
@stoc_follow_before = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "STOC")
if !@stoc_follows_before[changed_proto]
@stoc_follows_before[changed_proto] = []
@stoc_follows_before[changed_proto].push({callback: callback, synchronous: synchronous})
@helper.addHandler("STOC_#{proto}", translateHandler(callback), synchronous, 0)
return
@stoc_follow_after = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "STOC")
if !@stoc_follows_after[changed_proto]
@stoc_follows_after[changed_proto] = []
@stoc_follows_after[changed_proto].push({callback: callback, synchronous: synchronous})
@helper.addHandler("STOC_#{proto}", translateHandler(callback), synchronous, 2)
return
@ctos_follow = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "CTOS")
@ctos_follows[changed_proto] = {callback: callback, synchronous: synchronous}
@helper.addHandler("CTOS_#{proto}", translateHandler(callback), synchronous, 1)
return
@ctos_follow_before = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "CTOS")
if !@ctos_follows_before[changed_proto]
@ctos_follows_before[changed_proto] = []
@ctos_follows_before[changed_proto].push({callback: callback, synchronous: synchronous})
@helper.addHandler("CTOS_#{proto}", translateHandler(callback), synchronous, 0)
return
@ctos_follow_after = (proto, synchronous, callback)->
changed_proto = @replace_proto(proto, "CTOS")
if !@ctos_follows_after[changed_proto]
@ctos_follows_after[changed_proto] = []
@ctos_follows_after[changed_proto].push({callback: callback, synchronous: synchronous})
@helper.addHandler("CTOS_#{proto}", translateHandler(callback), synchronous, 2)
return
#消息发送函数,至少要把俩合起来....
@stoc_send = (socket, proto, info)->
if socket.closed
return
#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 = Buffer.allocUnsafe(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
return
return @helper.sendMessage(socket, "STOC_#{proto}", info)
@ctos_send = (socket, proto, info)->
if socket.closed
return
#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 = Buffer.allocUnsafe(3)
header.writeUInt16LE buffer.length + 1, 0
header.writeUInt8 proto, 2
socket.write header
socket.write buffer if buffer.length
return
return @helper.sendMessage(socket, "CTOS_#{proto}", info)
#util
@stoc_send_chat = (client, msg, player = 8)->
......
// Generated by CoffeeScript 2.5.1
(function() {
var Struct, _, declaration, field, i, len, loadJSON, name, result, structs_declaration, type, typedefs;
var Struct, YGOProMessageHelper, _, loadJSON, translateHandler;
_ = require('underscore');
......@@ -14,237 +14,69 @@
this.i18ns = loadJSON('./data/i18n.json');
//常量/类型声明
structs_declaration = loadJSON('./data/structs.json'); //结构体声明
YGOProMessageHelper = require("./YGOProMessages.js"); // 为 SRVPro2 准备的库,这里拿这个库只用来测试,SRVPro1 对异步支持不是特别完善,因此不会有很多异步优化
typedefs = loadJSON('./data/typedefs.json'); //类型声明
this.helper = new YGOProMessageHelper();
this.proto_structs = loadJSON('./data/proto_structs.json'); //消息与结构体的对应,未完成,对着duelclient.cpp加
this.structs = this.helper.structs;
this.constants = loadJSON('./data/constants.json'); //network.h里定义的常量
this.structs_declaration = this.helper.structs_declaration;
//结构体定义
this.structs = {};
this.typedefs = this.helper.typedefs;
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.stoc_follows_before = {};
this.proto_structs = this.helper.proto_structs;
this.stoc_follows_after = {};
this.constants = this.helper.constants;
this.ctos_follows = {};
this.ctos_follows_before = {};
this.ctos_follows_after = {};
this.replace_proto = function(proto, tp) {
var changed_proto, key, ref, value;
if (typeof proto !== "string") {
return proto;
}
changed_proto = proto;
ref = this.constants[tp];
for (key in ref) {
value = ref[key];
if (value === proto) {
changed_proto = key;
break;
}
}
if (!this.constants[tp][changed_proto]) {
throw "unknown proto";
}
return changed_proto;
translateHandler = function(handler) {
return async function(buffer, info, datas, params) {
return handler(buffer, info, params.client, params.server, datas);
};
};
this.stoc_follow = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "STOC");
this.stoc_follows[changed_proto] = {
callback: callback,
synchronous: synchronous
};
this.helper.addHandler(`STOC_${proto}`, translateHandler(callback), synchronous, 1);
};
this.stoc_follow_before = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "STOC");
if (!this.stoc_follows_before[changed_proto]) {
this.stoc_follows_before[changed_proto] = [];
}
this.stoc_follows_before[changed_proto].push({
callback: callback,
synchronous: synchronous
});
this.helper.addHandler(`STOC_${proto}`, translateHandler(callback), synchronous, 0);
};
this.stoc_follow_after = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "STOC");
if (!this.stoc_follows_after[changed_proto]) {
this.stoc_follows_after[changed_proto] = [];
}
this.stoc_follows_after[changed_proto].push({
callback: callback,
synchronous: synchronous
});
this.helper.addHandler(`STOC_${proto}`, translateHandler(callback), synchronous, 2);
};
this.ctos_follow = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "CTOS");
this.ctos_follows[changed_proto] = {
callback: callback,
synchronous: synchronous
};
this.helper.addHandler(`CTOS_${proto}`, translateHandler(callback), synchronous, 1);
};
this.ctos_follow_before = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "CTOS");
if (!this.ctos_follows_before[changed_proto]) {
this.ctos_follows_before[changed_proto] = [];
}
this.ctos_follows_before[changed_proto].push({
callback: callback,
synchronous: synchronous
});
this.helper.addHandler(`CTOS_${proto}`, translateHandler(callback), synchronous, 0);
};
this.ctos_follow_after = function(proto, synchronous, callback) {
var changed_proto;
changed_proto = this.replace_proto(proto, "CTOS");
if (!this.ctos_follows_after[changed_proto]) {
this.ctos_follows_after[changed_proto] = [];
}
this.ctos_follows_after[changed_proto].push({
callback: callback,
synchronous: synchronous
});
this.helper.addHandler(`CTOS_${proto}`, translateHandler(callback), synchronous, 2);
};
//消息发送函数,至少要把俩合起来....
this.stoc_send = function(socket, proto, info) {
var buffer, header, key, ref, struct, value;
if (socket.closed) {
return;
}
//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 = 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 = Buffer.allocUnsafe(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
socket.write(buffer);
}
return this.helper.sendMessage(socket, `STOC_${proto}`, info);
};
this.ctos_send = function(socket, proto, info) {
var buffer, header, key, ref, struct, value;
if (socket.closed) {
return;
}
//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 = 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 = Buffer.allocUnsafe(3);
header.writeUInt16LE(buffer.length + 1, 0);
header.writeUInt8(proto, 2);
socket.write(header);
if (buffer.length) {
socket.write(buffer);
}
return this.helper.sendMessage(socket, `CTOS_${proto}`, info);
};
//util
this.stoc_send_chat = function(client, msg, player = 8) {
var j, len1, line, o, r, re, ref, ref1;
var i, len, line, o, r, re, ref, ref1;
if (!client) {
console.log("err stoc_send_chat");
return;
}
ref = _.lines(msg);
for (j = 0, len1 = ref.length; j < len1; j++) {
line = ref[j];
for (i = 0, len = ref.length; i < len; i++) {
line = ref[i];
if (player >= 10) {
line = "[Server]: " + line;
}
......@@ -262,21 +94,21 @@
};
this.stoc_send_chat_to_room = function(room, msg, player = 8) {
var client, j, k, len1, len2, ref, ref1;
var client, i, j, len, len1, ref, ref1;
if (!room) {
console.log("err stoc_send_chat_to_room");
return;
}
ref = room.players;
for (j = 0, len1 = ref.length; j < len1; j++) {
client = ref[j];
for (i = 0, len = ref.length; i < len; i++) {
client = ref[i];
if (client) {
this.stoc_send_chat(client, msg, player);
}
}
ref1 = room.watchers;
for (k = 0, len2 = ref1.length; k < len2; k++) {
client = ref1[k];
for (j = 0, len1 = ref1.length; j < len1; j++) {
client = ref1[j];
if (client) {
this.stoc_send_chat(client, msg, player);
}
......@@ -284,14 +116,14 @@
};
this.stoc_send_hint_card_to_room = function(room, card) {
var client, j, k, len1, len2, ref, ref1;
var client, i, j, len, len1, ref, ref1;
if (!room) {
console.log("err stoc_send_hint_card_to_room");
return;
}
ref = room.players;
for (j = 0, len1 = ref.length; j < len1; j++) {
client = ref[j];
for (i = 0, len = ref.length; i < len; i++) {
client = ref[i];
if (client) {
this.stoc_send(client, 'GAME_MSG', {
curmsg: 2,
......@@ -302,8 +134,8 @@
}
}
ref1 = room.watchers;
for (k = 0, len2 = ref1.length; k < len2; k++) {
client = ref1[k];
for (j = 0, len1 = ref1.length; j < len1; j++) {
client = ref1[j];
if (client) {
this.stoc_send(client, 'GAME_MSG', {
curmsg: 2,
......
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