Fully implemented Map Data packet.

This commit is contained in:
Milutinke 2022-09-18 00:18:27 +02:00
parent 59e02c2da9
commit f47c240920
6 changed files with 175 additions and 61 deletions

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MinecraftClient.Protocol.Handlers;
namespace MinecraftClient.Mapping
{
public class MapIcon
{
public MapIconType Type { set; get; }
public byte X { set; get; }
public byte Z { set; get; }
public byte Direction { set; get; }
public string? DisplayName { set; get; } = null;
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MinecraftClient.Mapping
{
public enum MapIconType
{
White_Arrow = 0,
Green_Arrow,
Red_Arrow,
Blue_Arrow,
White_Cross,
Red_Pointer,
White_Circle,
Small_White_Circle,
Mansion,
Temple,
White_Banner,
Orange_Banner,
Magenta_Banner,
Light_Blue_Banner,
Yellow_Banner,
Lime_Banner,
Pink_Banner,
Gray_Banner,
Light_Gray_Banner,
Cyan_Banner,
Purple_Banner,
Blue_Banner,
Brown_Banner,
Green_Banner,
Red_Banner,
Black_Banner,
Treasure_Marker
}
}

View file

@ -3063,16 +3063,22 @@ namespace MinecraftClient
} }
/// <summary> /// <summary>
/// Called map data /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
/// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
/// </summary> /// </summary>
/// <param name="mapid"></param> /// <param name="mapid">Map ID of the map being modified</param>
/// <param name="scale"></param> /// <param name="scale">A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)</param>
/// <param name="trackingposition"></param> /// <param name="trackingposition">Specifies whether player and item frame icons are shown </param>
/// <param name="locked"></param> /// <param name="locked">True if the map has been locked in a cartography table </param>
/// <param name="iconcount"></param> /// <param name="icons">A list of MapIcon objects of map icons, send only if trackingPosition is true</param>
public void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount) /// <param name="columnsUpdated">Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)</param>
/// <param name="rowsUpdated">Map height</param>
/// <param name="mapCoulmnX">x offset of the westernmost column</param>
/// <param name="mapRowZ">z offset of the northernmost row</param>
/// <param name="colors">a byte array of colors on the map</param>
public void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List<MapIcon> icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapCoulmnZ, byte[]? colors)
{ {
DispatchBotEvent(bot => bot.OnMapData(mapid, scale, trackingposition, locked, iconcount)); DispatchBotEvent(bot => bot.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapCoulmnZ, colors));
} }
/// <summary> /// <summary>

View file

