Skip to content

Commit 3ac07b1

Browse files
committed
v0.1.0
1 parent b622c82 commit 3ac07b1

12 files changed

Lines changed: 572 additions & 10 deletions

File tree

README.MD

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11

2+
- English
3+
- [中文](README_zh.MD)
4+
25
# pcc
36

4-
A MCDR plugin allows you send MCDR commands privately
7+
A MCDR plugin allows you send MCDR commands privately.
8+
It also support to autocomplete MCDR commands in game without any mods install in the client.
9+
10+
Require `enable_packet_proxy` set to `true` in `loginproxy/config.json`
11+
12+
Only support 1.19.2 atm

README_zh.MD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
- [English](README.MD)
3+
- 中文
4+
5+
# pcc
6+
7+
一个允许你默默发送 MCDR 指令的插件.
8+
也允许你在游戏内自动补全 MCDR 指令
9+
10+
需要将 `loginproxy/config.json` 下的 `enable_packet_proxy` 选项设为 `true`
11+
12+
仅支持 1.19.2, 高版本开发中

lang/en_us.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pcc:
2+
hello: Hello

lang/zh_cn.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pcc:
2+
hello: 你好

mcdreforged.plugin.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{
22
"id": "pcc",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"name": "ProxiedChatConnection",
55
"author": [
66
"zyxkad"
77
],
8-
"description": "A MCDR plugin allows you send MCDR commands privately",
8+
"description": {
9+
"en_us": "A MCDR plugin allows you send MCDR commands privately with autocomplete feature",
10+
"zh_cn": "一个允许你默默发送以及自动补全MCDR指令的插件"
11+
},
912
"link": "https://github.com/kmcsr/pcc_mcdr",
1013
"dependencies": {
1114
"mcdreforged": "^2.14.0",
12-
"loginproxy": ">=0.6.12"
15+
"kpi": "~1.5.1",
16+
"loginproxy": "~0.7.3"
1317
},
1418
"resources": [
1519
"LICENSE",

pcc/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11

22
import mcdreforged.api.all as MCDR
33

4+
from .utils import *
5+
from . import api
6+
47
def on_load(server: MCDR.PluginServerInterface, prev_module):
58
if prev_module is None:
69
log_info('ProxiedChatConnection is on LOAD')
710
else:
811
log_info('ProxiedChatConnection is on RELOAD')
12+
api.on_load(server)
913

1014
def on_unload(server: MCDR.PluginServerInterface):
1115
log_info('ProxiedChatConnection is on UNLOAD')

pcc/api.py

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
2+
import mcdreforged.api.all as MCDR
3+
import mcdreforged.info_reactor.info
4+
from mcdreforged.utils import class_utils
5+
6+
import loginproxy
7+
8+
from .utils import *
9+
from .nodes import *
10+
11+
def on_load(server: MCDR.PluginServerInterface):
12+
server.register_event_listener(loginproxy.ON_POSTLOGIN, login_listener)
13+
server.register_event_listener(loginproxy.ON_PACKET_C2S, c2s_packet_listener)
14+
server.register_event_listener(loginproxy.ON_PACKET_S2C, s2c_packet_listener)
15+
16+
def login_listener(server: MCDR.PluginServerInterface, conn: loginproxy.Conn):
17+
if conn.protocol < loginproxy.Protocol.V1_19_2:
18+
return
19+
conn.send_client(loginproxy.PacketBuffer().write_varint(0x4e).write_bool(True).data)
20+
21+
def c2s_packet_listener(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
22+
if conn.protocol < loginproxy.Protocol.V1_19_2:
23+
return
24+
if packet.id == 0x04:
25+
handle_command_packet(server, conn, packet, cancel)
26+
elif packet.id == 0x05:
27+
handle_chat_packet(server, conn, packet, cancel)
28+
elif packet.id == 0x06:
29+
handle_chat_preview(server, conn, packet, cancel)
30+
elif packet.id == 0x09:
31+
handle_command_suggestion_packet(server, conn, packet, cancel)
32+
33+
def s2c_packet_listener(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
34+
if conn.protocol < loginproxy.Protocol.V1_19_2:
35+
return
36+
if packet.id == 0x15: # Chat suggestion
37+
log_warn('server sent chat suggestion packet')
38+
elif packet.id == 0x0f: # Commands
39+
handle_command_nodes(server, conn, packet, cancel)
40+
elif packet.id == 0x42:
41+
has_motd = packet.read_bool()
42+
motd = packet.read_string() if has_motd else None
43+
has_icon = packet.read_bool()
44+
icon = packet.read_string() if has_icon else None
45+
preview_chat = packet.read_bool()
46+
enforce_secure = packet.read_bool()
47+
48+
preview_chat = True
49+
50+
buf = loginproxy.PacketBuffer()
51+
buf.write_varint(packet.id)
52+
buf.write_bool(has_motd)
53+
if motd is not None:
54+
buf.write_string(motd)
55+
buf.write_bool(has_icon)
56+
if icon is not None:
57+
buf.write_string(icon)
58+
buf.write_bool(preview_chat)
59+
buf.write_bool(enforce_secure)
60+
cancel(buf.data)
61+
62+
def handle_command_packet(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
63+
text = packet.read_string()
64+
handle_text_packet(server, conn, text, cancel)
65+
66+
def handle_chat_packet(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
67+
text = packet.read_string()
68+
handle_text_packet(server, conn, text, cancel)
69+
70+
def handle_chat_preview(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
71+
cancel()
72+
qid = packet.read_int()
73+
text = packet.read_string()
74+
buf = loginproxy.PacketBuffer().write_varint(0x0c)
75+
buf.write_int(qid).write_bool(False)
76+
conn.send_client(buf.data)
77+
78+
if not text.startswith('!!'):
79+
buf = loginproxy.PacketBuffer()
80+
buf.write_varint(0x15)
81+
buf.write_varint(2)
82+
buf.write_varint(0)
83+
conn.send_client(buf.data)
84+
return
85+
86+
command_manager = server._mcdr_server.command_manager
87+
source = PacketCommandSource(server._mcdr_server, conn.name, text)
88+
suggestions = command_manager.suggest_command(text + ' ', source)
89+
90+
buf = loginproxy.PacketBuffer()
91+
buf.write_varint(0x15)
92+
buf.write_varint(2)
93+
buf.write_varint(len(suggestions))
94+
for suggest in suggestions:
95+
buf.write_string(suggest.suggest_input)
96+
conn.send_client(buf.data)
97+
98+
def handle_text_packet(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, text: str, cancel):
99+
if not text.startswith('!!'):
100+
return
101+
source = PacketCommandSource(server._mcdr_server, conn.name, text)
102+
server.execute_command(text, source)
103+
cancel()
104+
105+
def handle_command_suggestion_packet(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
106+
tid = packet.read_varint()
107+
text = packet.read_string()
108+
begin = 0
109+
if text.startswith('/!!'):
110+
begin = 1
111+
text = text[1:]
112+
elif not text.startswith('!!'):
113+
return
114+
cancel()
115+
command_manager = server._mcdr_server.command_manager
116+
source = PacketCommandSource(server._mcdr_server, conn.name, text)
117+
suggestions = command_manager.suggest_command(text, source)
118+
119+
min_existed = min(len(suggest.existed_input) for suggest in suggestions) if len(suggestions) > 0 else len(text)
120+
121+
response = loginproxy.PacketBuffer()
122+
response.write_varint(0x0e)
123+
response.write_varint(tid)
124+
response.write_varint(begin + min_existed)
125+
response.write_varint(len(text) - min_existed)
126+
response.write_varint(len(suggestions))
127+
for suggest in suggestions:
128+
response.write_string(suggest.command[min_existed:])
129+
response.write_bool(False)
130+
conn.send_client(response.data)
131+
132+
def handle_command_nodes(server: MCDR.PluginServerInterface, conn: loginproxy.Conn, packet: loginproxy.PacketReader, cancel):
133+
count = packet.read_varint()
134+
nodes = []
135+
for i in range(count):
136+
nodes.append(Node.parse_from(packet))
137+
root_index = packet.read_varint()
138+
root_node = nodes[root_index]
139+
def add_root_node(node: Node):
140+
root_node.children.append(len(nodes))
141+
nodes.append(node)
142+
143+
node_mcdr = Node(0x02 | 0x04 | 0x10, [], None, '!!MCDR-commands', 5, NodeStringProp.GREEDY_PHRASE, 'minecraft:ask_server')
144+
add_root_node(node_mcdr)
145+
146+
buf = loginproxy.PacketBuffer()
147+
buf.write_varint(packet.id)
148+
buf.write_varint(len(nodes))
149+
for n in nodes:
150+
n.write_to(buf)
151+
buf.write_varint(root_index)
152+
conn.send_client(buf.data)
153+
cancel()
154+
155+
class PacketCommandSource(MCDR.PlayerCommandSource):
156+
def __init__(self, mcdr_server, player: str, chat: str):
157+
super().__init__(mcdr_server, PlayerChatPacketInfo(player, chat, self), player)
158+
159+
self.player: str = player
160+
self.chat: str = chat
161+
162+
@property
163+
def is_player(self) -> bool:
164+
return True
165+
166+
def reply(self, message, *, encoding: str | None = None, **kwargs):
167+
self._mcdr_server.basic_server_interface.tell(self.player, message, encoding=encoding)
168+
169+
def __eq__(self, other) -> bool:
170+
return isinstance(other, PacketCommandSource) and self.player == other.player
171+
172+
def __str__(self):
173+
return 'NetworkPlayer {}'.format(self.player)
174+
175+
def __repr__(self):
176+
return class_utils.represent(self, {
177+
'player': self.player,
178+
'network': True,
179+
})
180+
181+
class PlayerChatPacketInfo(MCDR.Info):
182+
def __init__(self, player: str, chat: str, command_source: PacketCommandSource):
183+
super().__init__(mcdreforged.info_reactor.info.InfoSource.SERVER, chat)
184+
self.content = chat
185+
self.player = player
186+
self._command_source: PacketCommandSource = command_source
187+
188+
def get_command_source(self) -> MCDR.InfoCommandSource:
189+
return self._command_source

0 commit comments

Comments
 (0)