diff --git a/MinecraftClient/CSharpRunner.cs b/MinecraftClient/CSharpRunner.cs index 601c30fa..6327a45b 100644 --- a/MinecraftClient/CSharpRunner.cs +++ b/MinecraftClient/CSharpRunner.cs @@ -84,6 +84,7 @@ namespace MinecraftClient "using System.Threading;", "using MinecraftClient;", "using MinecraftClient.Mapping;", + "using MinecraftClient.Inventory;", String.Join("\n", libs), "namespace ScriptLoader {", "public class Script {", diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs index 99306882..781d3d17 100644 --- a/MinecraftClient/ChatBot.cs +++ b/MinecraftClient/ChatBot.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Text.RegularExpressions; using MinecraftClient.Inventory; +using MinecraftClient.Mapping; namespace MinecraftClient { @@ -156,7 +157,13 @@ namespace MinecraftClient /// Entity with updated location public virtual void OnEntityMove(Mapping.Entity entity) { } - public virtual void OnInternalCommand(string commandName,string commandParams, string Result) { } + /// + /// Called after an internal MCC command has been performed + /// + /// MCC Command Name + /// MCC Command Parameters + /// MCC command result + public virtual void OnInternalCommand(string commandName, string commandParams, string Result) { } /// /// Called when an entity spawned nearby @@ -183,6 +190,29 @@ namespace MinecraftClient /// New food level public virtual void OnHealthUpdate(float health, int food) { } + /// + /// Called when an explosion occurs on the server + /// + /// Explosion location + /// Amount of blocks blown up + public virtual void OnExplosion(Location explode, float strength, int recordcount) { } + + /// + /// Called when experience updates + /// + /// Between 0 and 1 + /// Level + /// Total Experience + public virtual void OnSetExperience(float Experiencebar, int Level, int TotalExperience) { } + + /// + /// Called when the Game Mode has been updated for a player + /// + /// Player Name + /// Player UUID + /// New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator). + public virtual void OnGamemodeUpdate(string playername, Guid uuid, int gamemode) { } + /* =================================================================== */ /* ToolBox - Methods below might be useful while creating your bot. */ /* You should not need to interact with other classes of the program. */ @@ -667,6 +697,7 @@ namespace MinecraftClient { return SendEntityAction(on ? Protocol.EntityActionType.StartSneaking : Protocol.EntityActionType.StopSneaking); } + /// /// Send Entity Action /// @@ -674,6 +705,18 @@ namespace MinecraftClient { return Handler.sendEntityAction(entityAction); } + + /// + /// Dig block - WORK IN PROGRESS - MAY NOT WORK + /// + /// + /// + /// + protected void DigBlock(int status, Location location, byte face) + { + Handler.DigBlock(status, location, face); + } + /// /// SetSlot /// @@ -871,7 +914,7 @@ namespace MinecraftClient /// /// /// 0: interact, 1: attack, 2: interact at - /// + /// TRUE in case of success protected bool InteractEntity(int EntityID, int type) { return Handler.InteractEntity(EntityID, type); @@ -881,6 +924,7 @@ namespace MinecraftClient /// Give Creative Mode items into regular/survival Player Inventory /// /// (obviously) requires to be in creative mode + /// /// Destination inventory slot /// Item type /// Item count @@ -894,7 +938,7 @@ namespace MinecraftClient /// Plays animation (Player arm swing) /// /// 0 for left arm, 1 for right arm - /// TRUE if animation successfully done + /// TRUE in case of success protected bool SendAnimation(int animation) { return Handler.DoAnimation(animation); @@ -903,7 +947,7 @@ namespace MinecraftClient /// /// Use item currently in the player's hand (active inventory bar slot) /// - /// + /// TRUE if successful protected bool UseItemInHand() { return Handler.UseItemOnHand(); @@ -912,12 +956,22 @@ namespace MinecraftClient /// /// Check inventory handling enable status /// - /// + /// TRUE if inventory handling is enabled public bool GetInventoryEnabled() { return Handler.GetInventoryEnabled(); } + /// + /// Place block + /// + /// Block location + /// + protected bool SendPlaceBlock(Location location) + { + return Handler.PlaceBlock(location); + } + /// /// Get the player's inventory. Do not write to it, will not have any effect server-side. /// @@ -937,6 +991,18 @@ namespace MinecraftClient return Handler.GetInventories(); } + /// + /// Perform inventory action + /// + /// Inventory ID + /// Slot ID + /// Action Type + /// TRUE in case of success + protected bool WindowAction(int inventoryId, int slot, WindowActionType actionType) + { + return Handler.DoWindowAction(inventoryId, slot, actionType); + } + /// /// Change player selected hotbar slot /// diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index 99ccac3b..4fcbda32 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -46,8 +46,8 @@ namespace MinecraftClient.ChatBots bool shouldAttack = handleEntity(entity.Value); if (shouldAttack) { - // hit the entity! - InteractEntity(entity.Key, 1); + SendAnimation(0); // Hit Animation + InteractEntity(entity.Key, 1); // hit the entity! } } } diff --git a/MinecraftClient/Commands/Health.cs b/MinecraftClient/Commands/Health.cs index d85bf688..42bb9a3e 100644 --- a/MinecraftClient/Commands/Health.cs +++ b/MinecraftClient/Commands/Health.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -12,7 +12,7 @@ namespace MinecraftClient.Commands public override string Run(McTcpClient handler, string command, Dictionary localVars) { - return "Health: " + handler.GetHealth() + ", Saturation: " + handler.GetSaturation(); + return "Health: " + handler.GetHealth() + ", Saturation: " + handler.GetSaturation() + ", Level: " + handler.GetLevel() + ", TotalExperience: " + handler.GetTotalExperience(); } } } diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 62cb2c28..ded49bd8 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -63,6 +63,8 @@ namespace MinecraftClient // player health and hunger private float playerHealth; private int playerFoodSaturation; + private int playerLevel; + private int playerTotalExperience; private byte CurrentSlot = 0; // Entity handling @@ -83,6 +85,8 @@ namespace MinecraftClient public Double GetServerTPS() { return serverTPS; } public float GetHealth() { return playerHealth; } public int GetSaturation() { return playerFoodSaturation; } + public int GetLevel() { return playerLevel; } + public int GetTotalExperience() { return playerTotalExperience; } public byte GetCurrentSlot() { return CurrentSlot; } // get bots list for unloading them by commands @@ -1261,6 +1265,23 @@ namespace MinecraftClient OnSpawnEntity(playerEntity); } + /// + /// Called when the Game Mode has been updated for a player + /// + /// Player Name + /// Player UUID + /// New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator). + public void OnGamemodeUpdate(Guid uuid, int gamemode) + { + string playerName = null; + if (onlinePlayers.ContainsKey(uuid)) + { + playerName = onlinePlayers[uuid]; + foreach (ChatBot bot in bots.ToArray()) + bot.OnGamemodeUpdate(playerName, uuid, gamemode); + } + } + /// /// Called when entities dead/despawn. /// @@ -1529,7 +1550,22 @@ namespace MinecraftClient //WORK IN PROGRESS. MAY NOT WORK YET if (Settings.DebugMessages) ConsoleIO.WriteLogLine(location.ToString()); - return handler.SendPlayerBlockPlacement(0, location, 1, 0.5f, 0.5f, 0.5f, false); + Location placelocation = new Location(location.X, location.Y - 1, location.Z); + return handler.SendPlayerBlockPlacement(0, placelocation, 1, 0.5f, 0.5f, 0.5f, false); + } + + /// + /// Dig block - WORK IN PROGRESS - MAY NOT WORK YET + /// + /// + /// + /// + public bool DigBlock(int status, Location location, byte Face) + { + if (Settings.DebugMessages) + ConsoleIO.WriteLogLine(location.ToString()); + Location placelocation = new Location(location.X, location.Y, location.Z); + return handler.SendPlayerDigging(status, placelocation, 1); } /// @@ -1549,7 +1585,7 @@ namespace MinecraftClient return false; } } - + /// /// Called when client player's health changed, e.g. getting attack /// @@ -1574,6 +1610,38 @@ namespace MinecraftClient bot.OnHealthUpdate(health, food); } + /// + /// Called when experience updates + /// + /// Between 0 and 1 + /// Level + /// Total Experience + public void OnSetExperience(float Experiencebar, int Level, int TotalExperience) + { + playerLevel = Level; + playerTotalExperience = TotalExperience; + foreach (ChatBot bot in bots.ToArray()) + bot.OnSetExperience(Experiencebar, Level, TotalExperience); + } + + /// + /// Called when and explosion occurs on the server + /// + /// Explosion location + /// Explosion strength + /// Amount of affected blocks + public void OnExplosion(Location location, float strength, int affectedBlocks) + { + foreach (ChatBot bot in bots.ToArray()) + bot.OnExplosion(explode, strength, ExplosionRecordCount); + } + + /// + /// Called when Experience bar is updated + /// + /// Experience bar level + /// Player Level + /// Total experience public void OnHeldItemChange(byte slot) { foreach (ChatBot bot in bots.ToArray()) diff --git a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs index 42987688..e5fab355 100644 --- a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -45,7 +45,9 @@ namespace MinecraftClient.Protocol.Handlers EntityTeleport, TimeUpdate, UpdateHealth, + SetExperience, HeldItemChange, + Explosion, /// /// Represents a packet not implemented in MCC. diff --git a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs index c1698e1d..7d00365d 100644 --- a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs @@ -33,5 +33,6 @@ namespace MinecraftClient.Protocol.Handlers PlayerBlockPlacement, CreativeInventoryAction, Animation, + PlayerDigging, } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 20b0c110..79aebcc2 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -718,6 +718,11 @@ namespace MinecraftClient.Protocol.Handlers return false; //Currently not implemented } + public bool SendPlayerDigging(int status, Location location, byte face) + { + return false; //Currently not implemented + } + /// /// Send a plugin channel packet to the server. /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index aace40ee..7f7c6847 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -444,6 +444,9 @@ namespace MinecraftClient.Protocol.Handlers handler.OnPlayerJoin(uuid, name); break; case 0x01: //Update gamemode + int gamemode = dataTypes.ReadNextVarInt(packetData); + handler.OnGamemodeUpdate(uuid, gamemode); + break; case 0x02: //Update latency dataTypes.ReadNextVarInt(packetData); break; @@ -714,6 +717,18 @@ namespace MinecraftClient.Protocol.Handlers dataTypes.ReadNextFloat(packetData); // Food Saturation handler.OnUpdateHealth(health, food); break; + case PacketIncomingType.SetExperience: + float experiencebar = dataTypes.ReadNextFloat(packetData); + int level = dataTypes.ReadNextVarInt(packetData); + int totalexperience = dataTypes.ReadNextVarInt(packetData); + handler.OnSetExperience(experiencebar, level, totalexperience); + break; + case PacketIncomingType.Explosion: + Location explodelocation = new Location(dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData), dataTypes.ReadNextFloat(packetData)); + float Explosionstrength = dataTypes.ReadNextFloat(packetData); + int ExplosionRecordCount = dataTypes.ReadNextInt(packetData); + handler.OnExplosion(explodelocation, Explosionstrength, ExplosionRecordCount); + break; case PacketIncomingType.HeldItemChange: byte slot = dataTypes.ReadNextByte(packetData); handler.OnHeldItemChange(slot); @@ -1066,7 +1081,7 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } - + public bool SendEntityAction(int PlayerEntityID, int ActionID) { try @@ -1228,7 +1243,7 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } - + /// /// Send an Interact Entity Packet to server /// @@ -1278,9 +1293,9 @@ namespace MinecraftClient.Protocol.Handlers { if (protocolversion < MC19Version) return false; // Packet does not exist prior to MC 1.9 - // According to https://wiki.vg/index.php?title=Protocol&oldid=5486#Player_Block_Placement - // MC 1.7 does this using Player Block Placement with special values - // TODO once Player Block Placement is implemented for older versions + // According to https://wiki.vg/index.php?title=Protocol&oldid=5486#Player_Block_Placement + // MC 1.7 does this using Player Block Placement with special values + // TODO once Player Block Placement is implemented for older versions try { List packet = new List(); @@ -1292,7 +1307,24 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } + + public bool SendPlayerDigging(int status, Location location, byte face) + { + try + { + List packet = new List(); + packet.AddRange(dataTypes.GetVarInt(status)); + packet.AddRange(dataTypes.GetLocation(location)); + packet.AddRange(dataTypes.GetVarInt(face)); + SendPacket(PacketOutgoingType.PlayerDigging, packet); + return true; + } + catch (SocketException) { return false; } + catch (System.IO.IOException) { return false; } + catch (ObjectDisposedException) { return false; } + } + public bool SendPlayerBlockPlacement(int hand, Location location, int face, float CursorX, float CursorY, float CursorZ, bool insideBlock) { if (protocolversion < MC114Version) @@ -1350,8 +1382,8 @@ namespace MinecraftClient.Protocol.Handlers case WindowActionType.LeftClick: button = 0; break; case WindowActionType.RightClick: button = 1; break; case WindowActionType.MiddleClick: button = 2; mode = 3; break; - case WindowActionType.DropItem: - button = 0; + case WindowActionType.DropItem: + button = 0; mode = 4; item = new Item(-1, 0, null); Container inventory = handler.GetInventory(windowId); @@ -1427,7 +1459,7 @@ namespace MinecraftClient.Protocol.Handlers SendPacket(PacketOutgoingType.Animation, packet); return true; } - else; + else { return false; } @@ -1436,7 +1468,6 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } - public bool SendCloseWindow(int windowId) { try diff --git a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs index ba2ada8d..49617fa4 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -59,7 +59,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x18: return PacketIncomingType.EntityTeleport; case 0x03: return PacketIncomingType.TimeUpdate; case 0x06: return PacketIncomingType.UpdateHealth; + case 0x1F: return PacketIncomingType.SetExperience; case 0x09: return PacketIncomingType.HeldItemChange; + case 0x1C: return PacketIncomingType.Explosion; } } else if (protocol <= Protocol18Handler.MC1112Version) // MC 1.9, 1.10 and 1.11 @@ -97,7 +99,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x49: return PacketIncomingType.EntityTeleport; case 0x44: return PacketIncomingType.TimeUpdate; case 0x3E: return PacketIncomingType.UpdateHealth; + case 0x3D: return PacketIncomingType.SetExperience; case 0x37: return PacketIncomingType.HeldItemChange; + case 0x27: return PacketIncomingType.Explosion; } } else if (protocol <= Protocol18Handler.MC112Version) // MC 1.12.0 @@ -135,7 +139,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x4B: return PacketIncomingType.EntityTeleport; case 0x46: return PacketIncomingType.TimeUpdate; case 0x40: return PacketIncomingType.UpdateHealth; + case 0x3F: return PacketIncomingType.SetExperience; case 0x39: return PacketIncomingType.HeldItemChange; + case 0x1C: return PacketIncomingType.Explosion; } } else if (protocol <= Protocol18Handler.MC1122Version) // MC 1.12.2 @@ -173,7 +179,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x4C: return PacketIncomingType.EntityTeleport; case 0x47: return PacketIncomingType.TimeUpdate; case 0x41: return PacketIncomingType.UpdateHealth; + case 0x40: return PacketIncomingType.SetExperience; case 0x3A: return PacketIncomingType.HeldItemChange; + case 0x1C: return PacketIncomingType.Explosion; } } else if (protocol < Protocol18Handler.MC114Version) // MC 1.13 to 1.13.2 @@ -211,7 +219,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x50: return PacketIncomingType.EntityTeleport; case 0x4A: return PacketIncomingType.TimeUpdate; case 0x44: return PacketIncomingType.UpdateHealth; + case 0x43: return PacketIncomingType.SetExperience; case 0x3D: return PacketIncomingType.HeldItemChange; + case 0x1E: return PacketIncomingType.Explosion; } } else if (protocol < Protocol18Handler.MC115Version) // MC 1.14 to 1.14.4 @@ -249,7 +259,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x56: return PacketIncomingType.EntityTeleport; case 0x4E: return PacketIncomingType.TimeUpdate; case 0x48: return PacketIncomingType.UpdateHealth; + case 0x47: return PacketIncomingType.SetExperience; case 0x3F: return PacketIncomingType.HeldItemChange; + case 0x1C: return PacketIncomingType.Explosion; } } else // MC 1.15 @@ -287,7 +299,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x57: return PacketIncomingType.EntityTeleport; case 0x4F: return PacketIncomingType.TimeUpdate; case 0x49: return PacketIncomingType.UpdateHealth; + case 0x48: return PacketIncomingType.SetExperience; case 0x40: return PacketIncomingType.HeldItemChange; + case 0x1D: return PacketIncomingType.Explosion; } } @@ -331,6 +345,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x08; case PacketOutgoingType.CreativeInventoryAction: return 0x10; case PacketOutgoingType.Animation: return 0x0A; + case PacketOutgoingType.PlayerDigging: return 0x07; } } else if (protocol <= Protocol18Handler.MC1112Version) // MC 1.9, 1,10 and 1.11 @@ -356,6 +371,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x1C; case PacketOutgoingType.CreativeInventoryAction: return 0x18; case PacketOutgoingType.Animation: return 0x1A; + case PacketOutgoingType.PlayerDigging: return 0x13; } } else if (protocol <= Protocol18Handler.MC112Version) // MC 1.12 @@ -381,6 +397,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x1F; case PacketOutgoingType.CreativeInventoryAction: return 0x1B; case PacketOutgoingType.Animation: return 0x1D; + case PacketOutgoingType.PlayerDigging: return 0x14; } } else if (protocol <= Protocol18Handler.MC1122Version) // 1.12.2 @@ -406,6 +423,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x1F; case PacketOutgoingType.CreativeInventoryAction: return 0x1B; case PacketOutgoingType.Animation: return 0x1D; + case PacketOutgoingType.PlayerDigging: return 0x14; } } else if (protocol < Protocol18Handler.MC114Version) // MC 1.13 to 1.13.2 @@ -431,6 +449,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x29; case PacketOutgoingType.CreativeInventoryAction: return 0x24; case PacketOutgoingType.Animation: return 0x27; + case PacketOutgoingType.PlayerDigging: return 0x18; } } else // MC 1.14 to 1.15 @@ -456,6 +475,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.PlayerBlockPlacement: return 0x2C; case PacketOutgoingType.CreativeInventoryAction: return 0x26; case PacketOutgoingType.Animation: return 0x2A; + case PacketOutgoingType.PlayerDigging: return 0x1A; } } diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index 39f82929..75306879 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -185,5 +185,14 @@ namespace MinecraftClient.Protocol /// TRUE if inside block /// True if packet was successfully sent bool SendPlayerBlockPlacement(int hand, Location location, int face, float CursorX, float CursorY, float CursorZ, bool insideBlock); + + /// + /// Send player blog digging packet to the server + /// + /// 0 to start diffing, 1 to cancel, 2 to finish ( https://wiki.vg/Protocol#Player_Digging ) + /// Location + /// Block face: 0 = bottom, 1 = top, etc (see wiki) + /// True if packet was succcessfully sent + bool SendPlayerDigging(int status, Location location, byte face); } } diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index d8998552..34b3c916 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -208,6 +208,29 @@ namespace MinecraftClient.Protocol /// void OnUpdateHealth(float health, int food); + /// + /// Called when and explosion occurs on the server + /// + /// Explosion location + /// Explosion strength + /// Amount of affected blocks + void OnExplosion(Location location, float strength, int affectedBlocks); + + /// + /// Called when a player's game mode has changed + /// + /// Affected player's UUID + /// New game mode + void OnGamemodeUpdate(Guid uuid, int gamemode); + + /// + /// Called when Experience bar is updated + /// + /// Experience bar level + /// Player Level + /// Total experience + void OnSetExperience(float Experiencebar, int Level, int TotalExperience); + /// /// Called when client need to change slot. ///