示例#1
0
 static PaletteEntry Multiply(PaletteEntry entry, ColorDesc rgb)
 {
     entry.R = (byte)(entry.R * rgb.R / 255);
     entry.G = (byte)(entry.G * rgb.G / 255);
     entry.B = (byte)(entry.B * rgb.B / 255);
     return(entry);
 }
示例#2
0
        void SetZoneProp(Player p, string[] args, Zone zone)
        {
            if (args[2].CaselessEq("col"))
            {
                ColorDesc desc = default(ColorDesc);
                if (!CommandParser.GetHex(p, args[3], ref desc))
                {
                    return;
                }

                zone.Config.ShowColor = args[3];
                zone.ShowAll(p.level);
            }
            else if (args[2].CaselessEq("alpha"))
            {
                if (!CommandParser.GetByte(p, args[3], "Alpha", ref zone.Config.ShowAlpha))
                {
                    return;
                }
                zone.ShowAll(p.level);
            }
            else
            {
                Player.Message(p, "?????");
                return;
            }
            p.level.Save(true);
        }
示例#3
0
        /// <summary> Constructs a custom block, with the default properties of the given classic/CPE block. </summary>
        public static BlockDefinition MakeCustomBlock(BlockID b)
        {
            BlockDefinition def = new BlockDefinition();

            def.SetBlock(b);
            def.Name        = Name(b);
            def.CollideType = Collide(b);
            def.Speed       = 1;
            def.BlocksLight = BlocksLight(b);

            def.TopTex    = topTex[b];
            def.BottomTex = bottomTex[b];
            def.SetSideTex(sideTex[b]);
            def.WalkSound = (byte)StepSound(b);

            def.FullBright = FullBright(b);
            def.Shape      = Draw(b) == DrawType.Sprite ? (byte)0 : (byte)1;
            def.BlockDraw  = Draw(b);
            if (def.BlockDraw == DrawType.Sprite)
            {
                def.BlockDraw = DrawType.Transparent;
            }

            def.FogDensity = FogDensity(b);
            ColorDesc fog = FogColor(b);

            def.FogR     = fog.R; def.FogG = fog.G; def.FogB = fog.B;
            def.FallBack = (BlockRaw)b;

            def.MaxX = 16; def.MaxZ = Height(b); def.MaxY = 16;
            return(def);
        }
示例#4
0
        void HandleAdd(Player p, string[] args)
        {
            if (args.Length != 4)
            {
                Help(p); return;
            }

            ImagePalette palette = ImagePalette.Find(args[1]);

            if (palette == null)
            {
                p.Message("Palette {0} does not exist.", args[1]); return;
            }

            BlockID block;

            if (!CommandParser.GetBlock(p, args[2], out block))
            {
                return;
            }

            ColorDesc rgb = default(ColorDesc);

            if (!CommandParser.GetHex(p, args[3], ref rgb))
            {
                return;
            }
            PaletteEntry entry = new PaletteEntry(rgb.R, rgb.G, rgb.B, block);

            AddEntry(p, palette, entry);
        }
示例#5
0
文件: Packet.cs 项目: GDWGH/MCGalaxy
 public static byte[] SetTextColor(ColorDesc col)
 {
     byte[] buffer = new byte[6];
     buffer[0] = Opcode.CpeSetTextColor;
     buffer[1] = col.R; buffer[2] = col.G; buffer[3] = col.B; buffer[4] = col.A;
     buffer[5] = col.Index;
     return(buffer);
 }
示例#6
0
        public bool SendSetTextColor(ColorDesc color)
        {
            if (!player.Supports(CpeExt.TextColors))
            {
                return(false);
            }

            Send(Packet.SetTextColor(color));
            return(true);
        }
示例#7
0
        /// <summary> Attempts to parse the given argument as a hex color. </summary>
        public static bool GetHex(Player p, string input, ref ColorDesc col)
        {
            ColorDesc tmp;

            if (!Colors.TryParseHex(input, out tmp))
            {
                p.Message("&W\"#{0}\" is not a valid HEX color.", input); return(false);
            }
            col = tmp; return(true);
        }
示例#8
0
        public override bool SendSetTextColor(ColorDesc color)
        {
            if (!hasTextColors)
            {
                return(false);
            }

            Send(Packet.SetTextColor(color));
            return(true);
        }
示例#9
0
        // Not very elegant, because we don't want the % to be escaped like everywhere else
        internal static string FormatColor(ColorDesc col)
        {
            string format = "{0} &{1}({2})%S - %%S{1}, falls back to &{3}%&{3}{3}";

            if (col.Code == col.Fallback)
            {
                format = "{0} &{1}({2})%S - %&S{1}";
            }

            return(string.Format(format, col.Name, col.Code, Utils.Hex(col.R, col.G, col.B), col.Fallback));
        }
示例#10
0
        void EditHandler(Player p, string[] args)
        {
            if (args.Length < 4)
            {
                Help(p); return;
            }

            char code = ParseColor(p, args[1]);

            if (code == '\0')
            {
                return;
            }
            ColorDesc col = Colors.List[code];

            if (args[2].CaselessEq("name"))
            {
                if (!CheckName(p, args[3]))
                {
                    return;
                }

                p.Message("Set name of {0} to {1}", col.Name, args[3]);
                col.Name = args[3];
            }
            else if (args[2].CaselessEq("fallback"))
            {
                char fallback;
                if (!CheckFallback(p, args[3], code, out fallback))
                {
                    return;
                }

                p.Message("Set fallback of {0} to %&S{1}", col.Name, fallback);
                col.Fallback = fallback;
            }
            else if (args[2].CaselessEq("hex") || args[2].CaselessEq("color"))
            {
                ColorDesc rgb = default(ColorDesc);
                if (!CommandParser.GetHex(p, args[3], ref rgb))
                {
                    return;
                }

                p.Message("Set hex color of {0} to {1}", col.Name, Utils.Hex(rgb.R, rgb.G, rgb.B));
                col.R = rgb.R; col.G = rgb.G; col.B = rgb.B;
            }
            else
            {
                Help(p); return;
            }

            Colors.Update(col);
        }
示例#11
0
        void SetZoneProp(Player p, string[] args, Zone zone)
        {
            ColorDesc desc = default(ColorDesc);

            if (args.Length < 4)
            {
                p.Message("No value provided. See %T/Help zone properties");
                return;
            }

            string             opt = args[2], value = args[3];
            Predicate <Player> selector = pl => pl.ZoneIn == zone;

            if (opt.CaselessEq("alpha"))
            {
                float alpha = 0;
                if (!CommandParser.GetReal(p, value, "Alpha", ref alpha, 0, 1))
                {
                    return;
                }

                zone.UnshowAll(p.level);
                zone.Config.ShowAlpha = (byte)(alpha * 255);
                zone.ShowAll(p.level);
            }
            else if (opt.CaselessEq("col"))
            {
                if (!CommandParser.GetHex(p, value, ref desc))
                {
                    return;
                }

                zone.Config.ShowColor = value;
                zone.ShowAll(p.level);
            }
            else if (opt.CaselessEq("motd"))
            {
                zone.Config.MOTD = value;
                OnChangedZone(zone);
            }
            else if (CmdEnvironment.Handle(p, selector, opt, value, zone.Config, "zone " + zone.ColoredName))
            {
                OnChangedZone(zone);
            }
            else
            {
                Help(p, "properties"); return;
            }
            p.level.Save(true);
        }
示例#12
0
        /// <summary> Attempts to parse the given argument as a hex color. </summary>
        public static bool GetHex(Player p, string input, ref ColorDesc col)
        {
            if (input.Length > 0 && input[0] == '#')
            {
                input = input.Substring(1);
            }

            if (!Utils.IsValidHex(input))
            {
                Player.Message(p, "\"#{0}\" is not a valid HEX color.", input); return(false);
            }

            col = Colors.ParseHex(input); return(true);
        }
示例#13
0
        static Color GetCol(char c, Color foreCol)
        {
            if (c == 'S' || c == 'f' || c == 'F' || c == '0')
            {
                return(foreCol);
            }
            Colors.Map(ref c);

            if (!Colors.IsDefined(c))
            {
                return(foreCol);
            }
            ColorDesc col = Colors.Get(c);

            return(Color.FromArgb(col.R, col.G, col.B));
        }
示例#14
0
        internal static Color LookupColor(char colCode, out Color textCol)
        {
            Color     rgb = default(Color);
            ColorDesc col = Colors.Get(colCode);

            if (col.Undefined)
            {
                rgb = Color.White;
            }
            else
            {
                rgb = Color.FromArgb(col.R, col.G, col.B);
            }

            textCol = ColorUtils.CalcBackgroundColor(rgb);
            return(rgb);
        }
示例#15
0
        void AddHandler(Player p, string[] args)
        {
            if (args.Length <= 4)
            {
                Help(p); return;
            }

            char code = args[1][0];

            if (Colors.IsStandard(code))
            {
                p.Message("You may only edit standard codes using %T/CustomColors edit"); return;
            }
            if (code == ' ' || code == '\0' || code == '\u00a0' || code == '%' || code == '&')
            {
                p.Message("{0} must be a standard ASCII character.", code);
                p.Message("It also cannot be a space, percentage, or ampersand.");
                return;
            }

            char code2 = code;

            if (Colors.Map(ref code2))
            {
                p.Message("There is already an existing or server defined color with the code " + code +
                          ", you must either use a different code or use %T/CustomColors remove " + code);
                return;
            }

            char fallback;

            if (!CheckName(p, args[2]) || !CheckFallback(p, args[3], code, out fallback))
            {
                return;
            }
            ColorDesc col = default(ColorDesc);

            if (!CommandParser.GetHex(p, args[4], ref col))
            {
                return;
            }

            col.Code = code; col.Fallback = fallback; col.Name = args[2];
            Colors.Update(col);
            p.Message("Successfully added a color.");
        }
示例#16
0
        Color GetColor(string name)
        {
            string code = Colors.Parse(name);

            if (code.Length == 0)
            {
                return(SystemColors.Control);
            }
            if (Colors.IsStandard(code[1]))
            {
                return(Color.FromName(name));
            }

            ColorDesc col = Colors.Get(code[1]);

            return(Color.FromArgb(col.R, col.G, col.B));
        }
示例#17
0
        static void RainbowCallback(SchedulerTask task)
        {
            index = (index + 1) % colors.Length;

            ColorDesc desc = Colors.ParseHex(colors[index]);

            desc.Code = 'r';
            Player[] players = PlayerInfo.Online.Items;

            foreach (Player p in players)
            {
                if (!p.Supports(CpeExt.TextColors))
                {
                    continue;
                }
                p.Send(Packet.SetTextColor(desc));
            }
        }
示例#18
0
        internal static Color LookupColor(char colCode, out Color textCol)
        {
            Color     rgb = default(Color);
            ColorDesc col = Colors.Get(colCode);

            if (col.Undefined)
            {
                rgb = Color.White;
            }
            else
            {
                rgb = Color.FromArgb(col.R, col.G, col.B);
            }

            double r = Map(rgb.R), g = Map(rgb.G), b = Map(rgb.B);
            double L = 0.2126 * r + 0.7152 * g + 0.0722 * b;

            textCol = L > 0.179 ? Color.Black : Color.White;
            return(rgb);
        }
示例#19
0
        void AddHandler(Player p, string[] args)
        {
            if (args.Length <= 4)
            {
                Help(p); return;
            }
            char code = args[1][0];

            if (code >= 'A' && code <= 'F')
            {
                code += ' ';
            }

            if (code == ' ' || code == '\0' || code == '\u00a0' || code == '%' || code == '&')
            {
                p.Message("&WColor code cannot be a space, percentage, or ampersand.");
                return;
            }
            if (Colors.IsSystem(code))
            {
                p.Message("&WCannot change system defined color codes using %T/CustomColors");
                return;
            }

            char fallback;

            if (!CheckName(p, args[2]) || !CheckFallback(p, args[3], code, out fallback))
            {
                return;
            }
            ColorDesc col = default(ColorDesc);

            if (!CommandParser.GetHex(p, args[4], ref col))
            {
                return;
            }

            col.Code = code; col.Fallback = fallback; col.Name = args[2];
            Colors.Update(col);
            p.Message("Successfully added '{0}' color", code);
        }
示例#20
0
        void CalcLayerColors()
        {
            PaletteEntry[] front = new PaletteEntry[Palette.Entries.Length];
            PaletteEntry[] back  = new PaletteEntry[Palette.Entries.Length];

            ColorDesc sun  = Colors.ParseHex("FFFFFF");
            ColorDesc dark = Colors.ParseHex("9B9B9B");

            if (Utils.IsValidHex(Level.Config.LightColor))
            {
                sun = Colors.ParseHex(Level.Config.LightColor);
            }
            if (Utils.IsValidHex(Level.Config.ShadowColor))
            {
                dark = Colors.ParseHex(Level.Config.ShadowColor);
            }

            for (int i = 0; i < Palette.Entries.Length; i++)
            {
                PaletteEntry    entry = Palette.Entries[i];
                ExtBlock        block = ExtBlock.FromRaw(entry.Raw);
                BlockDefinition def   = Level.GetBlockDef(block);

                if (def != null && def.FullBright)
                {
                    front[i] = Multiply(entry, Colors.ParseHex("FFFFFF"));
                    back[i]  = Multiply(entry, Colors.ParseHex("FFFFFF"));
                }
                else
                {
                    front[i] = Multiply(entry, sun);
                    back[i]  = Multiply(entry, dark);
                }
            }
            selector.SetPalette(front, back);
        }
示例#21
0
        static bool DoEdit(Player p, Level lvl, BlockID block, string[] parts,
                           bool global, string cmd)
        {
            BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : lvl.CustomBlockDefs;
            BlockDefinition   def = defs[block], globalDef = BlockDefinition.GlobalDefs[block];

            if (def == null && block < Block.CpeCount)
            {
                def = DefaultSet.MakeCustomBlock(block);
                UpdateBlock(p, lvl, def, global);
            }
            if (def != null && !global && def == globalDef)
            {
                def = globalDef.Copy();
                UpdateBlock(p, lvl, def, global);
            }
            if (!ExistsInScope(def, block, global))
            {
                MessageNoBlock(p, block, global, cmd); return(false);
            }

            string value = parts[3], blockName = def.Name;
            bool   temp = false, changedFallback = false;

            string arg = MapPropertyName(parts[2].ToLower());

            switch (arg)
            {
            case "name":
                def.Name = value; break;

            case "collide":
                if (!EditByte(p, value, "Collide type", ref def.CollideType, arg))
                {
                    return(false);
                }
                break;

            case "speed":
                if (!CommandParser.GetReal(p, value, "Movement speed", ref def.Speed, 0.25f, 3.96f))
                {
                    SendEditHelp(p, arg); return(false);
                }
                break;

            case "toptex":
                if (!EditUShort(p, value, "Top texture", ref def.TopTex, arg))
                {
                    return(false);
                }
                break;

            case "alltex":
                if (!EditUShort(p, value, "All textures", ref def.RightTex, arg))
                {
                    return(false);
                }
                def.SetAllTex(def.RightTex);
                break;

            case "sidetex":
                if (!EditUShort(p, value, "Side texture", ref def.RightTex, arg))
                {
                    return(false);
                }
                def.SetSideTex(def.RightTex);
                break;

            case "lefttex":
                if (!EditUShort(p, value, "Left texture", ref def.LeftTex, arg))
                {
                    return(false);
                }
                break;

            case "righttex":
                if (!EditUShort(p, value, "Right texture", ref def.RightTex, arg))
                {
                    return(false);
                }
                break;

            case "fronttex":
                if (!EditUShort(p, value, "Front texture", ref def.FrontTex, arg))
                {
                    return(false);
                }
                break;

            case "backtex":
                if (!EditUShort(p, value, "Back texture", ref def.BackTex, arg))
                {
                    return(false);
                }
                break;

            case "bottomtex":
                if (!EditUShort(p, value, "Bottom texture", ref def.BottomTex, arg))
                {
                    return(false);
                }
                break;

            case "blockslight":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return(false);
                }
                def.BlocksLight = temp;
                break;

            case "sound":
                if (!EditByte(p, value, "Walk sound", ref def.WalkSound, arg))
                {
                    return(false);
                }
                break;

            case "fullbright":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return(false);
                }
                def.FullBright = temp;
                break;

            case "shape":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return(false);
                }
                def.Shape = temp ? (byte)0 : def.MaxZ;
                break;

            case "blockdraw":
                if (!EditByte(p, value, "Block draw", ref def.BlockDraw, arg))
                {
                    return(false);
                }
                break;

            case "min":
                if (!ParseCoords(p, value, ref def.MinX, ref def.MinY, ref def.MinZ))
                {
                    SendEditHelp(p, arg); return(false);
                }
                break;

            case "max":
                if (!ParseCoords(p, value, ref def.MaxX, ref def.MaxY, ref def.MaxZ))
                {
                    SendEditHelp(p, arg); return(false);
                }
                break;

            case "fogdensity":
                if (!EditByte(p, value, "Fog density", ref def.FogDensity, arg))
                {
                    return(false);
                }
                break;

            case "fogcolor":
                ColorDesc rgb = default(ColorDesc);
                if (!CommandParser.GetHex(p, value, ref rgb))
                {
                    return(false);
                }
                def.FogR = rgb.R; def.FogG = rgb.G; def.FogB = rgb.B;
                break;

            case "fallback":
                byte fallback = GetFallback(p, value);
                if (fallback == Block.Invalid)
                {
                    return(false);
                }
                changedFallback = true;

                value        = Block.GetName(p, fallback);
                def.FallBack = fallback; break;

            case "order":
                int order = 0;
                if (!CommandParser.GetInt(p, value, "Inventory order", ref order, 0, Block.MaxRaw))
                {
                    SendEditHelp(p, arg); return(false);
                }

                // Don't let multiple blocks be assigned to same order
                if (order != def.RawID && order != 0)
                {
                    for (int i = 0; i < defs.Length; i++)
                    {
                        if (defs[i] == null || defs[i].InventoryOrder != order)
                        {
                            continue;
                        }
                        p.Message("Block {0} already had order {1}", defs[i].Name, order);
                        return(false);
                    }
                }

                def.InventoryOrder = order == def.RawID ? -1 : order;
                BlockDefinition.UpdateOrder(def, global, lvl);
                p.Message("Set inventory order for {0} to {1}", blockName,
                          order == def.RawID ? "default" : order.ToString());
                return(true);

            default:
                p.Message("Unrecognised property: " + arg); return(false);
            }

            p.Message("Set {0} for {1} to {2}", arg, blockName, value);
            BlockDefinition.Add(def, defs, lvl);
            if (changedFallback)
            {
                BlockDefinition.UpdateFallback(global, def.GetBlock(), lvl);
            }
            return(true);
        }
示例#22
0
        static void DefineBlockStep(Player p, Level lvl, string value,
                                    bool global, string cmd)
        {
            string          opt  = value.ToLower();
            int             step = GetStep(p, global);
            BlockDefinition bd   = GetBD(p, global);
            bool            temp = false;

            if (opt == "revert" && step > 2)
            {
                if (step == 17 && bd.FogDensity == 0)
                {
                    step -= 2;
                }
                else if (step == 9 && bd.Shape == 0)
                {
                    step -= 5;
                }
                else
                {
                    step--;
                }

                SetStep(p, global, step);
                SendStepHelp(p, global);
                return;
            }

            if (step == 2)
            {
                bd.Name = value;
                step++;
            }
            else if (step == 3)
            {
                if (CommandParser.GetBool(p, value, ref temp))
                {
                    bd.Shape = temp ? (byte)0 : (byte)16;
                    step++;
                }
            }
            else if (step == 4)
            {
                if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.TopTex))
                {
                    step += (bd.Shape == 0 ? 5 : 1); // skip other texture steps for sprites
                    if (bd.Shape == 0)
                    {
                        bd.SetAllTex(bd.TopTex);
                    }
                }
            }
            else if (step == 5)
            {
                if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.RightTex))
                {
                    bd.SetSideTex(bd.RightTex);
                    step++;
                }
            }
            else if (step == 6)
            {
                if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.BottomTex))
                {
                    step++;
                }
            }
            else if (step == 7)
            {
                if (ParseCoords(p, value, ref bd.MinX, ref bd.MinY, ref bd.MinZ))
                {
                    step++;
                }
            }
            else if (step == 8)
            {
                if (ParseCoords(p, value, ref bd.MaxX, ref bd.MaxY, ref bd.MaxZ))
                {
                    step++;
                }
                bd.Shape = bd.MaxY;
            }
            else if (step == 9)
            {
                if (CommandParser.GetByte(p, value, "Collide type", ref bd.CollideType, 0, 7))
                {
                    step++;
                }
            }
            else if (step == 10)
            {
                if (CommandParser.GetReal(p, value, "Movement speed", ref bd.Speed, 0.25f, 3.96f))
                {
                    step++;
                }
            }
            else if (step == 11)
            {
                if (CommandParser.GetBool(p, value, ref temp))
                {
                    bd.BlocksLight = temp;
                    step++;
                }
            }
            else if (step == 12)
            {
                if (CommandParser.GetByte(p, value, "Walk sound", ref bd.WalkSound, 0, 11))
                {
                    step++;
                }
            }
            else if (step == 13)
            {
                if (CommandParser.GetBool(p, value, ref bd.FullBright))
                {
                    step++;
                }
            }
            else if (step == 14)
            {
                if (CommandParser.GetByte(p, value, "Block draw", ref bd.BlockDraw, 0, 4))
                {
                    step++;
                }
            }
            else if (step == 15)
            {
                if (CommandParser.GetByte(p, value, "Fog density", ref bd.FogDensity))
                {
                    step += (bd.FogDensity == 0 ? 2 : 1);
                }
            }
            else if (step == 16)
            {
                ColorDesc rgb = default(ColorDesc);
                if (CommandParser.GetHex(p, value, ref rgb))
                {
                    bd.FogR = rgb.R; bd.FogG = rgb.G; bd.FogB = rgb.B;
                    step++;
                }
            }
            else if (step == 17)
            {
                byte fallback = GetFallback(p, value);
                if (fallback == Block.Invalid)
                {
                    SendStepHelp(p, global); return;
                }
                bd.FallBack = fallback;

                if (!AddBlock(p, lvl, bd, global, cmd))
                {
                    return;
                }
                BlockDefinition.Save(global, lvl);

                SetBD(p, global, null);
                SetStep(p, global, 0);
                return;
            }

            SetStep(p, global, step);
            SendStepHelp(p, global);
        }
