Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
ygopro-match
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
ygopro-match
Commits
2f31c6e8
Commit
2f31c6e8
authored
Sep 13, 2016
by
Peter Xin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init commit
parent
2b0c8fa7
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
194 additions
and
61 deletions
+194
-61
.gitignore
.gitignore
+4
-10
main.js
main.js
+166
-48
package.json
package.json
+9
-3
test.js
test.js
+15
-0
No files found.
.gitignore
View file @
2f31c6e8
#################
.gitignore
## Jetbrains
config.json
#################
node_modules/
.idea/
/.idea/
\ No newline at end of file
#################
## Node
#################
/node_modules/
\ No newline at end of file
main.js
View file @
2f31c6e8
'
use strict
'
;
'
use strict
'
;
const
request
=
require
(
'
request
'
);
const
http
=
require
(
'
http
'
);
const
http
=
require
(
'
http
'
);
const
crypto
=
require
(
'
crypto
'
);
const
crypto
=
require
(
'
crypto
'
);
const
fs
=
require
(
'
fs
'
);
let
servers
=
[{
const
config
=
JSON
.
parse
(
fs
.
readFileSync
(
"
./config.json
"
));
"
address
"
:
"
112.124.105.11
"
,
let
athleticUserPool
=
[];
"
port
"
:
7911
let
entertainUserPool
=
[];
}];
let
pending
=
null
;
let
getUserConfig
=
function
(
user
,
callback
)
{
// HTTP GET 抓取数据。
// 原 HTTP POST 抓取数据保留
let
address
=
config
.
arena
.
address
;
// let ak = config.arena.ak;
request
.
get
(
address
+
user
.
username
,
function
(
err
,
res
,
body
)
{
if
(
res
.
statusCode
!=
200
)
{
console
.
log
(
"
failed to load user data for #{user}
"
);
}
else
{
callback
(
JSON
.
parse
(
body
));
}
});
/*
request.post(address, {form:{ ak, username: user.username, password: user.password }}, function (err, res, body) {
callback();
});
*/
};
// TrueSkill
// 参考于 https://zh.wikipedia.org/zh-hans/TrueSkill评分系统
let
athleticTrueSkillMatchPoint
=
function
(
userA
,
userB
)
{
let
trueSkillA
=
userA
.
trueskill
;
let
trueSkillB
=
userB
.
trueskill
;
let
b2
=
(
Math
.
pow
(
trueSkillA
.
variance
,
2
)
+
Math
.
pow
(
trueSkillB
.
variance
,
2
))
/
2
;
let
c2
=
2
*
b2
+
trueSkillA
.
mean
*
trueSkillA
.
mean
+
trueSkillB
.
mean
*
trueSkillB
.
mean
;
return
Math
.
exp
(
-
Math
.
pow
((
trueSkillA
.
mean
-
trueSkillB
.
mean
),
2
)
/
2
/
c2
)
*
Math
.
sqrt
(
2
*
b2
/
c2
)
};
// 刷新竞技玩家池
let
updateAthleticMatch
=
function
()
{
let
length
=
athleticUserPool
.
length
;
// 数量少于 2,什么都不做
if
(
length
<
2
)
return
;
// 生成对称表
let
values
=
[];
for
(
let
i
=
0
;
i
<
length
;
i
++
)
for
(
let
j
=
0
;
j
<
length
;
j
++
)
if
(
i
===
j
)
values
[
length
*
j
+
i
]
=
{
i
,
j
,
value
:
0
};
else
values
[
length
*
j
+
i
]
=
{
i
,
j
,
value
:
athleticTrueSkillMatchPoint
(
athleticUserPool
[
i
].
data
,
athleticUserPool
[
j
].
data
)
};
// 含参排序
values
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
);
// 生成 mask 表
let
masks
=
[];
for
(
let
i
=
0
;
i
<
length
;
i
++
)
masks
[
i
]
=
false
;
// 开始返回
for
(
let
value
of
values
)
{
if
(
value
.
value
<
config
.
match
.
gate
)
break
;
if
(
masks
[
value
.
i
]
||
masks
[
value
.
j
])
continue
;
pair
(
athleticUserPool
[
value
.
i
].
client
,
athleticUserPool
[
value
.
j
].
client
);
masks
[
i
]
=
true
;
masks
[
j
]
=
true
;
}
// 移除用户
let
newPool
=
[];
for
(
let
i
=
0
;
i
<
masks
.
length
;
i
++
)
if
(
!
(
masks
[
i
]))
newPool
.
push
(
athleticUserPool
[
i
]);
athleticUserPool
=
newPool
;
};
// 刷新娱乐玩家池
let
updateEntertainMatch
=
function
()
{
let
length
=
entertainUserPool
.
length
;
if
(
length
<
2
)
return
;
// 根据用户等级进行排序
entertainUserPool
.
sort
((
a
,
b
)
=>
b
.
level
-
a
.
level
);
// 从高到低进行贪心配对
let
newPool
=
[];
// TODO: 加入时间分界
for
(
let
i
=
0
;
i
<
length
;
i
++
)
{
let
userA
=
entertainUserPool
[
i
];
let
userB
=
entertainUserPool
[
i
+
1
];
// 移出边界时的处理
if
(
userA
===
undefined
)
break
;
if
(
userB
===
undefined
)
{
newPool
.
push
(
userA
);
break
;
}
// 若 exp 之差小于门限,则匹配房间
if
(
userA
.
data
.
exp
-
userB
.
data
.
exp
<
config
.
match
.
entertainExpGate
)
{
pair
(
userA
.
client
,
userB
.
client
);
i
+=
1
;
}
// 否则留存
else
newPool
.
add
(
userA
);
}
entertainUserPool
=
newPool
;
};
let
update
=
function
()
{
updateAthleticMatch
();
updateEntertainMatch
();
};
// 为两名玩家匹配房间
let
pair
=
function
(
userARes
,
userBRes
)
{
let
servers
=
config
.
servers
;
let
server
=
servers
[
Math
.
floor
(
Math
.
random
()
*
servers
.
length
)];
let
room_id
=
crypto
.
randomBytes
(
9
).
toString
(
'
base64
'
).
slice
(
0
,
11
).
replace
(
'
+
'
,
'
-
'
).
replace
(
'
/
'
,
'
_
'
);
let
options_buffer
=
new
Buffer
(
6
);
options_buffer
.
writeUInt8
(
4
<<
4
,
1
);
let
checksum
=
0
;
for
(
let
i
=
1
;
i
<
options_buffer
.
length
;
i
++
)
{
checksum
-=
options_buffer
.
readUInt8
(
i
)
}
options_buffer
.
writeUInt8
(
checksum
&
0xFF
,
0
);
for
(
let
client
of
[
userARes
,
userBRes
])
{
let
buffer
=
new
Buffer
(
6
);
let
secret
=
parseInt
(
client
.
password
)
%
65535
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
)
}
let
password
=
buffer
.
toString
(
'
base64
'
)
+
room_id
;
let
result
=
JSON
.
stringify
({
"
address
"
:
server
.
address
,
"
port
"
:
server
.
port
,
"
password
"
:
password
});
console
.
log
(
userARes
.
username
+
"
and
"
+
userBRes
.
username
+
"
matched on room
"
+
room_id
);
client
.
writeHead
(
200
,
{
'
Content-Type
'
:
'
application/json
'
,
'
Cache-Control
'
:
'
no-cache
'
});
client
.
end
(
result
);
}
};
// 创建服务器
http
.
createServer
((
req
,
res
)
=>
{
http
.
createServer
((
req
,
res
)
=>
{
try
{
try
{
// 读取数据
let
credentials
=
new
Buffer
(
req
.
headers
[
'
authorization
'
].
split
(
'
'
)[
1
],
'
base64
'
).
toString
().
split
(
'
:
'
);
let
credentials
=
new
Buffer
(
req
.
headers
[
'
authorization
'
].
split
(
'
'
)[
1
],
'
base64
'
).
toString
().
split
(
'
:
'
);
let
username
=
credentials
[
0
];
let
username
=
credentials
[
0
];
let
password
=
credentials
[
1
];
let
password
=
credentials
[
1
];
if
(
!
username
||
!
password
)
{
if
(
!
username
||
!
password
)
{
throw
'
auth
'
;
throw
'
auth
'
;
}
}
//TODO: Auth
console
.
log
(
username
+
'
apply for a match.
'
);
console
.
log
(
username
+
'
requested match.
'
);
res
.
username
=
username
;
res
.
username
=
username
;
res
.
password
=
password
;
res
.
password
=
password
;
}
catch
(
error
)
{
// 送读取数据
getUserConfig
(
res
,
(
ans
)
=>
{
athleticUserPool
.
push
({
client
:
res
,
data
:
ans
});
});
}
catch
(
error
)
{
res
.
statusCode
=
403
;
res
.
statusCode
=
403
;
res
.
end
();
res
.
end
();
return
;
return
;
}
}
if
(
pending
)
{
});
let
server
=
servers
[
Math
.
floor
(
Math
.
random
()
*
servers
.
length
)];
let
room_id
=
crypto
.
randomBytes
(
9
).
toString
(
'
base64
'
).
slice
(
0
,
11
).
replace
(
'
+
'
,
'
-
'
).
replace
(
'
/
'
,
'
_
'
);
setInterval
(
update
,
config
.
match
.
timeInterval
);
let
options_buffer
=
new
Buffer
(
6
);
options_buffer
.
writeUInt8
(
4
<<
4
,
1
);
let
checksum
=
0
;
for
(
let
i
=
1
;
i
<
options_buffer
.
length
;
i
++
)
{
checksum
-=
options_buffer
.
readUInt8
(
i
)
}
options_buffer
.
writeUInt8
(
checksum
&
0xFF
,
0
);
for
(
let
client
of
[
res
,
pending
])
{
let
buffer
=
new
Buffer
(
6
);
let
secret
=
parseInt
(
client
.
password
)
%
65535
+
1
;
for
(
let
i
=
0
;
i
<
options_buffer
.
length
;
i
+=
2
)
{
buffer
.
writeUInt16LE
(
options_buffer
.
readUInt16LE
(
i
)
^
secret
,
i
)
}
let
password
=
buffer
.
toString
(
'
base64
'
)
+
room_id
;
let
result
=
JSON
.
stringify
({
"
address
"
:
server
.
address
,
"
port
"
:
server
.
port
,
"
password
"
:
password
});
client
.
writeHead
(
200
,
{
'
Content-Type
'
:
'
application/json
'
,
'
Cache-Control
'
:
'
no-cache
'
});
getUserConfig
({
username
:
"
userA
"
},
(
ans
)
=>
{
client
.
end
(
result
)
entertainUserPool
.
push
({
client
:
{},
data
:
ans
});
}
});
pending
=
null
;
getUserConfig
({
username
:
"
userB
"
},
(
ans
)
=>
{
console
.
log
(
'
matched
'
+
room_id
);
entertainUserPool
.
push
({
client
:
{},
data
:
ans
});
});
}
else
{
pending
=
res
;
res
.
on
(
'
close
'
,
()
=>
{
console
.
log
(
'
connection closed.
'
);
if
(
pending
==
res
)
{
pending
=
null
;
}
})
}
}).
listen
(
80
);
package.json
View file @
2f31c6e8
{
{
"name"
:
"ygopro-match"
,
"name"
:
"ygopro-match"
,
"version"
:
"1.0.0"
,
"version"
:
"0.0.1a"
,
"scripts"
:
{
"author"
:
"zh99998 & pandaiami"
,
"start"
:
"node main.js"
"scripts"
:
{
"start"
:
"node main.js"
,
"test"
:
"node test.js"
},
"dependencies"
:
{
"
request
"
:
"
>=2.74.0
"
,
"
crypto
"
:
"
>=0.0.3
"
}
}
}
}
test.js
0 → 100644
View file @
2f31c6e8
/*
request = require('request');
request.get("http://www.baidu.com", function (err, res, body) {
console.log(err);
console.log(res);
});
*/
const
fs
=
require
(
'
fs
'
);
const
request
=
require
(
'
request
'
);
const
config
=
JSON
.
parse
(
fs
.
readFileSync
(
"
./config.json
"
));
request
.
get
(
"
http://mycard.moe/ygopro/arena/index.php/Home/query?username=userB
"
,
function
(
err
,
res
,
body
)
{
console
.
log
(
err
);
console
.
log
(
body
);
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment