Minecraft Websocket 服务器

Minecraft Websocket 服务器

Minecraft websocket 服务器

这两天学习了nodejs,于是想着做点什么来实践一下,正好对Minecraft 基岩版的websocket功能比较感兴趣,于是做了一个websocket服务器的demo,可以用来获得游戏内的信息以及执行命令。

准备

在服务器上使用Websocket

不少人已经在bds服务器上尝试过使用wsserver/connect命令了吧?但是这条命令不知道为什么是不能直接使用的,要想使用这条命令我们需要做以下准备。

  • 获得op权限

    只有op可以执行这条命令

  • 修改权限等级

    修改服务器配置文件server.proterties,加入一行op-permission-level = 4,使op拥有与控制台同级的命令权限

做完上述操作之后就可以使用/connect命令了,当然如果只是输入/connect,会提示Command version mismatch,这里我们暂时不管它。

上代码

我使用的使nodejs+typescript的方式创建了这个demo,只有3个文件。注释已经写的很清楚了,有问题就留下评论吧。

app.ts server.ts packet.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//app.ts 用于启动程序,端口可以在这里设置
import {WSServer} from './server';
let server = new WSServer();
server.listen(6800);</code></pre>

//server.ts 包含ws服务器类,用于创建server对象
import { Packet,UnSubscribe,Subscribe,CommandPacket } from './packet/packet';
import { Server } from 'ws';
import {EventEmitter} from 'events';
import { Socket } from 'net';
import {createInterface} from 'readline';
//import {v4} from 'uuid';
let uuid4 = require('uuid/v4');
//创建一个负责输入输出的对象
const rl = createInterface({
input: process.stdin,
output: process.stdout
});

export class WSServer extends EventEmitter{
//strictPropertyInitialization:false
_socket:Server;

public listen(port:number):void{
let server:WSServer = this;

this._socket = new Server({port:port});
//当有客户端连接时回调
console.log("WS开始监听" + port);
this._socket.on("connection",socket => {
console.log("客户端连接");

//发送subscribe包建立监听
registerSubscribe(socket,"PlayerMessage");
registerSubscribe(socket,"BlockPlaced");

//当socket收到信息时回调
socket.on("message", message => {
console.log("接收到客户端的信息");

let data = JSON.parse(message as string);
let msgPurpose = data.header.messagePurpose;
if(msgPurpose == "error"){
console.log("出现错误:", data);
}
else if(msgPurpose == "event"){
console.log(data.body.eventName);
//发送unsubscribe包,取消对该事件的监听,具体表现为服务端只能获得一次客户端的方块放置事件
if (data.body.eventName == "BlockPlaced"){
sendCommand(socket,<code>say 发送unsubscribe包解除对方块放置事件的监听</code>);
unRegisterSubscribe(socket,"BlockPlaced");
}

}
else if(msgPurpose == "commandResponse"){
console.log("命令返回:" + data.body.statusCode);
}

});
//接收到控制台的发送信息事件
server.on("sendMsg",msg=>{
console.log("[sendMsg]:" + msg);
sendCommand(socket,<code>say ${msg}</code>);
});

socket.on("error",err=>{
console.log("建立的socket出现错误" + err.message);
});

socket.on("close", () => {console.log("客户端断开连接")});

});

this._socket.on("error",error=>{
console.log(<code>出现错误${error}</code>);
});

//持续获得用户输入
rl.on('line', (input) => {
console.log(<code>[consoleInput]:${input}</code>);
let [cmd,content] = input.split(":");
if(cmd == "send"){
//触发sendMsg事件
server.emit("sendMsg",content);
}
else if(cmd == "exit"){
process.exit();
}
});

}
}

function registerSubscribe(socket:any,eventName:string):void{
let packet:Subscribe = new Subscribe(eventName);
socket.send(JSON.stringify(packet));
}

function unRegisterSubscribe(socket:any,eventName:string):void{
let packet:UnSubscribe = new UnSubscribe(eventName);
socket.send(JSON.stringify(packet));
}