示例#23
0
 /// <summary> Sends an update text color code packet to the client </summary>
 public abstract bool SendSetTextColor(ColorDesc color);
示例#24
0
        void SetZoneProp(Player p, string[] args, Zone zone)
        {
            ColorDesc desc = default(ColorDesc);

            if (args.Length < 4)
            {
                p.Message("No value provided. See &T/Help zone properties");
                return;
            }

            string opt = args[2], value = args[3];

            if (opt.CaselessEq("alpha"))
            {
                float alpha = 0;
                if (!CommandParser.GetReal(p, value, "Alpha", ref alpha, 0, 1))
                {
                    return;
                }

                zone.UnshowAll(p.level);
                zone.Config.ShowAlpha = (byte)(alpha * 255);
                zone.ShowAll(p.level);
            }
            else if (opt.CaselessEq("col"))
            {
                if (!CommandParser.GetHex(p, value, ref desc))
                {
                    return;
                }

                zone.Config.ShowColor = value;
                zone.ShowAll(p.level);
            }
            else if (opt.CaselessEq("motd"))
            {
                zone.Config.MOTD = value;
                OnChangedZone(zone);
            }
            else if (opt.CaselessEq("text"))
            {
                if (value == "null")
                {
                    zone.Config.Text = "";
                }
                else
                {
                    bool allCmds = HasExtraPerm(p, "MB", p.Rank, 1);
                    if (!MessageBlock.Validate(p, value, allCmds))
                    {
                        return;
                    }
                    zone.Config.Text = value;
                    OnChangedZone(zone);
                }
            }
            else if (CmdEnvironment.Handle(p, p.level, opt, value, zone.Config, "zone " + zone.ColoredName))
            {
                OnChangedZone(zone);
            }
            else
            {
                Help(p, "properties"); return;
            }
            p.level.Save(true);
        }
