using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Fleck;
using Newtonsoft.Json;
namespace Ddd.Web.Controllers
{
public class WebSocketController : Controller
{
public static List
public static List
public static WebSocketServer server;
/// <summary>
/// 所有角色(固定Y预言家、W女巫、R猎人,n个L狼人、n个M平民)
/// </summary>
public static string strRoles = "YWR";
public static bool Going = false;//游戏进行中
// GET: WebSocket
public ActionResult Index()
{
if (server == null)
{
allSockets = new List<UserSockets>();
server = new WebSocketServer("ws://0.0.0.0:8181");
votes = new List<Vote>();
server.Start(socket =>
{
socket.OnOpen = () =>
{
string uid = socket.ConnectionInfo.Path.Replace("/", "");
if (!allSockets.Any(m => m.UId == uid))
{
allSockets.Add(new UserSockets { UId = uid, Active = true, webSocket = socket });
#region 发送连接返回数据
//推送新连接人信息给已连接的玩家
Result result = new Result() { Command = "openTo", Succeed = true };
//用户,角色
result.Role = new List<UserRole>() { new UserRole { UId = uid } };
allSockets.Where(m => m.UId != uid).ToList().ForEach(m => m.webSocket.Send(JsonConvert.SerializeObject(result)));
result.Command = "openFrom";
//推送所有已连接的玩家给当前连接人
result.Role = (from x in allSockets
select new UserRole { UId = x.UId, Role = x.Role, Name = x.Name }).ToList();
allSockets.FirstOrDefault(m => m.UId == uid).webSocket.Send(JsonConvert.SerializeObject(result));
#endregion
}
};
socket.OnClose = () =>
{
string uid = socket.ConnectionInfo.Path.Replace("/", "");
allSockets.Remove(allSockets.FirstOrDefault(m => m.UId == uid));
//推送离开的连接人信息给已连接的玩家
Result result = new Result() { Command = "remove", Succeed = true };
//用户,角色
result.Role = new List<UserRole>() { new UserRole { UId = uid } };
allSockets.ToList().ForEach(m => m.webSocket.Send(JsonConvert.SerializeObject(result)));
};
socket.OnMessage = message =>
{
string uid = socket.ConnectionInfo.Path.Replace("/", "");
Message o = JsonConvert.DeserializeObject<Message>(message);
switch (o.Command)
{
#region 开始游戏
//如果人数足够直接开始,不够则返回
case "start":
if (!Going)
{
Result result = new Result() { Command = "start" };
//分配用户角色
result.Succeed = AllotUserRole();
if (result.Succeed)
{
Going = true;
//用户,角色
result.Role = (from x in allSockets
select new UserRole { UId = x.UId, Role = x.Role, Name = x.Name }).ToList();
//向所有玩家客户端发送角色信息(内部玩,不考虑被解析)
foreach (var item in allSockets.ToList())
{
result.Msg = item.Role;//返回自己的角色
item.webSocket.Send(JsonConvert.SerializeObject(result));
}
}
else
{
allSockets.FirstOrDefault(m => m.UId == uid).webSocket.Send(JsonConvert.SerializeObject(result));
}
}
break;
#endregion
#region 结束游戏
case "end":
if (Going)
{
foreach (var item in allSockets)
{
item.Active = true;
}
Going = false;
Result result = new Result() { Command = "end", Succeed = true };
allSockets.ToList().ForEach(m => m.webSocket.Send(JsonConvert.SerializeObject(result)));
}
break;
#endregion
#region 狼人选择目标
case "kill":
var kVote = votes.FirstOrDefault(m => m.FromeId == uid);
if (null == kVote)
votes.Add(new Vote { FromeId = uid, ToId = o.Do });
else
kVote.ToId = o.Do;
Game kill = new Game() { Command = "kill", Target = uid + "|" + o.Do };
//向所有狼队友发送袭击的目标
allSockets.Where(m => m.Role == "L").ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(kill)));
break;
#endregion
#region 狼人交谈
case "talk":
Game talk = new Game() { Command = "talk", Target = o.Do };
//向所有狼队友发送袭击的目标
allSockets.Where(m => m.Role == "L").ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(talk)));
break;
#endregion
#region 判断投票杀死的玩家
case "selected":
var selectedUser = votes.GroupBy(v => v.ToId).Select(g => (new { name = g.Key, count = g.Count() })).OrderByDescending(m => m.count).FirstOrDefault();
if (null != selectedUser)
{
Game selected = new Game() { Command = "die", Target = selectedUser.name };
var selecteder = allSockets.FirstOrDefault(m => m.UId == selected.Target);
selecteder.Active = false;
//重置投票列表
votes = new List<Vote>();
//向所有玩家发送死掉的目标
allSockets.ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(selected)));
}
break;
#endregion
#region 所有人投票
case "vote":
var aVote = votes.FirstOrDefault(m => m.FromeId == uid);
if (null == aVote)
votes.Add(new Vote { FromeId = uid, ToId = o.Do });
else
aVote.ToId = o.Do;
Game vote = new Game() { Command = "vote", Target = o.Do };
//向所有玩家发送选择的目标
allSockets.Where(m => m.UId != uid).ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(vote)));
break;
#endregion
#region 杀死玩家(狼人袭击、女巫毒死、投票、猎人带走)
case "die":
Game die = new Game() { Command = "die", Target = o.Do };
var dier = allSockets.FirstOrDefault(m => m.UId == die.Target);
dier.Active = false;
//向所有玩家发送死掉的目标
allSockets.ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(die)));
break;
#endregion
#region 救活玩家
case "live":
Game live = new Game() { Command = "live", Target = o.Do };
var liver = allSockets.FirstOrDefault(m => m.UId == live.Target);
liver.Active = true;
//向所有玩家发送救活的目标
allSockets.ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(live)));
break;
#endregion
#region 查验玩家
case "check":
Game check = new Game() { Command = "check" };
var checker = allSockets.FirstOrDefault(m => m.UId == o.Do);
check.Target = checker.Role;
//向预言家发送查验的身份
allSockets.ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(check)));
break;
#endregion
#region 昵称
case "name":
var user = allSockets.FirstOrDefault(m => m.UId == uid);
user.Name = o.Do;
Result name = new Result() { Command = "name", Succeed = true };
name.Role = new List<UserRole>() { new UserRole {
UId=user.UId,
Name=user.Name,
Role=user.Role
} };
allSockets.ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(name)));
break;
#endregion
#region 判断是否满足继续的条件
case "continue":
if (Going)
{
//所有幸存者
var survival = allSockets.Where(m => m.Active).ToList();
if (survival.Count > 0)
{
Message isContinue = new Message() { Command = "continue" };
if (!survival.Any(m => m.Role == "M") || !survival.Any(m => m.Role != "L" && m.Role != "M"))
isContinue.Do = "狼人获胜";
if (!survival.Any(m => m.Role == "L"))
isContinue.Do = "好人获胜";
if (!string.IsNullOrEmpty(isContinue.Do))
{
allSockets.ToList().ForEach(m => m.webSocket.Send(JsonConvert.SerializeObject(isContinue)));
Going = false;
}
}
}
break;
#endregion
#region 日夜交替
case "replace":
if (Going)
{
Game replace = new Game() { Command = "replace", Target = o.Do };
//向所有人发送日夜交替
allSockets.Where(m => m.Active).ToList().ForEach(s => s.webSocket.Send(JsonConvert.SerializeObject(replace)));
}
break;
#endregion
default:
break;
}
};
});
}
return Content("服务激活");
}
public class Message
{
public string Command { get; set; }
public string Do { get; set; }
}
public class Result
{
public string Command { get; set; }
public bool Succeed { get; set; }
public string Msg { get; set; }
public List<UserRole> Role { get; set; }
}
public class Game
{
public string Command { get; set; }
/// <summary>
/// 目标
/// </summary>
public string Target { get; set; }
}
public class UserRole
{
/// <summary>
/// 用户Id
/// </summary>
public string UId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 角色
/// </summary>
public string Role { get; set; }
}
public class UserSockets
{
/// <summary>
/// 用户Id
/// </summary>
public string UId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 角色
/// </summary>
public string Role { get; set; }
/// <summary>
/// 活着
/// </summary>
public bool Active { get; set; }
/// <summary>
/// websocket
/// </summary>
public IWebSocketConnection webSocket { get; set; }
}
public class Vote
{
public string FromeId { get; set; }
public string ToId { get; set; }
}
/// <summary>
/// 分配用户角色
/// </summary>
/// <returns></returns>
public bool AllotUserRole()
{
int num = allSockets.Count;
if (num < 5)
return false;
else
{
int l = (num - 3) / 2;
int m = (num - 3) % 2;
if (m != 0)
strRoles = String.Concat(strRoles, "L");
for (int i = 0; i < l; i++)
{
strRoles = String.Concat(strRoles, "LM");
}
}
List<char> mylist = new List<char>();
mylist.AddRange(strRoles.ToCharArray());
Random r = new Random(Guid.NewGuid().GetHashCode());//生成随机生成器
foreach (var item in allSockets)
{
int nIndex = r.Next(0, mylist.Count);
item.Role = mylist[nIndex].ToString();
item.Active = true;
mylist.Remove(mylist[nIndex]);
}
strRoles = "YWR";
return true;
}
[HttpPost]
public JsonResult Test(int num)
{
if (num < 5)
return Json(new { result = false });
else
{
int l = (num - 3) / 2;
int m = (num - 3) % 2;
if (m != 0)
strRoles = String.Concat(strRoles, "L");
for (int i = 0; i < l; i++)
{
strRoles = String.Concat(strRoles, "LM");
}
}
string msg = string.Empty;
List<char> mylist = new List<char>();
mylist.AddRange(strRoles.ToCharArray());
Random r = new Random(Guid.NewGuid().GetHashCode());//生成随机生成器
for (int i = 0; i < num; i++)
{
int nIndex = r.Next(0, mylist.Count);
msg += mylist[nIndex].ToString();
mylist.Remove(mylist[nIndex]);
}
strRoles = "YWR";
return Json(new { result = true, msg = msg });
}
}
}
<head> <meta charset="utf-8"> <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0" /> <title>title</title> <link rel="stylesheet" type="text/css" href="../css/api.css" /> <style> html, body { height: 100%; background-color: #ddd; color: white; } .person {
height: 40px;
line-height: 40px;
padding: 1px;
position: relative;
}
.left {
40%;
float: left;
background-color: #d67070;
line-height: 30px;
padding: 5px 0;
height: 30px;
}
.left .head {
30px;
height: 30px;
text-align: center;
background-color: #544141;
border-radius: 20px;
font-size: 16px;
margin-left: 10px;
}
.kill .left,
.kill .right {
background-color: red;
}
.kill .head {
background-color: white;
color: red;
}
.left .label {
float: right;
padding: 0 2px;
}
.left .state {
color: white;
background-color: red;
20px;
height: 20px;
line-height: 20px;
font-size: 12px;
text-align: center;
position: absolute;
top: 0;
left: 0;
}
.right {
60%;
float: left;
background-color: #d67070;
line-height: 30px;
padding: 5px 0;
height: 30px;
}
.right a {
18%;
background-color: red;
color: white;
text-align: center;
float: left;
border-radius: 5px;
margin: 0 1%;
}
.bottom {
text-align: center;
position: fixed;
100%;
bottom: 0;
}
.btn {
padding: 10px 0;
98%;
background-color: red;
color: white;
height: 30px;
line-height: 30px;
float: left;
margin: 5px 1%;
}
a:active {
background-color: #bb0909;
}
.die .right a {
background-color: #ddd;
}
.hide {
display: none;
}
.green {
background-color: green !important;
}
</style>
</head>
<body>
<div id="content" style="height:80%;">
<!-- <div id="p1" class="person">
<div class="left">
<em class="head">王</em>
<em class="label">纪</em>
<em class="label">沈</em>
<em class="label">萌</em>
<em class="state">民</em>
</div>
<div class="right">
</div>
</div>
<div id="p2" class="person kill die">
<div class="left">
<em class="head">王</em>
<em class="label">纪</em>
<em class="label">沈</em>
<em class="label">萌</em>
<em class="state">民</em>
</div>
<div class="right">
<a href="javascript:;">投</a>
<a href="javascript:;">查</a>
<a href="javascript:;">毒</a>
<a href="javascript:;">救</a>
<a href="javascript:;">杀</a>
</div>
</div> -->
</div>
<div class="bottom">
<a id="btnStart" href="javascript:;" class="btn hide" onclick="start();">开始</a>
<a id="btnEnd" href="javascript:;" class="btn hide" onclick="end();">结束</a>
<a id="btnGo" href="javascript:;" class="btn hide" onclick="go();">检票</a>
</div>
</body>
<script type="text/javascript" src="../script/api.js"></script>
<script type="text/javascript" src="../script/zepto.js"></script>
<script type="text/javascript">
var userId, websocket, audio, roles, sf, bt = dy = jy = cy = dz = zc = true; //玩家,身份,白天=毒药=解药=查验=带走=主持
apiready = function() {
userId = api.deviceId;
if (userId == "861839037046314") {
$api.removeCls($api.byId('btnStart'), 'hide');
zc = true;
} else {
zc = false;
}
audio = api.require('audio');
loadStock();
};
function loadStock() {
var wsServer = 'ws://121.40.84.132:8181/' + userId;
websocket = new WebSocket(wsServer);
//onopen监听连接打开
websocket.onopen = function(evt) {
// api.toast({
// msg: '连接成功',
// duration: 2000,
// location: 'bottom'
// });
nameTip();
}
//onmessage 监听服务器数据推送
websocket.onmessage = function(evt) {
var res = JSON.parse(evt.data);
console.log(JSON.stringify(res));
if (res.Command == "openFrom") {
for (var i = 0; i < res.Role.length; i++) {
$api.append($api.byId('content'), '<div id="p' + res.Role[i].UId +
'" class="person"><div class="left"><em class="head">' + res.Role[i].Name +
'</em></div><div class="right"></div></div>'
);
}
} else if (res.Command == "openTo") {
$api.append($api.byId('content'), '<div id="p' + res.Role[0].UId +
'" class="person"><div class="left"><em class="head">' + res.Role[0].Name +
'</em></div><div class="right"></div></div>'
);
} else if (res.Command == "remove") { //玩家离开房间
$api.remove($api.byId('p' + res.Role[0].UId));
} else if (res.Command == "name") {
$api.text($api.dom('#p' + res.Role[0].UId + ' .left .head'), res.Role[0].Name);
} else if (res.Command == "start") {
if (res.Succeed) {
roles = res.Role;
if (zc) {
$api.addCls($api.byId('btnStart'), 'hide');
$api.removeCls($api.byId('btnEnd'), 'hide');
$api.removeCls($api.byId('btnGo'), 'hide');
}
sf = res.Msg; //身份
for (var i = 0; i < roles.length; i++) {
if (roles[i].UId == userId) {
$api.append($api.dom('#p' + roles[i].UId + ' .left'), '<em class="state green">' + sf + '</em>');
} else {
if (sf == roles[i].Role == "L") { //狼人显示队友
$api.append($api.dom('#p' + roles[i].UId + ' .left'), '<em class="state">' + roles[i].Role + '</em>');
} else {
//隐藏所有身份标签,预言家查验直接前台操作
$api.append($api.dom('#p' + roles[i].UId + ' .left'), '<em class="state hide">' + roles[i].Role + '</em>');
}
}
//根据自己的角色添加按钮
var strBtn = '';
if (sf == "L") {
strBtn = '<a href="javascript:;" onclick="kill(' + roles[i].UId + ');">杀</a>';
} else if (sf == "Y") {
strBtn = '<a href="javascript:;" onclick="check(' + roles[i].UId + ')">查</a>';
} else if (sf == "W") {
strBtn = '<a href="javascript:;" onclick="die(' + roles[i].UId + ');">毒</a><a href="javascript:;" onclick="live(' + roles[i].UId + ');">救</a>';
} else if (sf == "R") {
strBtn = '<a class="gun hide" href="javascript:;" onclick="die(' + roles[i].UId + ');">带</a>';
}
$api.html($api.dom('#p' + roles[i].UId + ' .right'), '<a href="javascript:;" onclick="vote(' + roles[i].UId + ');">投</a>' + strBtn);
}
//发送日夜交替通知
websocket.send("{"Command":"replace","Do":"" + !bt + ""}");
} else {
api.toast({
msg: '人数不足或正在进行',
duration: 2000,
location: 'bottom'
});
}
} else if (res.Command == "end") {
if (zc) {
$api.removeCls($api.byId('btnStart'), 'hide');
$api.addCls($api.byId('btnEnd'), 'hide');
$api.addCls($api.byId('btnGo'), 'hide');
}
$('.left .state').remove();
$('.left .label').remove();
$('.right').html('');
} else if (res.Command == "continue") {
api.alert({
title: '游戏结束',
msg: res.Do,
}, function(ret, err) {
end();
});
} else if (res.Command == "kill") {
var target = res.Target.split("|");
//如果是变更就删除原有的
var label = $api.byId('#l' + target[0]);
if (null != label) {
$api.remove(label);
}
$api.append($api.dom('#p' + target[1] + ' .left'), '<em id="#l' + target[0] + '" class="label">杀</em>');
} else if (res.Command == "die") {
//如果晚上杀死,且玩家为有解药的女巫,被杀玩家显示kill;否则,被杀玩家显示die
if (!bt && sf == "W" && jy) {
$api.addCls($api.byId('p' + res.Target), 'kill');
} else {
$api.addCls($api.byId('p' + res.Target), 'die');
//如果被杀玩家为猎人,可以开枪带走一个
if (sf == "R" && res.Target == userId) {
var gun = $api.domAll('.person .right .gun');
for (var j = 0; j < gun.length; j++) {
$api.removeCls(gun[j], 'hide');
}
}
}
} else if (res.Command == "live") {
if ($api.hasCls($api.dom('#p' + res.Target), 'die')) {
$api.removeCls($api.dom('#p' + res.Target), 'die');
}
if ($api.hasCls($api.dom('#p' + res.Target), 'kill')) {
$api.removeCls($api.dom('#p' + res.Target), 'kill');
}
} else if (res.Command == "replace") {
if (res.Target=="true") {
bt = true;
} else {
cy = true;
bt = false;
//调用语音
audioPlay(1, 10000);
}
}
}
//监听连接关闭
websocket.onclose = function(evt) {
console.log("Disconnected");
};
//监听连接错误信息
websocket.onerror = function(evt, e) {
console.log('Error occured: ' + evt.data);
};
}
//开始游戏
function start() {
websocket.send("{"Command":"start","Do":""}");
}
//结束游戏
function end() {
websocket.send("{"Command":"end","Do":""}");
}
function nameTip() {
api.prompt({
title: '确认昵称',
msg: '请输入一个字的昵称',
text: '猪',
buttons: ['确定', '取消']
}, function(ret, err) {
if (ret.buttonIndex == 1 && ret.text.length == 1) {
websocket.send("{"Command":"name","Do":"" + ret.text + ""}");
} else {
nameTip();
}
});
}
//投票
function vote(uid) {
if (bt) {
websocket.send("{"Command":"vote","Do":"" + uid + ""}");
} else {
api.toast({
msg: '无效操作',
duration: 2000,
location: 'bottom'
});
}
}
//查验
function check(uid) {
if (sf == "Y" && !bt && cy) {
$api.removeCls($api.dom('#p' + uid + ' .left .state'), 'hide');
cy = false;
} else {
api.toast({
msg: '无效操作',
duration: 2000,
location: 'bottom'
});
}
}
//狼杀
function kill(uid) {
if (sf == "L" && !bt) {
// $api.append($api.dom('#p' + uid + ' .left'), '<em class="label">萌</em>');
websocket.send("{"Command":"kill","Do":"" + uid + ""}");
} else {
api.toast({
msg: '无效操作',
duration: 2000,
location: 'bottom'
});
}
}
//杀死
function die(uid) {
if (sf == "L" && bt && dz) {
websocket.send("{"Command":"die","Do":"" + uid + ""}");
dz = false;
} else if (sf == "W" && dy && !bt) {
websocket.send("{"Command":"die","Do":"" + uid + ""}");
dy = false;
} else {
api.toast({
msg: '无效操作',
duration: 2000,
location: 'bottom'
});
}
}
//救活
function live(uid) {
if (sf == "W" && !bt && jy) {
websocket.send("{"Command":"live","Do":"" + uid + ""}");
jy = false;
// $api.removeCls($api.dom('#p' + uid), 'die');
} else {
api.toast({
msg: '无效操作',
duration: 2000,
location: 'bottom'
});
}
}
// function game() {
// //狼人选择目标
// //判断狼人的目标发送die
// // selected();
// //调用女巫
// //女巫用药
// //救人
// //毒死
// //判断有戏是否继续
// //预言家查验
// // bt=true;
// //玩家投票
// // selected();
// }
//判断狼人选择击杀的目标/投票杀死的目标
function selected() {
websocket.send("{"Command":"selected","Do":""}");
}
function go() {
//判断投票杀死的玩家
selected();
api.toast({
msg: '请稍等...',
duration: 2000,
location: 'bottom'
});
setTimeout('audioPlay(1,10);', 5000);
}
//播放语音(1:天黑请闭眼,狼人请睁眼 2:狼人请闭眼,女巫请睁眼 3:女巫请闭眼,预言家请睁眼 4:预言家请闭眼...天亮了请睁眼)
function audioPlay(index, seconds) {
//播放女巫出场语音前判断狼人的击杀目标
if (index == 2) {
selected();
}
audio.play({
path: 'widget://recorder/a' + index + '.mp3'
}, function(ret, err) {
if (ret.complete) {
if (index < 4) {
index++;
setTimeout('audioPlay(' + index + ',5000);', seconds);
} else {
//判断是否继续游戏
websocket.send("{"Command":"continue","Do":""}");
//白天
websocket.send("{"Command":"replace","Do":"true"}");
}
}
});
}