PocketMine-MP 5.41.1 git-fcc6fb5566a921cb669160c90f56fb68f5b29123
Loading...
Searching...
No Matches
TextPacket.php
1<?php
2
3/*
4 * This file is part of BedrockProtocol.
5 * Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/BedrockProtocol>
6 *
7 * BedrockProtocol is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13declare(strict_types=1);
14
15namespace pocketmine\network\mcpe\protocol;
16
17use pmmp\encoding\Byte;
18use pmmp\encoding\ByteBufferReader;
19use pmmp\encoding\ByteBufferWriter;
20use pmmp\encoding\VarInt;
22use function count;
23
25 public const NETWORK_ID = ProtocolInfo::TEXT_PACKET;
26
27 private const CATEGORY_MESSAGE_ONLY = 0;
28 private const CATEGORY_AUTHORED_MESSAGE = 1;
29 private const CATEGORY_MESSAGE_WITH_PARAMETERS = 2;
30
31 public const TYPE_RAW = 0;
32 public const TYPE_CHAT = 1;
33 public const TYPE_TRANSLATION = 2;
34 public const TYPE_POPUP = 3;
35 public const TYPE_JUKEBOX_POPUP = 4;
36 public const TYPE_TIP = 5;
37 public const TYPE_SYSTEM = 6;
38 public const TYPE_WHISPER = 7;
39 public const TYPE_ANNOUNCEMENT = 8;
40 public const TYPE_JSON_WHISPER = 9;
41 public const TYPE_JSON = 10;
42 public const TYPE_JSON_ANNOUNCEMENT = 11;
43
44 public int $type;
45 public bool $needsTranslation = false;
46 public string $sourceName;
47 public string $message;
49 public array $parameters = [];
50 public string $xboxUserId = "";
51 public string $platformChatId = "";
52 public ?string $filteredMessage = null;
53
54 private static function messageOnly(int $type, string $message) : self{
55 $result = new self;
56 $result->type = $type;
57 //TODO: HACK! Empty message crashes or bugs out client in 1.21.130
58 $result->message = $message === "" ? " " : $message;
59 return $result;
60 }
61
65 private static function baseTranslation(int $type, string $key, array $parameters) : self{
66 $result = new self;
67 $result->type = $type;
68 $result->needsTranslation = true;
69 //TODO: HACK! Empty message crashes or bugs out client in 1.21.130
70 $result->message = $key === "" ? " " : $key;
71 $result->parameters = $parameters;
72 return $result;
73 }
74
75 public static function raw(string $message) : self{
76 return self::messageOnly(self::TYPE_RAW, $message);
77 }
78
82 public static function translation(string $key, array $parameters = []) : self{
83 return self::baseTranslation(self::TYPE_TRANSLATION, $key, $parameters);
84 }
85
86 public static function popup(string $message) : self{
87 return self::messageOnly(self::TYPE_POPUP, $message);
88 }
89
93 public static function translatedPopup(string $key, array $parameters = []) : self{
94 return self::baseTranslation(self::TYPE_POPUP, $key, $parameters);
95 }
96
100 public static function jukeboxPopup(string $key, array $parameters = []) : self{
101 return self::baseTranslation(self::TYPE_JUKEBOX_POPUP, $key, $parameters);
102 }
103
104 public static function tip(string $message) : self{
105 return self::messageOnly(self::TYPE_TIP, $message);
106 }
107
108 protected function decodePayload(ByteBufferReader $in) : void{
109 $this->needsTranslation = CommonTypes::getBool($in);
110
111 $category = Byte::readUnsigned($in);
112 $this->type = Byte::readUnsigned($in);
113 switch($this->type){
114 case self::TYPE_CHAT:
115 case self::TYPE_WHISPER:
117 case self::TYPE_ANNOUNCEMENT:
118 if($category !== self::CATEGORY_AUTHORED_MESSAGE){
119 throw new PacketDecodeException("Decoded TextPacket has invalid structure: type {$this->type} requires category CATEGORY_AUTHORED_MESSAGE");
120 }
121 $this->sourceName = CommonTypes::getString($in);
122 $this->message = CommonTypes::getString($in);
123 break;
124 case self::TYPE_RAW:
125 case self::TYPE_TIP:
126 case self::TYPE_SYSTEM:
127 case self::TYPE_JSON_WHISPER:
128 case self::TYPE_JSON:
129 case self::TYPE_JSON_ANNOUNCEMENT:
130 if($category !== self::CATEGORY_MESSAGE_ONLY){
131 throw new PacketDecodeException("Decoded TextPacket has invalid structure: type {$this->type} requires category CATEGORY_MESSAGE_ONLY");
132 }
133 $this->message = CommonTypes::getString($in);
134 break;
135 case self::TYPE_TRANSLATION:
136 case self::TYPE_POPUP:
137 case self::TYPE_JUKEBOX_POPUP:
138 if($category !== self::CATEGORY_MESSAGE_WITH_PARAMETERS){
139 throw new PacketDecodeException("Decoded TextPacket has invalid structure: type {$this->type} requires category CATEGORY_MESSAGE_WITH_PARAMETERS");
140 }
141 $this->message = CommonTypes::getString($in);
142 $count = VarInt::readUnsignedInt($in);
143 for($i = 0; $i < $count; ++$i){
144 $this->parameters[] = CommonTypes::getString($in);
145 }
146 break;
147 }
148
149 $this->xboxUserId = CommonTypes::getString($in);
150 $this->platformChatId = CommonTypes::getString($in);
151 $this->filteredMessage = CommonTypes::readOptional($in, CommonTypes::getString(...));
152 }
153
154 protected function encodePayload(ByteBufferWriter $out) : void{
155 CommonTypes::putBool($out, $this->needsTranslation);
156
157 $category = match ($this->type) {
158 self::TYPE_RAW,
159 self::TYPE_TIP,
160 self::TYPE_SYSTEM,
161 self::TYPE_JSON_WHISPER,
162 self::TYPE_JSON_ANNOUNCEMENT,
163 self::TYPE_JSON => self::CATEGORY_MESSAGE_ONLY,
164
165 self::TYPE_CHAT,
166 self::TYPE_WHISPER,
167 self::TYPE_ANNOUNCEMENT => self::CATEGORY_AUTHORED_MESSAGE,
168
169 self::TYPE_TRANSLATION,
170 self::TYPE_POPUP,
171 self::TYPE_JUKEBOX_POPUP => self::CATEGORY_MESSAGE_WITH_PARAMETERS,
172
173 default => throw new \LogicException("Invalid TextPacket type: $this->type")
174 };
175
176 Byte::writeUnsigned($out, $category);
177 Byte::writeUnsigned($out, $this->type);
178 switch($this->type){
179 case self::TYPE_CHAT:
180 case self::TYPE_WHISPER:
182 case self::TYPE_ANNOUNCEMENT:
183 CommonTypes::putString($out, $this->sourceName);
184 case self::TYPE_RAW:
185 case self::TYPE_TIP:
186 case self::TYPE_SYSTEM:
187 case self::TYPE_JSON_WHISPER:
188 case self::TYPE_JSON:
189 case self::TYPE_JSON_ANNOUNCEMENT:
190 CommonTypes::putString($out, $this->message);
191 break;
192
193 case self::TYPE_TRANSLATION:
194 case self::TYPE_POPUP:
195 case self::TYPE_JUKEBOX_POPUP:
196 CommonTypes::putString($out, $this->message);
197 VarInt::writeUnsignedInt($out, count($this->parameters));
198 foreach($this->parameters as $p){
199 CommonTypes::putString($out, $p);
200 }
201 break;
202 }
203
204 CommonTypes::putString($out, $this->xboxUserId);
205 CommonTypes::putString($out, $this->platformChatId);
206 CommonTypes::writeOptional($out, $this->filteredMessage, CommonTypes::putString(...));
207 }
208
209 public function handle(PacketHandlerInterface $handler) : bool{
210 return $handler->handleText($this);
211 }
212}
static translation(string $key, array $parameters=[])
static jukeboxPopup(string $key, array $parameters=[])
handle(PacketHandlerInterface $handler)
static translatedPopup(string $key, array $parameters=[])