Protocol.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * Utility Class to construct a packet conforming to Minecraft's
  3. * protocol. All data types are BE except VarInt and VarLong.
  4. *
  5. * @see https://wiki.vg/Protocol
  6. */
  7. export class ServerBoundPacket {
  8. private buffer: number[]
  9. protected constructor() {
  10. this.buffer = []
  11. }
  12. public static build(): ServerBoundPacket {
  13. return new ServerBoundPacket()
  14. }
  15. /**
  16. * Packet is prefixed with its data length as a VarInt.
  17. *
  18. * @see https://wiki.vg/Protocol#Packet_format
  19. */
  20. public toBuffer(): Buffer {
  21. const finalizedPacket = new ServerBoundPacket()
  22. finalizedPacket.writeVarInt(this.buffer.length)
  23. finalizedPacket.writeBytes(...this.buffer)
  24. return Buffer.from(finalizedPacket.buffer)
  25. }
  26. public writeBytes(...bytes: number[]): ServerBoundPacket {
  27. this.buffer.push(...bytes)
  28. return this
  29. }
  30. /**
  31. * @see https://wiki.vg/Protocol#VarInt_and_VarLong
  32. */
  33. public writeVarInt(value: number): ServerBoundPacket {
  34. do {
  35. let temp = value & 0b01111111
  36. value >>>= 7
  37. if (value != 0) {
  38. temp |= 0b10000000
  39. }
  40. this.writeBytes(temp)
  41. } while (value != 0)
  42. return this
  43. }
  44. /**
  45. * Strings are prefixed with their length as a VarInt.
  46. *
  47. * @see https://wiki.vg/Protocol#Data_types
  48. */
  49. public writeString(string: string): ServerBoundPacket {
  50. this.writeVarInt(string.length)
  51. for (let i=0; i<string.length; i++) {
  52. this.writeBytes(string.codePointAt(i)!)
  53. }
  54. return this
  55. }
  56. public writeUnsignedShort(short: number): ServerBoundPacket {
  57. const buf = Buffer.alloc(2)
  58. buf.writeUInt16BE(short, 0)
  59. this.writeBytes(...buf)
  60. return this
  61. }
  62. }
  63. /**
  64. * Utility Class to read a client-bound packet conforming to
  65. * Minecraft's protocol. All data types are BE except VarInt
  66. * and VarLong.
  67. *
  68. * @see https://wiki.vg/Protocol
  69. */
  70. export class ClientBoundPacket {
  71. private buffer: number[]
  72. constructor(buffer: Buffer) {
  73. this.buffer = [...buffer]
  74. }
  75. public append(buffer: Buffer): void {
  76. this.buffer.push(...buffer)
  77. }
  78. public readByte(): number {
  79. return this.buffer.shift()!
  80. }
  81. public readBytes(length: number): number[] {
  82. const value = this.buffer.slice(0, length)
  83. this.buffer.splice(0, length)
  84. return value
  85. }
  86. public readVarInt(): number {
  87. let numRead = 0
  88. let result = 0
  89. let read
  90. do {
  91. read = this.readByte()
  92. const value = (read & 0b01111111)
  93. result |= (value << (7 * numRead))
  94. numRead++
  95. if (numRead > 5) {
  96. throw new Error('VarInt is too big')
  97. }
  98. } while ((read & 0b10000000) != 0)
  99. return result
  100. }
  101. public readString(): string {
  102. const length = this.readVarInt()
  103. const data = this.readBytes(length)
  104. let value = ''
  105. for (let i=0; i<data.length; i++) {
  106. value += String.fromCharCode(data[i])
  107. }
  108. return value
  109. }
  110. }
  111. export class ProtocolUtils {
  112. public static getVarIntSize(value: number): number {
  113. let size = 0
  114. do {
  115. value >>>= 7
  116. size++
  117. } while (value != 0)
  118. return size
  119. }
  120. }