示例#25
0
        static void EditHandler(Player p, string[] parts, bool global, string cmd)
        {
            if (parts.Length <= 3)
            {
                if (parts.Length == 1)
                {
                    Player.Message(p, "Valid properties: " + helpSections.Keys.Join());
                }
                else if (parts.Length == 3)
                {
                    Help(p, cmd, "edit " + parts[2]);
                }
                else
                {
                    Help(p, cmd);
                }
                return;
            }

            ExtBlock block;

            if (!CheckBlock(p, parts[1], out block))
            {
                return;
            }
            BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : p.level.CustomBlockDefs;
            BlockDefinition   def = defs[block.RawID], globalDef = BlockDefinition.GlobalDefs[block.RawID];

            if (def == null && block.BlockID < Block.CpeCount)
            {
                def = DefaultSet.MakeCustomBlock(block.BlockID);
                AddBlock(p, def, global, cmd, BlockDefinition.DefaultProps(block));
            }
            if (def != null && !global && def == globalDef)
            {
                def = globalDef.Copy();
                AddBlock(p, def, global, cmd, BlockDefinition.DefaultProps(block));
            }
            if (!ExistsInScope(def, block, global))
            {
                MessageNoBlock(p, block, global, cmd); return;
            }

            string value = parts[3], blockName = def.Name;
            float  fTemp;
            bool   temp = false, changedFallback = false;
            Level  level = p == null ? null : p.level;

            string arg = MapPropertyName(parts[2].ToLower());

            switch (arg)
            {
            case "name":
                def.Name = value; break;

            case "collide":
                if (!EditByte(p, value, "Collide type", ref def.CollideType, arg))
                {
                    return;
                }
                break;

            case "speed":
                if (!Utils.TryParseDecimal(value, out fTemp) || fTemp < 0.25f || fTemp > 3.96f)
                {
                    SendEditHelp(p, arg); return;
                }
                def.Speed = fTemp; break;

            case "toptex":
                if (!EditByte(p, value, "Top texture", ref def.TopTex, arg))
                {
                    return;
                }
                break;

            case "alltex":
                if (!EditByte(p, value, "All textures", ref def.SideTex, arg))
                {
                    return;
                }
                def.SetAllTex(def.SideTex);
                break;

            case "sidetex":
                if (!EditByte(p, value, "Side texture", ref def.SideTex, arg))
                {
                    return;
                }
                def.SetSideTex(def.SideTex);
                break;

            case "lefttex":
                if (!EditByte(p, value, "Left texture", ref def.LeftTex, arg))
                {
                    return;
                }
                break;

            case "righttex":
                if (!EditByte(p, value, "Right texture", ref def.RightTex, arg))
                {
                    return;
                }
                break;

            case "fronttex":
                if (!EditByte(p, value, "Front texture", ref def.FrontTex, arg))
                {
                    return;
                }
                break;

            case "backtex":
                if (!EditByte(p, value, "Back texture", ref def.BackTex, arg))
                {
                    return;
                }
                break;

            case "bottomtex":
                if (!EditByte(p, value, "Bottom texture", ref def.BottomTex, arg))
                {
                    return;
                }
                break;

            case "blockslight":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return;
                }
                def.BlocksLight = temp;
                break;

            case "sound":
                if (!EditByte(p, value, "Walk sound", ref def.WalkSound, arg))
                {
                    return;
                }
                break;

            case "fullbright":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return;
                }
                def.FullBright = temp;
                break;

            case "shape":
                if (!CommandParser.GetBool(p, value, ref temp))
                {
                    SendEditHelp(p, arg); return;
                }
                def.Shape = temp ? (byte)0 : def.MaxZ;
                break;

            case "blockdraw":
                if (!EditByte(p, value, "Block draw", ref def.BlockDraw, arg))
                {
                    return;
                }
                break;

            case "min":
                if (!ParseCoords(p, value, ref def.MinX, ref def.MinY, ref def.MinZ))
                {
                    SendEditHelp(p, arg); return;
                }
                break;

            case "max":
                if (!ParseCoords(p, value, ref def.MaxX, ref def.MaxY, ref def.MaxZ))
                {
                    SendEditHelp(p, arg); return;
                }
                break;

            case "fogdensity":
                if (!EditByte(p, value, "Fog density", ref def.FogDensity, arg))
                {
                    return;
                }
                break;

            case "fogcolor":
                ColorDesc rgb = default(ColorDesc);
                if (!CommandParser.GetHex(p, value, ref rgb))
                {
                    return;
                }
                def.FogR = rgb.R; def.FogG = rgb.G; def.FogB = rgb.B;
                break;

            case "fallback":
                byte fallback = GetFallback(p, value);
                if (fallback == Block.Invalid)
                {
                    return;
                }
                changedFallback = true;

                value        = Block.Name(fallback);
                def.FallBack = fallback; break;

            case "order":
                int order = 0;
                if (!CommandParser.GetInt(p, value, "Inventory order", ref order, 1, 255))
                {
                    SendEditHelp(p, arg); return;
                }

                def.InventoryOrder = order == def.BlockID ? -1 : order;
                BlockDefinition.UpdateOrder(def, global, level);
                BlockDefinition.Save(global, level);
                Player.Message(p, "Set inventory order for {0} to {1}", blockName,
                               order == def.BlockID ? "default" : order.ToString());
                return;

            default:
                Player.Message(p, "Unrecognised property: " + arg); return;
            }

            Player.Message(p, "Set {0} for {1} to {2}", arg, blockName, value);
            BlockDefinition.Add(def, defs, level);
            if (changedFallback)
            {
                BlockDefinition.UpdateFallback(global, def.BlockID, level);
            }
        }