function sendCommand(socket:any,command:string):void{
let packet:CommandPacket = new CommandPacket(command);
socket.send(JSON.stringify(packet));
}</code></pre>
<pre><code class="language-javascript">//packet 这里是三种数据包的类
let uuid4 = require('uuid/v4');
//数据包
export abstract class Packet{
body:{};
header:{};
}

export class Subscribe extends Packet{
body:{
eventName: string;
};
header:{
requestId: string;
messagePurpose: string;
version: number;
messageType: string;
};

constructor(eventName:string){
super();
this.body = {
eventName:eventName
};

this.header = {
requestId: uuid4(),
messagePurpose: "subscribe",
version: 1,
messageType: "commandRequest"
};
}
}

export class UnSubscribe extends Packet{
body:{
eventName: string;
};
header:{
requestId: string;
messagePurpose: string;
version: number;
messageType: string;
}

constructor(eventName:string,uuid = uuid4()){
super();

this.body = {
eventName: eventName
};

this.header = {
requestId: uuid,
messagePurpose: "unsubscribe",
version: 1,
messageType: "commandRequest"
}

}
}

export class CommandPacket extends Packet{
body:{};
header:{};

constructor(cmd:string){
super();
this.body = {
origin:
{
type: "player"
},
commandLine: cmd,
version: 1
};

this.header = {
requestId: uuid4(),
messagePurpose: "commandRequest",
version: 1,
messageType: "commandRequest"
};
}
}

运行程序

如果想部署一个ws服务器试试看

1
2
3
4
git clone https://github.com/aoyouer/BedrockWsServer.git
cd BedrockWsServer
npm install
node build/app.js
#默认使用6800端口

之后我们在游戏里即可使用 /connect ip:6800 连接ws服务器了,但是不知道为什么,我在自己的电脑(win10)上运行的ws服务器可以通过浏览器访问,但是无法在游戏中连接,在我将程序放到远程的服务器上才正常连接。

在这个demo中,我尝试发送/接收了mc中文wiki ws教程中提到的几种数据包

  • subscribe

    用于监听一个事件,当用户成功连接以后,我们依旧是无法获得用户相关的信息的,我们需要发送subscribe包表明我们对哪些数据"感兴趣",之后客户端才会通过ws发送给我们。在demo中我发送了两个时间的subscribe包,分别是 "PlayerMessage" 表示用户发送信息 与 "BlockPlaced" 表示用户放置方块这两个事件,我没有取出更多信息,感兴趣的朋友可以查看返回的json,并取出详细信息。

  • unsubscribe

    当我们对一个事件不再感兴趣之后,可以发送unsubscribe包解除对此事件的接收,在demo中,我在接收到了一个“BlockPlaced”事件之后即发送该事件的unsubscribe包,因此我们只会接收到一次BlockPlaced事件。

  • commandrequest

    该数据包用于执行命令,在demo中,你只需要在程序运行的后台中输入 send:你想发送的信息 按下回车后,程序即会构建一个执行 say 你想发送的信息的命令的数据包并发送,还会获得该命令执行的结果。

在后台输入exit退出程序。

总结

写这个小程序算是加深了一些我对nodejs的了解,Minecraft基岩版的websocket虽然看上去可以获得很多信息,但是在我看来,它的功能还是相当有限的,因为有几个巨大的限制

  • 只有op在客户端上才能执行,而不是bds服务端直接连接另一个websocket服务端
  • 要想保持连接需要op持续在线

因为这些限制,我暂时想不出什么有趣的应用方向(也许之后我会慢慢扩展这个项目),不过github上依旧有几个比较成熟的基于Minecraft websocket的项目可以了解一下

参考链接

https://minecraft-zh.gamepedia.com/%E6%95%99%E7%A8%8B/WebSocket

https://minecraft-zh.gamepedia.com/%E6%95%99%E7%A8%8B/WebSocket

https://github.com/eDroiid/BedrockWS


评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...