@ -156,7 +156,7 @@ namespace MinecraftClient.Protocol.Handlers
entityPalette = new EntityPalette114(); entityPalette = new EntityPalette114();
else if (protocolVersion >= MC_1_13_Version) else if (protocolVersion >= MC_1_13_Version)
entityPalette = new EntityPalette113(); entityPalette = new EntityPalette113();
else else
entityPalette = new EntityPalette112(); entityPalette = new EntityPalette112();
// Item palette // Item palette
@ -173,7 +173,7 @@ namespace MinecraftClient.Protocol.Handlers
itemPalette = new ItemPalette1162(); itemPalette = new ItemPalette1162();
else if (protocolVersion >= MC_1_16_1_Version) else if (protocolVersion >= MC_1_16_1_Version)
itemPalette = new ItemPalette1161(); itemPalette = new ItemPalette1161();
else else
itemPalette = new ItemPalette115(); itemPalette = new ItemPalette115();
// MessageType // MessageType
@ -586,7 +586,7 @@ namespace MinecraftClient.Protocol.Handlers
byte[] bodyDigest = dataTypes.ReadNextByteArray(packetData); byte[] bodyDigest = dataTypes.ReadNextByteArray(packetData);
bool verifyResult; bool verifyResult;
if (!isOnlineMode) if (!isOnlineMode)
verifyResult = false; verifyResult = false;
else if (senderUUID == handler.GetUserUuid()) else if (senderUUID == handler.GetUserUuid())
@ -594,7 +594,7 @@ namespace MinecraftClient.Protocol.Handlers
else else
{ {
PlayerInfo? player = handler.GetPlayerInfo(senderUUID); PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
if (player == null || !player.IsMessageChainLegal()) if (player == null || !player.IsMessageChainLegal())
verifyResult = false; verifyResult = false;
else else
@ -783,7 +783,7 @@ namespace MinecraftClient.Protocol.Handlers
case PacketTypesIn.MapData: case PacketTypesIn.MapData:
int mapid = dataTypes.ReadNextVarInt(packetData); int mapid = dataTypes.ReadNextVarInt(packetData);
byte scale = dataTypes.ReadNextByte(packetData); byte scale = dataTypes.ReadNextByte(packetData);
bool trackingposition = protocolVersion >= MC_1_17_Version ? false : dataTypes.ReadNextBool(packetData); bool trackingPosition = protocolVersion >= MC_1_17_Version ? false : dataTypes.ReadNextBool(packetData);
bool locked = false; bool locked = false;
if (protocolVersion >= MC_1_14_Version) if (protocolVersion >= MC_1_14_Version)
{ {
@ -791,10 +791,48 @@ namespace MinecraftClient.Protocol.Handlers
} }
if (protocolVersion >= MC_1_17_Version) if (protocolVersion >= MC_1_17_Version)
{ {
trackingposition = dataTypes.ReadNextBool(packetData); trackingPosition = dataTypes.ReadNextBool(packetData);
} }
int iconcount = dataTypes.ReadNextVarInt(packetData);
handler.OnMapData(mapid, scale, trackingposition, locked, iconcount); int iconcount = 0;
List<MapIcon> icons = new();
if (trackingPosition)
{
iconcount = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < iconcount; i++)
{
MapIcon mapIcon = new();
mapIcon.Type = (MapIconType)dataTypes.ReadNextVarInt(packetData);
mapIcon.X = dataTypes.ReadNextByte(packetData);
mapIcon.Z = dataTypes.ReadNextByte(packetData);
mapIcon.Direction = dataTypes.ReadNextByte(packetData);
bool mapIconHasDisplayName = dataTypes.ReadNextBool(packetData);
if (mapIconHasDisplayName)
mapIcon.DisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData));
icons.Add(mapIcon);
}
}
byte columnsUpdated = dataTypes.ReadNextByte(packetData); // width
byte rowsUpdated = 0; // height
byte mapCoulmnX = 0;
byte mapRowZ = 0;
byte[]? colors = null;
if (columnsUpdated > 0)
{
rowsUpdated = dataTypes.ReadNextByte(packetData); // height
mapCoulmnX = dataTypes.ReadNextByte(packetData);
mapRowZ = dataTypes.ReadNextByte(packetData);
colors = dataTypes.ReadNextByteArray(packetData);
}
handler.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapRowZ, colors);
break; break;
case PacketTypesIn.TradeList: case PacketTypesIn.TradeList:
if ((protocolVersion >= MC_1_14_Version) && (handler.GetInventoryEnabled())) if ((protocolVersion >= MC_1_14_Version) && (handler.GetInventoryEnabled()))
@ -1365,7 +1403,7 @@ namespace MinecraftClient.Protocol.Handlers
{ {
int entityid = dataTypes.ReadNextVarInt(packetData); int entityid = dataTypes.ReadNextVarInt(packetData);
Inventory.Effects effect = Effects.Speed; Inventory.Effects effect = Effects.Speed;
int effectId = protocolVersion >= MC_1_18_2_Version ? int effectId = protocolVersion >= MC_1_18_2_Version ?
dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextByte(packetData); dataTypes.ReadNextVarInt(packetData) : dataTypes.ReadNextByte(packetData);
if (Enum.TryParse(effectId.ToString(), out effect)) if (Enum.TryParse(effectId.ToString(), out effect))
{ {
@ -1657,7 +1695,8 @@ namespace MinecraftClient.Protocol.Handlers
{ {
netMain.Item2.Cancel(); netMain.Item2.Cancel();
} }
if (netReader != null){ if (netReader != null)
{
netReader.Item2.Cancel(); netReader.Item2.Cancel();
socketWrapper.Disconnect(); socketWrapper.Disconnect();
} }
@ -2192,7 +2231,7 @@ namespace MinecraftClient.Protocol.Handlers
DateTimeOffset timeNow = DateTimeOffset.UtcNow; DateTimeOffset timeNow = DateTimeOffset.UtcNow;
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds())); fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
List<Tuple<string, string>>? needSigned = List<Tuple<string, string>>? needSigned =
playerKeyPair != null ? CollectCommandArguments(command) : null; // List< Argument Name, Argument Value > playerKeyPair != null ? CollectCommandArguments(command) : null; // List< Argument Name, Argument Value >
if (needSigned == null || needSigned!.Count == 0) if (needSigned == null || needSigned!.Count == 0)
{ {

View file

@ -112,7 +112,7 @@ namespace MinecraftClient.Protocol
/// This method is called when the protocol handler receives a title /// This method is called when the protocol handler receives a title
/// </summary> /// </summary>
void OnTitle(int action, string titletext, string subtitletext, string actionbartext, int fadein, int stay, int fadeout, string json); void OnTitle(int action, string titletext, string subtitletext, string actionbartext, int fadein, int stay, int fadeout, string json);
/// <summary> /// <summary>
/// Called when receiving a connection keep-alive from the server /// Called when receiving a connection keep-alive from the server
/// </summary> /// </summary>
@ -216,7 +216,7 @@ namespace MinecraftClient.Protocol
/// </summary> /// </summary>
/// <param name="entity">Spawned entity</param> /// <param name="entity">Spawned entity</param>
void OnSpawnEntity(Entity entity); void OnSpawnEntity(Entity entity);
/// <summary> /// <summary>
/// Called when an entity has spawned /// Called when an entity has spawned
/// </summary> /// </summary>
@ -224,7 +224,7 @@ namespace MinecraftClient.Protocol
/// <param name="slot">Equipment slot. 0: main hand, 1: off hand, 25: armor slot (2: boots, 3: leggings, 4: chestplate, 5: helmet)/param> /// <param name="slot">Equipment slot. 0: main hand, 1: off hand, 25: armor slot (2: boots, 3: leggings, 4: chestplate, 5: helmet)/param>
/// <param name="item">Item/param> /// <param name="item">Item/param>
void OnEntityEquipment(int entityid, int slot, Item item); void OnEntityEquipment(int entityid, int slot, Item item);
/// <summary> /// <summary>
/// Called when a player spawns or enters the client's render distance /// Called when a player spawns or enters the client's render distance
/// </summary> /// </summary>
@ -312,7 +312,7 @@ namespace MinecraftClient.Protocol
/// <param name="entityID">Entity ID</param> /// <param name="entityID">Entity ID</param>
/// <param name="health">The health of the entity</param> /// <param name="health">The health of the entity</param>
void OnEntityHealth(int entityID, float health); void OnEntityHealth(int entityID, float health);
/// <summary> /// <summary>
/// Called when entity metadata or metadata changed. /// Called when entity metadata or metadata changed.
/// </summary> /// </summary>
@ -334,14 +334,14 @@ namespace MinecraftClient.Protocol
/// <param name="uuid">Affected player's UUID</param> /// <param name="uuid">Affected player's UUID</param>
/// <param name="gamemode">New game mode</param> /// <param name="gamemode">New game mode</param>
void OnGamemodeUpdate(Guid uuid, int gamemode); void OnGamemodeUpdate(Guid uuid, int gamemode);
/// <summary> /// <summary>
/// Called when a player's latency has changed /// Called when a player's latency has changed
/// </summary> /// </summary>
/// <param name="uuid">Affected player's UUID</param> /// <param name="uuid">Affected player's UUID</param>
/// <param name="latency">latency</param> /// <param name="latency">latency</param>
void OnLatencyUpdate(Guid uuid, int latency); void OnLatencyUpdate(Guid uuid, int latency);
/// <summary> /// <summary>
/// Called when Experience bar is updated /// Called when Experience bar is updated
/// </summary> /// </summary>
@ -356,17 +356,23 @@ namespace MinecraftClient.Protocol
/// <remarks>Used for setting player slot after joining game</remarks> /// <remarks>Used for setting player slot after joining game</remarks>
/// <param name="slot"></param> /// <param name="slot"></param>
void OnHeldItemChange(byte slot); void OnHeldItemChange(byte slot);
/// <summary> /// <summary>
/// Called map data /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
/// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
/// </summary> /// </summary>
/// <param name="mapid"></param> /// <param name="mapid">Map ID of the map being modified</param>
/// <param name="scale"></param> /// <param name="scale">A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)</param>
/// <param name="trackingposition"></param> /// <param name="trackingposition">Specifies whether player and item frame icons are shown </param>
/// <param name="locked"></param> /// <param name="locked">True if the map has been locked in a cartography table </param>
/// <param name="iconcount"></param> /// <param name="icons">A list of MapIcon objects of map icons, send only if trackingPosition is true</param>
void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount); /// <param name="columnsUpdated">Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)</param>
/// <param name="rowsUpdated">Map height</param>
/// <param name="mapCoulmnX">x offset of the westernmost column</param>
/// <param name="mapRowZ">z offset of the northernmost row</param>
/// <param name="colors">a byte array of colors on the map</param>
void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List<MapIcon> icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapRowZ, byte[]? colors);
/// <summary> /// <summary>
/// Called when the Player entity ID has been received from the server /// Called when the Player entity ID has been received from the server
/// </summary> /// </summary>
@ -393,7 +399,7 @@ namespace MinecraftClient.Protocol
/// <param name="objectivevalue">Only if mode is 0 or 2. The text to be displayed for the score</param> /// <param name="objectivevalue">Only if mode is 0 or 2. The text to be displayed for the score</param>
/// <param name="type">Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".</param> /// <param name="type">Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".</param>
void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type); void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type);
/// <summary> /// <summary>
/// Called when DisplayScoreboard /// Called when DisplayScoreboard
/// </summary> /// </summary>

View file

@ -145,7 +145,7 @@ namespace MinecraftClient
/// <param name="text">Text from the server</param> /// <param name="text">Text from the server</param>
/// <param name="json">Raw JSON from the server. This parameter will be NULL on MC 1.5 or lower!</param> /// <param name="json">Raw JSON from the server. This parameter will be NULL on MC 1.5 or lower!</param>
public virtual void GetText(string text, string? json) { } public virtual void GetText(string text, string? json) { }
/// <summary> /// <summary>
/// Is called when the client has been disconnected fom the server /// Is called when the client has been disconnected fom the server
/// </summary> /// </summary>
@ -245,7 +245,7 @@ namespace MinecraftClient
/// <param name="uuid">Player UUID</param> /// <param name="uuid">Player UUID</param>
/// <param name="gamemode">New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator).</param> /// <param name="gamemode">New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator).</param>
public virtual void OnGamemodeUpdate(string playername, Guid uuid, int gamemode) { } public virtual void OnGamemodeUpdate(string playername, Guid uuid, int gamemode) { }
/// <summary> /// <summary>
/// Called when the Latency has been updated for a player /// Called when the Latency has been updated for a player
/// </summary> /// </summary>
@ -253,7 +253,7 @@ namespace MinecraftClient
/// <param name="uuid">Player UUID</param> /// <param name="uuid">Player UUID</param>
/// <param name="latency">Latency.</param> /// <param name="latency">Latency.</param>
public virtual void OnLatencyUpdate(string playername, Guid uuid, int latency) { } public virtual void OnLatencyUpdate(string playername, Guid uuid, int latency) { }
/// <summary> /// <summary>
/// Called when the Latency has been updated for a player /// Called when the Latency has been updated for a player
/// </summary> /// </summary>
@ -262,16 +262,22 @@ namespace MinecraftClient
/// <param name="uuid">Player UUID</param> /// <param name="uuid">Player UUID</param>
/// <param name="latency">Latency.</param> /// <param name="latency">Latency.</param>
public virtual void OnLatencyUpdate(Entity entity, string playername, Guid uuid, int latency) { } public virtual void OnLatencyUpdate(Entity entity, string playername, Guid uuid, int latency) { }
/// <summary> /// <summary>
/// Called when a map was updated /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
/// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
/// </summary> /// </summary>
/// <param name="mapid"></param> /// <param name="mapid">Map ID of the map being modified</param>
/// <param name="scale"></param> /// <param name="scale">A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)</param>
/// <param name="trackingposition"></param> /// <param name="trackingposition">Specifies whether player and item frame icons are shown </param>
/// <param name="locked"></param> /// <param name="locked">True if the map has been locked in a cartography table </param>
/// <param name="iconcount"></param> /// <param name="icons">A list of MapIcon objects of map icons, send only if trackingPosition is true</param>
public virtual void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount) { } /// <param name="columnsUpdated">Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)</param>
/// <param name="rowsUpdated">Map height</param>
/// <param name="mapCoulmnX">x offset of the westernmost column</param>
/// <param name="mapRowZ">z offset of the northernmost row</param>
/// <param name="colors">a byte array of colors on the map</param>
public virtual void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List<MapIcon> icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapRowZ, byte[]? colors) { }
/// <summary> /// <summary>
/// Called when tradeList is received from server /// Called when tradeList is received from server
@ -319,7 +325,7 @@ namespace MinecraftClient
/// <param name="objectivevalue">Only if mode is 0 or 2. The text to be displayed for the score</param> /// <param name="objectivevalue">Only if mode is 0 or 2. The text to be displayed for the score</param>
/// <param name="type">Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".</param> /// <param name="type">Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".</param>
public virtual void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type, string json) { } public virtual void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type, string json) { }
/// <summary> /// <summary>
/// Called when a scoreboard updated /// Called when a scoreboard updated
/// </summary> /// </summary>
@ -360,12 +366,12 @@ namespace MinecraftClient
/// <param name="uuid">UUID of the player</param> /// <param name="uuid">UUID of the player</param>
/// <param name="name">Name of the player</param> /// <param name="name">Name of the player</param>
public virtual void OnPlayerLeave(Guid uuid, string? name) { } public virtual void OnPlayerLeave(Guid uuid, string? name) { }
/// <summary> /// <summary>
/// Called when the player deaths /// Called when the player deaths
/// </summary> /// </summary>
public virtual void OnDeath() { } public virtual void OnDeath() { }
/// <summary> /// <summary>
/// Called when the player respawns /// Called when the player respawns
/// </summary> /// </summary>
@ -451,14 +457,14 @@ namespace MinecraftClient
/// </summary> /// </summary>
public static string GetVerbatim(string text) public static string GetVerbatim(string text)
{ {
if ( String.IsNullOrEmpty(text) ) if (String.IsNullOrEmpty(text))
return String.Empty; return String.Empty;
int idx = 0; int idx = 0;
var data = new char[text.Length]; var data = new char[text.Length];
for ( int i = 0; i < text.Length; i++ ) for (int i = 0; i < text.Length; i++)
if ( text[i] != '§' ) if (text[i] != '§')
data[idx++] = text[i]; data[idx++] = text[i];
else else
i++; i++;
@ -478,7 +484,7 @@ namespace MinecraftClient
if (!((c >= 'a' && c <= 'z') if (!((c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || (c >= '0' && c <= '9')
|| c == '_') ) || c == '_'))
return false; return false;
return true; return true;
@ -950,7 +956,7 @@ namespace MinecraftClient
return Handler.GetWorld(); return Handler.GetWorld();
return null; return null;
} }
/// <summary> /// <summary>
/// Get all Entities /// Get all Entities
/// </summary> /// </summary>
@ -968,7 +974,7 @@ namespace MinecraftClient
{ {
return Handler.GetPlayersLatency(); return Handler.GetPlayersLatency();
} }
/// <summary> /// <summary>
/// Get the current location of the player (Feet location) /// Get the current location of the player (Feet location)
/// </summary> /// </summary>
@ -1002,7 +1008,7 @@ namespace MinecraftClient
{ {
return Handler.ClientIsMoving(); return Handler.ClientIsMoving();
} }
/// <summary> /// <summary>
/// Look at the specified location /// Look at the specified location
/// </summary> /// </summary>
@ -1086,7 +1092,7 @@ namespace MinecraftClient
{ {
return Handler.GetUsername(); return Handler.GetUsername();
} }
/// <summary> /// <summary>
/// Return the Gamemode of the current account /// Return the Gamemode of the current account
/// </summary> /// </summary>
@ -1361,7 +1367,7 @@ namespace MinecraftClient
{ {
return Handler.GetCurrentSlot(); return Handler.GetCurrentSlot();
} }
/// <summary> /// <summary>
/// Clean all inventory /// Clean all inventory
/// </summary> /// </summary>
@ -1370,7 +1376,7 @@ namespace MinecraftClient
{ {
return Handler.ClearInventories(); return Handler.ClearInventories();
} }
/// <summary> /// <summary>
/// Update sign text /// Update sign text
/// </summary> /// </summary>
@ -1410,7 +1416,7 @@ namespace MinecraftClient
{ {
return Handler.SpectateByUUID(UUID); return Handler.SpectateByUUID(UUID);
} }
/// <summary> /// <summary>
/// Update command block /// Update command block
/// </summary> /// </summary>
@ -1456,7 +1462,7 @@ namespace MinecraftClient
{ {
return Handler.GetMaxChatMessageLength(); return Handler.GetMaxChatMessageLength();
} }
/// <summary> /// <summary>
/// Respawn player /// Respawn player
/// </summary> /// </summary>