Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.

Commit 7191fa1

Browse files
committed
Started Packet/ByteStream implementation
1 parent 33933e9 commit 7191fa1

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

src/Server/Packets/ByteStream.php

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
namespace CavePHP\Server\Packets;
4+
5+
use CavePHP\Exceptions\CavePHPException;
6+
use CavePHP\Server\Packets\McVars\McVarInt;
7+
8+
class ByteStream
9+
{
10+
public const SIGNED_CHAR = 'c';
11+
public const UNSIGNED_CHAR = 'C';
12+
public const SIGNED_SHORT = 's';
13+
public const UNSIGNED_SHORT = 'S';
14+
public const INT = 'i';
15+
public const LONG = 'l';
16+
public const FLOAT = 'f';
17+
public const DOUBLE = 'd';
18+
private Bytes $data;
19+
20+
private int $position = 0;
21+
22+
public function __construct() {
23+
$this->data = new Bytes;
24+
}
25+
26+
/**
27+
* @throws CavePHPException If length is less than 1
28+
*/
29+
public function read(int $length = 1): string
30+
{
31+
if ($length < 1) {
32+
throw new CavePHPException('Length must be greater than 0');
33+
}
34+
35+
$data = $this->data->getRange($this->position, $length);
36+
$this->move($length);
37+
return $data;
38+
}
39+
40+
public function unpack(string $format, int $length): mixed
41+
{
42+
return unpack($format, $this->read($length))[1];
43+
}
44+
45+
public function getLength(): int
46+
{
47+
return count($this->data);
48+
}
49+
50+
public function readByte(): int
51+
{
52+
return $this->unpack(self::SIGNED_CHAR, 1);
53+
}
54+
55+
public function readUnsignedByte(): int
56+
{
57+
return $this->unpack(self::UNSIGNED_CHAR, 1);
58+
}
59+
60+
public function readShort(): int
61+
{
62+
return $this->unpack(self::SIGNED_SHORT, 2);
63+
}
64+
65+
public function readUnsignedShort(): int
66+
{
67+
return $this->unpack(self::UNSIGNED_SHORT, 2);
68+
}
69+
70+
public function readInt(): int
71+
{
72+
return $this->unpack(self::INT, 4);
73+
}
74+
75+
public function readLong(): int
76+
{
77+
return $this->unpack(self::LONG, 8);
78+
}
79+
80+
public function readFloat(): float
81+
{
82+
return $this->unpack(self::FLOAT, 4);
83+
}
84+
85+
public function readDouble(): float
86+
{
87+
return $this->unpack(self::DOUBLE, 8);
88+
}
89+
90+
public function readBoolean(): bool
91+
{
92+
return $this->readByte() === 1;
93+
}
94+
95+
public function readVarInt(): int
96+
{
97+
return (new McVarInt)->read($this);
98+
}
99+
100+
/**
101+
* @throws CavePHPException
102+
*/
103+
public function write(string $data): void
104+
{
105+
if (isset($this->length) && count($this->data) + strlen($data) > $this->length) {
106+
throw new CavePHPException('Data exceeds the length of the stream');
107+
}
108+
109+
$this->data->push(...str_split($data));
110+
111+
if (!isset($this->length)) {
112+
$this->rewind();
113+
}
114+
}
115+
116+
public function rewind(): void
117+
{
118+
$this->position = 0;
119+
}
120+
121+
/** @return int The new position after moving */
122+
public function move(int $length): int
123+
{
124+
return $this->position += $length;
125+
}
126+
127+
public function getData(): Bytes
128+
{
129+
return $this->data;
130+
}
131+
132+
public static function createWithData(string $data): self
133+
{
134+
$stream = new self;
135+
$stream->write($data);
136+
return $stream;
137+
}
138+
}

src/Server/Packets/Bytes.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace CavePHP\Server\Packets;
4+
5+
use CavePHP\Exceptions\CavePHPException;
6+
use Countable;
7+
use stdClass;
8+
use Stringable;
9+
10+
class Bytes implements Countable, Stringable
11+
{
12+
private stdClass $data;
13+
14+
public function __construct() {
15+
$this->data = new stdClass();
16+
}
17+
18+
/**
19+
* @throws CavePHPException If a given byte is not a string of length 1
20+
*/
21+
public function push(string $byte, string ...$bytes): void
22+
{
23+
$bytes = [$byte, ...$bytes];
24+
25+
foreach ($bytes as $byte) {
26+
if (strlen($byte) !== 1) {
27+
throw new CavePHPException('Byte must be a string of length 1');
28+
}
29+
30+
$this->data->{$this->count()} = $byte;
31+
}
32+
}
33+
34+
public function getByte(int $index): mixed
35+
{
36+
return $this->data->{$index};
37+
}
38+
39+
public function getRange(int $start = 0, int $length = -1): string
40+
{
41+
return substr(implode('', get_object_vars($this->data)), $start, $length);
42+
}
43+
44+
public function count(): int
45+
{
46+
return count(get_object_vars($this->data));
47+
}
48+
49+
public function __toString()
50+
{
51+
return implode('', get_object_vars($this->data));
52+
}
53+
}

src/Server/Packets/PacketType.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace CavePHP\Server\Packets;
4+
5+
use CavePHP\Server\Packets\Uniq\UniqPacket;
6+
use ReflectionClass;
7+
8+
class PacketType
9+
{
10+
private static ?array $maps = null;
11+
12+
public function __construct(
13+
public readonly int $id,
14+
public readonly ClientState $state,
15+
public readonly string $abstraction
16+
) {
17+
}
18+
19+
public static function getMappings(): array {
20+
if (self::$maps === null) {
21+
self::$maps = [];
22+
23+
$addMap = static function (ClientState $state, int $id, string $className): void {
24+
if (!isset(self::$maps[$state->name])) {
25+
self::$maps[$state->name] = [];
26+
}
27+
28+
self::$maps[$state->name][$id] = $className;
29+
};
30+
31+
loopClasses(__DIR__, static function (string $className) use ($addMap): void {
32+
/** @var $className UniqPacket|string */
33+
34+
$reflection = new ReflectionClass($className);
35+
36+
if (in_array(UniqPacket::class, $reflection->getInterfaceNames())) {
37+
$addMap(($className)::getState(), ($className)::getId(), $className);
38+
}
39+
});
40+
}
41+
42+
return self::$maps;
43+
}
44+
45+
46+
public static function createFromIdAndStatus(int $id, ClientState $status): PacketType {
47+
foreach (self::getMappings()[$status->name] ?? [] as $packetId => $className) {
48+
if ($packetId === $id) {
49+
return new self($packetId, $status, $className);
50+
}
51+
}
52+
53+
return new self($id, $status, GenericPacket::class);
54+
}
55+
}

0 commit comments

Comments
 (0)