static void SetExtCol(CustomColor col) { ExtColors[col.Code] = col; Player[] players = Server.Players; foreach (Player p in players) { if (!p.Supports(CpeExt.TextColors)) { continue; } p.Send(Packet.MakeSetTextColor(col)); } SaveExtColors(); }
bool NegotiateProtocolExtension() { // write our ExtInfo and ExtEntry packets writer.Write(Packet.MakeExtInfo("ProCraft", 30).Bytes); writer.Write(Packet.MakeExtEntry(ClickDistanceExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(CustomBlocksExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(HeldBlockExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(TextHotKeyExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(ExtPlayerListExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EnvColorsExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(SelectionCuboidExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(BlockPermissionsExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(ChangeModelExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EnvMapAppearanceExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EnvWeatherTypeExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(HackControlExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(ExtPlayerListExtName, 2).Bytes); writer.Write(Packet.MakeExtEntry(PlayerClickExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(MessageTypesExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EmoteFixExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(LongerMessagesExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(FullCP437ExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(BlockDefinitionsExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(BlockDefinitionsExtExtName, 2).Bytes); writer.Write(Packet.MakeExtEntry(BulkBlockUpdateExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(TextColorsExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EnvMapAspectExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(ExtPlayerPositionsExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(EntityPropertyExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(TwoWayPingExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(InventoryOrderExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(InstantMOTDExtName, 1).Bytes); writer.Write(Packet.MakeExtEntry(FastMapExtName, 1).Bytes); // Fix for ClassiCube Client which violates the spec - // If server supports version > 1 but client version 1, client should reply with version 1. // ClassiCube just doesn't reply at all in that case. writer.Write(Packet.MakeExtEntry(EnvMapAppearanceExtName, 2).Bytes); // Expect ExtInfo reply from the client OpCode extInfoReply = reader.ReadOpCode(); //Logger.Log(LogType.Debug, "Expected: {0} / Received: {1}", OpCode.ExtInfo, extInfoReply ); if (extInfoReply != OpCode.ExtInfo) { Logger.Log(LogType.Debug, "Player {0}: Unexpected ExtInfo reply ({1})", Info.Name, extInfoReply); return(false); } ClientName = reader.ReadString(); int expectedEntries = reader.ReadInt16(); // wait for client to send its ExtEntries for (int i = 0; i < expectedEntries; i++) { // Expect ExtEntry replies (0 or more) OpCode extEntryReply = reader.ReadOpCode(); if (extEntryReply != OpCode.ExtEntry) { Logger.Log(LogType.Warning, "Player {0} from {1}: Unexpected ExtEntry reply ({2})", Name, IP, extInfoReply); return(false); } string extName = reader.ReadString(); int version = reader.ReadInt32(); CpeExt ext = CpeExt.None; switch (extName) { case CustomBlocksExtName: if (version == 1) { ext = CpeExt.CustomBlocks; } break; case BlockPermissionsExtName: if (version == 1) { ext = CpeExt.BlockPermissions; } break; case ClickDistanceExtName: if (version == 1) { ext = CpeExt.ClickDistance; } break; case EnvColorsExtName: if (version == 1) { ext = CpeExt.EnvColors; } break; case ChangeModelExtName: if (version == 1) { ext = CpeExt.ChangeModel; } break; case EnvMapAppearanceExtName: if (version == 1) { ext = CpeExt.EnvMapAppearance; } if (version == 2) { ext = CpeExt.EnvMapAppearance2; } break; case EnvWeatherTypeExtName: if (version == 1) { ext = CpeExt.EnvWeatherType; } break; case HeldBlockExtName: if (version == 1) { ext = CpeExt.HeldBlock; } break; case ExtPlayerListExtName: if (version == 1) { ext = CpeExt.ExtPlayerList; if (Supports(CpeExt.ExtPlayerList2)) { ext = CpeExt.ExtPlayerList2; } } else if (version == 2) { ext = CpeExt.ExtPlayerList2; if (Supports(CpeExt.ExtPlayerList)) { supportedExts.Remove(CpeExt.ExtPlayerList); } } break; case SelectionCuboidExtName: if (version == 1) { ext = CpeExt.SelectionCuboid; } break; case MessageTypesExtName: if (version == 1) { ext = CpeExt.MessageType; } break; case HackControlExtName: if (version == 1) { ext = CpeExt.HackControl; } break; case EmoteFixExtName: if (version == 1) { ext = CpeExt.EmoteFix; } break; case TextHotKeyExtName: if (version == 1) { ext = CpeExt.TextHotKey; } break; case PlayerClickExtName: if (version == 1) { ext = CpeExt.PlayerClick; } break; case LongerMessagesExtName: if (version == 1) { ext = CpeExt.LongerMessages; } break; case FullCP437ExtName: if (version == 1) { ext = CpeExt.FullCP437; } break; case BlockDefinitionsExtName: if (version == 1) { ext = CpeExt.BlockDefinitions; } break; case BlockDefinitionsExtExtName: if (version == 1) { ext = CpeExt.BlockDefinitionsExt; } if (version == 2) { ext = CpeExt.BlockDefinitionsExt2; } break; case BulkBlockUpdateExtName: if (version == 1) { ext = CpeExt.BulkBlockUpdate; } break; case TextColorsExtName: if (version == 1) { ext = CpeExt.TextColors; } break; case EnvMapAspectExtName: if (version == 1) { ext = CpeExt.EnvMapAspect; } break; case ExtPlayerPositionsExtName: if (version == 1) { ext = CpeExt.ExtPlayerPositions; } supportsExtPositions = true; break; case EntityPropertyExtName: if (version == 1) { ext = CpeExt.EntityProperty; } break; case TwoWayPingExtName: if (version == 1) { ext = CpeExt.TwoWayPing; } break; case InventoryOrderExtName: if (version == 1) { ext = CpeExt.InventoryOrder; } break; case InstantMOTDExtName: if (version == 1) { ext = CpeExt.InstantMOTD; } break; case FastMapExtName: if (version == 1) { ext = CpeExt.FastMap; } break; } if (ext != CpeExt.None) { supportedExts.Add(ext); } } supportsCustomBlocks = Supports(CpeExt.CustomBlocks); supportsBlockDefs = Supports(CpeExt.BlockDefinitions); // log client's capabilities if (supportedExts.Count > 0) { Logger.Log(LogType.Debug, "Player {0} is using \"{1}\", supporting: {2}", Info.Name, ClientName, supportedExts.JoinToString(", ")); } else if (supportedExts.Count == 0) { Kick("Please use the ClassicalSharp client", LeaveReason.InvalidOpcodeKick); } // if client also supports CustomBlockSupportLevel, figure out what level to use // Send CustomBlockSupportLevel writer.Write(Packet.MakeCustomBlockSupportLevel(CustomBlocksLevel).Bytes); if (Supports(CpeExt.TextColors)) { for (int i = 0; i < Color.ExtColors.Length; i++) { if (Color.ExtColors[i].Undefined) { continue; } writer.Write(Packet.MakeSetTextColor(Color.ExtColors[i]).Bytes); } } return(true); }