From 7ff12b4026fa2bc6474365ea2b32ab14f10e96ca Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 19 Jul 2018 17:25:18 +1000 Subject: [PATCH] Move JSON parsing into core --- MCGalaxy/Blocks/BlockDefinitions.cs | 216 +++++++++++--------- MCGalaxy/Blocks/DefaultSet.cs | 1 - MCGalaxy/Bots/BotsFile.cs | 130 +++++++----- MCGalaxy/Bots/PlayerBot.cs | 2 +- MCGalaxy/Chat/Colors.cs | 81 ++++---- MCGalaxy/Commands/CPE/CustomBlockCommand.cs | 27 ++- MCGalaxy/Config/ConfigElement.cs | 2 + MCGalaxy/Config/JSON.cs | 203 ++++++++++++++++++ MCGalaxy/Config/NumberAttributes.cs | 34 ++- MCGalaxy/Config/OtherAttributes.cs | 6 + MCGalaxy/Config/StringAttributes.cs | 5 +- MCGalaxy/Levels/IO/Importers/CwImporter.cs | 4 +- MCGalaxy/MCGalaxy_.csproj | 4 +- MCGalaxy/Network/Heartbeat/ClassiCube.cs | 66 +++--- MCGalaxy/Network/Packets/Packet.cs | 6 +- MCGalaxy/Network/Player.Networking.cs | 2 +- MCGalaxy/Server/Server.cs | 1 - MCGalaxy/Server/Tasks/UpgradeTasks.cs | 12 +- 18 files changed, 548 insertions(+), 254 deletions(-) create mode 100644 MCGalaxy/Config/JSON.cs diff --git a/MCGalaxy/Blocks/BlockDefinitions.cs b/MCGalaxy/Blocks/BlockDefinitions.cs index 695756dd1..2ed162ab1 100644 --- a/MCGalaxy/Blocks/BlockDefinitions.cs +++ b/MCGalaxy/Blocks/BlockDefinitions.cs @@ -18,37 +18,54 @@ using System; using System.IO; using MCGalaxy.Blocks; +using MCGalaxy.Config; using MCGalaxy.Network; -using Newtonsoft.Json; -using BlockID_ = System.UInt16; -using BlockRaw = System.Byte; +using BlockID = System.UInt16; namespace MCGalaxy { public sealed class BlockDefinition { - public ushort BlockID; // really raw block ID - public string Name; - public byte CollideType; - public float Speed; - public ushort TopTex, SideTex, BottomTex; - public bool BlocksLight; - public byte WalkSound; - public bool FullBright; - public byte Shape; - public byte BlockDraw; - public byte FogDensity, FogR, FogG, FogB; - public byte FallBack; - // BlockDefinitionsExt fields - public byte MinX, MinY, MinZ; - public byte MaxX, MaxY, MaxZ; - // BlockDefinitionsExt version 2 fields - public bool Version2; - public ushort LeftTex, RightTex, FrontTex, BackTex; + [ConfigUShort("BlockID", null)] + public ushort RawID; + [ConfigString] public string Name; + [ConfigReal] public float Speed; + [ConfigByte] public byte CollideType; + [ConfigUShort] public ushort TopTex; + [ConfigUShort] ushort SideTex; + [ConfigUShort] public ushort BottomTex; + [ConfigBool] public bool BlocksLight; + [ConfigByte] public byte WalkSound; + [ConfigBool] public bool FullBright; + [ConfigByte] public byte Shape; + [ConfigByte] public byte BlockDraw; + [ConfigByte] public byte FallBack; + + [ConfigByte] public byte FogDensity; + [ConfigByte] public byte FogR; + [ConfigByte] public byte FogG; + [ConfigByte] public byte FogB; + + // BlockDefinitionsExt fields + [ConfigByte] public byte MinX; + [ConfigByte] public byte MinY; + [ConfigByte] public byte MinZ; + [ConfigByte] public byte MaxX; + [ConfigByte] public byte MaxY; + [ConfigByte] public byte MaxZ; + + // BlockDefinitionsExt version 2 fields + [ConfigBool] bool Version2; + [ConfigUShort] public ushort LeftTex; + [ConfigUShort] public ushort RightTex; + [ConfigUShort] public ushort FrontTex; + [ConfigUShort] public ushort BackTex; + + [ConfigInt(null, null, -1, -1)] public int InventoryOrder = -1; - public BlockID_ GetBlock() { return Block.FromRaw(BlockID); } - public void SetBlock(BlockID_ b) { BlockID = Block.ToRaw(b); } + public BlockID GetBlock() { return Block.FromRaw(RawID); } + public void SetBlock(BlockID b) { RawID = Block.ToRaw(b); } public const string GlobalPath = "blockdefs/global.json", GlobalBackupPath = "blockdefs/global.json.bak"; @@ -56,80 +73,84 @@ namespace MCGalaxy { public BlockDefinition Copy() { BlockDefinition def = new BlockDefinition(); - def.BlockID = BlockID; def.Name = Name; + def.RawID = RawID; def.Name = Name; def.CollideType = CollideType; def.Speed = Speed; - def.TopTex = TopTex; def.SideTex = SideTex; - def.BottomTex = BottomTex; def.BlocksLight = BlocksLight; - def.WalkSound = WalkSound; def.FullBright = FullBright; - def.Shape = Shape; def.BlockDraw = BlockDraw; - def.FogDensity = FogDensity; def.FogR = FogR; - def.FogG = FogG; def.FogB = FogB; + def.TopTex = TopTex; def.BottomTex = BottomTex; + def.BlocksLight = BlocksLight; def.WalkSound = WalkSound; + def.FullBright = FullBright; def.Shape = Shape; + def.BlockDraw = BlockDraw; def.FogDensity = FogDensity; + def.FogR = FogR; def.FogG = FogG; def.FogB = FogB; def.FallBack = FallBack; def.MinX = MinX; def.MinY = MinY; def.MinZ = MinZ; def.MaxX = MaxX; def.MaxY = MaxY; def.MaxZ = MaxZ; - def.Version2 = Version2; def.LeftTex = LeftTex; def.RightTex = RightTex; def.FrontTex = FrontTex; def.BackTex = BackTex; def.InventoryOrder = InventoryOrder; return def; } - + static ConfigElement[] elems; public static BlockDefinition[] Load(bool global, string mapName) { - BlockDefinition[] defs = null; + BlockDefinition[] defs = new BlockDefinition[Block.ExtendedCount]; string path = global ? GlobalPath : "blockdefs/lvl_" + mapName + ".json"; + if (!File.Exists(path)) return defs; + if (elems == null) elems = ConfigElement.GetAll(typeof(BlockDefinition)); + try { - if (File.Exists(path)) { - string json = File.ReadAllText(path); - defs = JsonConvert.DeserializeObject(json); - } - } catch (Exception ex) { - Logger.LogError("Error Loading block defs from " + path, ex); - } - - if (defs == null) return new BlockDefinition[Block.ExtendedCount]; - - for (int i = 0; i < defs.Length; i++) { - if (defs[i] != null && defs[i].Name == null) defs[i] = null; - BlockDefinition def = defs[i]; - if (def == null) continue; + JsonContext ctx = new JsonContext(); + ctx.Val = File.ReadAllText(path); + JsonArray array = (JsonArray)Json.ParseStream(ctx); + if (array == null) return defs; - if (!def.Version2) { - def.Version2 = true; - def.SetSideTex(def.SideTex); + foreach (object raw in array) { + JsonObject obj = (JsonObject)raw; + if (obj == null) continue; + + BlockDefinition def = new BlockDefinition(); + obj.Deserialise(elems, def, "Block definition"); + if (String.IsNullOrEmpty(def.Name)) continue; + + BlockID block = def.GetBlock(); + if (block >= defs.Length) { + Logger.Log(LogType.Warning, "Invalid block ID: " + def.RawID); + } else { + defs[block] = def; + } } + } catch (Exception ex) { + Logger.LogError("Error Loading block defs from " + path, ex); } - - // Need to adjust index of raw block ID - BlockDefinition[] adjDefs = new BlockDefinition[Block.ExtendedCount]; - for (int b = 0; b < defs.Length; b++) { - BlockDefinition def = defs[b]; - if (def == null) continue; - - BlockID_ block = def.GetBlock(); - if (block >= adjDefs.Length) { - Logger.Log(LogType.Warning, "Invalid block ID: " + block); - } else { - adjDefs[block] = def; - } - } - return adjDefs; + return defs; } public static void Save(bool global, Level lvl) { - BlockDefinition[] defs = global ? GlobalDefs : lvl.CustomBlockDefs; - // We don't want to save global blocks in the level's custom blocks list - if (!global) { - BlockDefinition[] realDefs = new BlockDefinition[defs.Length]; - for (int i = 0; i < defs.Length; i++) { - realDefs[i] = defs[i] == GlobalDefs[i] ? null : defs[i]; - } - defs = realDefs; - } - - string json = JsonConvert.SerializeObject(defs, Formatting.Indented); + if (elems == null) elems = ConfigElement.GetAll(typeof(BlockDefinition)); string path = global ? GlobalPath : "blockdefs/lvl_" + lvl.MapName + ".json"; - File.WriteAllText(path, json); + BlockDefinition[] defs = global ? GlobalDefs : lvl.CustomBlockDefs; + + using (StreamWriter w = new StreamWriter(path)) { + w.WriteLine("["); + SaveEntries(w, global, defs); + w.WriteLine(); + w.WriteLine("]"); + } + } + + static void SaveEntries(StreamWriter w, bool global, BlockDefinition[] defs) { + bool first = true; + for (int i = 0; i < defs.Length; i++) { + BlockDefinition def = defs[i]; + // don't want to save global blocks in the level's custom blocks list + if (!global && def == GlobalDefs[i]) def = null; + + if (def == null) continue; + def.SideTex = def.RightTex; def.Version2 = true; + + // need to add ',' from last element + if (!first) w.WriteLine(", "); + Json.Serialise(w, elems, def); + first = false; + } } public static void LoadGlobal() { @@ -141,8 +162,8 @@ namespace MCGalaxy { if (File.Exists(GlobalPath)) { File.Copy(GlobalPath, GlobalBackupPath, true); } - } catch (Exception ex) { - Logger.LogError("Error backing up global block defs", ex); + } catch (Exception ex) { + Logger.LogError("Error backing up global block defs", ex); } // As the BlockDefinition instances in levels will now be different @@ -160,14 +181,14 @@ namespace MCGalaxy { if ((lvl.Props[b].ChangedScope & 2) == 0) { lvl.Props[b] = Block.Props[b]; } - lvl.UpdateCustomBlock((BlockID_)b, GlobalDefs[b]); + lvl.UpdateCustomBlock((BlockID)b, GlobalDefs[b]); } } } public static void Add(BlockDefinition def, BlockDefinition[] defs, Level level) { - BlockID_ block = def.GetBlock(); + BlockID block = def.GetBlock(); bool global = defs == GlobalDefs; if (global) UpdateGlobalCustom(block, def); @@ -178,7 +199,7 @@ namespace MCGalaxy { Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (!global && pl.level != level) continue; - if (!pl.hasBlockDefs || def.BlockID > pl.MaxRawBlock) continue; + if (!pl.hasBlockDefs || def.RawID > pl.MaxRawBlock) continue; if (global && pl.level.CustomBlockDefs[block] != GlobalDefs[block]) continue; pl.Send(def.MakeDefinePacket(pl)); @@ -188,7 +209,7 @@ namespace MCGalaxy { } public static void Remove(BlockDefinition def, BlockDefinition[] defs, Level level) { - BlockID_ block = def.GetBlock(); + BlockID block = def.GetBlock(); bool global = defs == GlobalDefs; if (global) UpdateGlobalCustom(block, null); @@ -199,7 +220,7 @@ namespace MCGalaxy { Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (!global && pl.level != level) continue; - if (!pl.hasBlockDefs || def.BlockID > pl.MaxRawBlock) continue; + if (!pl.hasBlockDefs || def.RawID > pl.MaxRawBlock) continue; if (global && pl.level.CustomBlockDefs[block] != null) continue; pl.Send(Packet.UndefineBlock(def, pl.hasExtBlocks)); @@ -211,12 +232,12 @@ namespace MCGalaxy { Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (!global && pl.level != level) continue; - if (!pl.Supports(CpeExt.InventoryOrder) || def.BlockID > pl.MaxRawBlock) continue; + if (!pl.Supports(CpeExt.InventoryOrder) || def.RawID > pl.MaxRawBlock) continue; SendLevelInventoryOrder(pl); } } - static void UpdateGlobalCustom(BlockID_ block, BlockDefinition def) { + static void UpdateGlobalCustom(BlockID block, BlockDefinition def) { Level[] loaded = LevelInfo.Loaded.Items; foreach (Level lvl in loaded) { if (lvl.CustomBlockDefs[block] != GlobalDefs[block]) continue; @@ -225,12 +246,11 @@ namespace MCGalaxy { } public void SetAllTex(ushort id) { - SetSideTex(id); + SetSideTex(id); TopTex = id; BottomTex = id; } public void SetSideTex(ushort id) { - SideTex = id; LeftTex = id; RightTex = id; FrontTex = id; BackTex = id; } @@ -239,7 +259,7 @@ namespace MCGalaxy { BlockDefinition[] defs = pl.level.CustomBlockDefs; for (int i = 0; i < defs.Length; i++) { BlockDefinition def = defs[i]; - if (def == null || def.BlockID > pl.MaxRawBlock) continue; + if (def == null || def.RawID > pl.MaxRawBlock) continue; pl.Send(def.MakeDefinePacket(pl)); } } @@ -258,23 +278,23 @@ namespace MCGalaxy { // Fill slots with explicit order for (int i = 0; i < defs.Length; i++) { BlockDefinition def = defs[i]; - if (def == null || def.BlockID > pl.MaxRawBlock) continue; + if (def == null || def.RawID > pl.MaxRawBlock) continue; if (def.InventoryOrder == -1) continue; if (def.InventoryOrder != 0) { if (order_to_blocks[def.InventoryOrder] != -1) continue; - order_to_blocks[def.InventoryOrder] = def.BlockID; + order_to_blocks[def.InventoryOrder] = def.RawID; } - block_to_orders[def.BlockID] = def.InventoryOrder; + block_to_orders[def.RawID] = def.InventoryOrder; } // Put blocks into their default slot if slot is unused for (int i = 0; i < defs.Length; i++) { BlockDefinition def = defs[i]; - int raw = def != null ? def.BlockID : i; + int raw = def != null ? def.RawID : i; if (raw > pl.MaxRawBlock || (def == null && raw >= Block.CpeCount)) continue; - if (def != null && def.InventoryOrder >= 0) continue; + if (def != null && def.InventoryOrder >= 0) continue; if (order_to_blocks[raw] == -1) { order_to_blocks[raw] = raw; block_to_orders[raw] = raw; @@ -284,7 +304,7 @@ namespace MCGalaxy { // Push blocks whose slots conflict with other blocks into free slots at end for (int i = defs.Length - 1; i >= 0; i--) { BlockDefinition def = defs[i]; - int raw = def != null ? def.BlockID : i; + int raw = def != null ? def.RawID : i; if (raw > pl.MaxRawBlock || (def == null && raw >= Block.CpeCount)) continue; if (block_to_orders[raw] != -1) continue; @@ -301,12 +321,12 @@ namespace MCGalaxy { int order = block_to_orders[raw]; if (order == -1) order = 0; - BlockDefinition def = defs[Block.FromRaw((BlockID_)raw)]; + BlockDefinition def = defs[Block.FromRaw((BlockID)raw)]; if (def == null && raw >= Block.CpeCount) continue; // Special case, don't want 255 getting hidden by default if (raw == 255 && def.InventoryOrder == -1) continue; - pl.Send(Packet.SetInventoryOrder((BlockID_)raw, (BlockID_)order, pl.hasExtBlocks)); + pl.Send(Packet.SetInventoryOrder((BlockID)raw, (BlockID)order, pl.hasExtBlocks)); } } @@ -320,7 +340,7 @@ namespace MCGalaxy { } } - public static void UpdateFallback(bool global, BlockID_ block, Level level) { + public static void UpdateFallback(bool global, BlockID block, Level level) { Player[] players = PlayerInfo.Online.Items; foreach (Player pl in players) { if (!global && pl.level != level) continue; diff --git a/MCGalaxy/Blocks/DefaultSet.cs b/MCGalaxy/Blocks/DefaultSet.cs index 7e86b4a93..e943db9ec 100644 --- a/MCGalaxy/Blocks/DefaultSet.cs +++ b/MCGalaxy/Blocks/DefaultSet.cs @@ -51,7 +51,6 @@ namespace MCGalaxy.Blocks { def.FallBack = (BlockRaw)b; def.MaxX = 16; def.MaxZ = Height(b); def.MaxY = 16; - def.Version2 = true; return def; } diff --git a/MCGalaxy/Bots/BotsFile.cs b/MCGalaxy/Bots/BotsFile.cs index 6674d10fc..18e4d1b76 100644 --- a/MCGalaxy/Bots/BotsFile.cs +++ b/MCGalaxy/Bots/BotsFile.cs @@ -16,67 +16,100 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using System.IO; -using MCGalaxy.Maths; -using Newtonsoft.Json; +using MCGalaxy.Config; namespace MCGalaxy.Bots { /// Maintains persistent data for in-game bots. public static class BotsFile { - public static string BotsPath(string mapName) { - return "extra/bots/" + mapName + ".json"; - } - + public static string BotsPath(string map) { return "extra/bots/" + map + ".json"; } + static ConfigElement[] elems; + public static void Load(Level lvl) { lock (lvl.botsIOLock) { LoadCore(lvl); } } static void LoadCore(Level lvl) { string path = BotsPath(lvl.MapName); if (!File.Exists(path)) return; string json = File.ReadAllText(path); - BotProperties[] bots = JsonConvert.DeserializeObject(json); + List props = null; - foreach (BotProperties props in bots) { - if (String.IsNullOrEmpty(props.DisplayName)) { - props.DisplayName = props.Name; - } - - PlayerBot bot = new PlayerBot(props.Name, lvl); - props.ApplyTo(bot); + try { + props = ReadAll(json); + } catch (Exception ex) { + Logger.LogError("Reading bots file", ex); return; + } + + foreach (BotProperties data in props) { + PlayerBot bot = new PlayerBot(data.Name, lvl); + data.ApplyTo(bot); bot.SetModel(bot.Model, lvl); - LoadAi(props, bot); + LoadAi(data, bot); PlayerBot.Add(bot, false); } } + internal static List ReadAll(string json) { + List props = new List(); + if (elems == null) elems = ConfigElement.GetAll(typeof(BotProperties)); + + JsonContext ctx = new JsonContext(); ctx.Val = json; + JsonArray array = (JsonArray)Json.ParseStream(ctx); + if (array == null) return props; + + foreach (object raw in array) { + JsonObject obj = (JsonObject)raw; + if (obj == null) continue; + + BotProperties data = new BotProperties(); + obj.Deserialise(elems, data, "Bot properties"); + + if (String.IsNullOrEmpty(data.DisplayName)) data.DisplayName = data.Name; + props.Add(data); + } + return props; + } + public static void Save(Level lvl) { lock (lvl.botsIOLock) { SaveCore(lvl); } } static void SaveCore(Level lvl) { PlayerBot[] bots = lvl.Bots.Items; string path = BotsPath(lvl.MapName); if (!File.Exists(path) && bots.Length == 0) return; - BotProperties[] props = new BotProperties[bots.Length]; - for (int i = 0; i < props.Length; i++) { - BotProperties savedProps = new BotProperties(); - savedProps.FromBot(bots[i]); - props[i] = savedProps; + List props = new List(bots.Length); + for (int i = 0; i < bots.Length; i++) { + BotProperties data = new BotProperties(); + data.FromBot(bots[i]); + props.Add(data); } - string json = JsonConvert.SerializeObject(props); try { - File.WriteAllText(path, json); + using (StreamWriter w = new StreamWriter(path)) { WriteAll(w, props); } } catch (Exception ex) { Logger.LogError("Error saving bots to " + path, ex); - } + } + } + + internal static void WriteAll(StreamWriter w, List props) { + w.WriteLine("["); + if (elems == null) elems = ConfigElement.GetAll(typeof(BotProperties)); + + for (int i = 0; i < props.Count; i++) { + Json.Serialise(w, elems, props[i]); + bool last = i == props.Count - 1; + w.WriteLine(last ? "" : ","); + } + w.WriteLine("]"); } internal static void LoadAi(BotProperties props, PlayerBot bot) { if (String.IsNullOrEmpty(props.AI)) return; try { ScriptFile.Parse(Player.Console, bot, props.AI); - } catch (Exception ex) { - Logger.LogError("Error loading bot AI " + props.AI, ex); + } catch (Exception ex) { + Logger.LogError("Error loading bot AI " + props.AI, ex); } bot.cur = props.CurInstruction; @@ -85,31 +118,32 @@ namespace MCGalaxy.Bots { } public sealed class BotProperties { - public string DisplayName { get; set; } - public string Name { get; set; } - public string Level { get; set; } - public string Skin { get; set; } - public string Model { get; set; } - public string Color { get; set; } - public string ClickedOnText { get; set; } - public string DeathMessage { get; set; } + [ConfigString] public string DisplayName; + [ConfigString] public string Name; + [ConfigString] public string Level; + [ConfigString] public string Skin; + [ConfigString] public string Model; + [ConfigString] public string Color; + [ConfigString] public string ClickedOnText; + [ConfigString] public string DeathMessage; - public string AI { get; set; } - public bool Kill { get; set; } - public bool Hunt { get; set; } - public int CurInstruction { get; set; } - public sbyte CurJump { get; set; } + [ConfigString] public string AI; + [ConfigBool] public bool Kill; + [ConfigBool] public bool Hunt; + [ConfigInt] public int CurInstruction; + [ConfigInt] public int CurJump; - public int X { get; set; } - public int Y { get; set; } - public int Z { get; set; } - public byte RotX { get; set; } - public byte RotY { get; set; } - public byte BodyX { get; set; } - public byte BodyZ { get; set; } - public float ScaleX { get; set; } - public float ScaleY { get; set; } - public float ScaleZ { get; set; } + [ConfigInt] public int X; + [ConfigInt] public int Y; + [ConfigInt] public int Z; + [ConfigByte] public byte RotX; + [ConfigByte] public byte RotY; + + [ConfigByte] public byte BodyX; + [ConfigByte] public byte BodyZ; + [ConfigReal] public float ScaleX; + [ConfigReal] public float ScaleY; + [ConfigReal] public float ScaleZ; public void FromBot(PlayerBot bot) { Name = bot.name; Level = bot.level.name; diff --git a/MCGalaxy/Bots/PlayerBot.cs b/MCGalaxy/Bots/PlayerBot.cs index 860998c33..9387421a0 100644 --- a/MCGalaxy/Bots/PlayerBot.cs +++ b/MCGalaxy/Bots/PlayerBot.cs @@ -44,7 +44,7 @@ namespace MCGalaxy { public Position TargetPos; public bool movement = false; public int movementSpeed = 3; - internal sbyte curJump = 0; + internal int curJump = 0; public PlayerBot(string n, Level lvl) { name = n; DisplayName = n; SkinName = n; diff --git a/MCGalaxy/Chat/Colors.cs b/MCGalaxy/Chat/Colors.cs index effb8d32f..e9d4465d5 100644 --- a/MCGalaxy/Chat/Colors.cs +++ b/MCGalaxy/Chat/Colors.cs @@ -69,22 +69,22 @@ namespace MCGalaxy { public static ColorDesc DefaultCol(char code) { switch (code) { - case '0': return new ColorDesc('0', "Black"); - case '1': return new ColorDesc('1', "Navy"); - case '2': return new ColorDesc('2', "Green"); - case '3': return new ColorDesc('3', "Teal"); - case '4': return new ColorDesc('4', "Maroon"); - case '5': return new ColorDesc('5', "Purple"); - case '6': return new ColorDesc('6', "Gold"); - case '7': return new ColorDesc('7', "Silver"); - case '8': return new ColorDesc('8', "Gray"); - case '9': return new ColorDesc('9', "Blue"); - case 'a': return new ColorDesc('a', "Lime"); - case 'b': return new ColorDesc('b', "Aqua"); - case 'c': return new ColorDesc('c', "Red"); - case 'd': return new ColorDesc('d', "Pink"); - case 'e': return new ColorDesc('e', "Yellow"); - case 'f': return new ColorDesc('f', "White"); + case '0': return new ColorDesc('0', "Black"); + case '1': return new ColorDesc('1', "Navy"); + case '2': return new ColorDesc('2', "Green"); + case '3': return new ColorDesc('3', "Teal"); + case '4': return new ColorDesc('4', "Maroon"); + case '5': return new ColorDesc('5', "Purple"); + case '6': return new ColorDesc('6', "Gold"); + case '7': return new ColorDesc('7', "Silver"); + case '8': return new ColorDesc('8', "Gray"); + case '9': return new ColorDesc('9', "Blue"); + case 'a': return new ColorDesc('a', "Lime"); + case 'b': return new ColorDesc('b', "Aqua"); + case 'c': return new ColorDesc('c', "Red"); + case 'd': return new ColorDesc('d', "Pink"); + case 'e': return new ColorDesc('e', "Yellow"); + case 'f': return new ColorDesc('f', "White"); } ColorDesc col = default(ColorDesc); @@ -120,21 +120,21 @@ namespace MCGalaxy { if (code >= 'A' && code <= 'F') code += ' '; return IsDefined(code) ? Get(code).Name : ""; } - + static readonly string[] ircColors = new string[] { - "\u000300", "\u000301", "\u000302", "\u000303", "\u000304", "\u000305", + "\u000300", "\u000301", "\u000302", "\u000303", "\u000304", "\u000305", "\u000306", "\u000307", "\u000308", "\u000309", "\u000310", "\u000311", "\u000312", "\u000313", "\u000314", "\u000315", }; static readonly string[] ircSingle = new string[] { - "\u00030", "\u00031", "\u00032", "\u00033", "\u00034", "\u00035", + "\u00030", "\u00031", "\u00032", "\u00033", "\u00034", "\u00035", "\u00036", "\u00037", "\u00038", "\u00039", }; static readonly string[] ircReplacements = new string[] { white, black, navy, green, red, maroon, purple, gold, yellow, lime, teal, aqua, blue, pink, gray, silver, - }; + }; static readonly Regex IrcTwoColorCode = new Regex("(\x03\\d{1,2}),\\d{1,2}"); public static string ConvertIRCToMC(string input) { @@ -187,7 +187,7 @@ namespace MCGalaxy { if (col == 'I') { col = ServerConfig.IRCColor[1]; return true; } if (col == 'W') { col = ServerConfig.WarningErrorColor[1]; return true; } return IsDefined(col); - } + } /// Converts percentage color codes to their actual/real color codes. @@ -234,8 +234,8 @@ namespace MCGalaxy { char color = chars[i + 1]; if (!Map(ref color)) continue; - chars[i] = '&'; - chars[i + 1] = color; + chars[i] = '&'; + chars[i + 1] = color; i++; // skip over color code } } @@ -254,8 +254,8 @@ namespace MCGalaxy { } } return new string(output, 0, usedChars); - } - + } + /// Removes all non-existent color codes, and converts /// custom colors to their fallback standard color codes if required. public static string Cleanup(string value, bool supportsCustomCols) { @@ -322,38 +322,35 @@ namespace MCGalaxy { if (!(hex.Length == 3 || hex.Length == 6)) return false; for (int i = 0; i < hex.Length; i++) { - if (Hex(hex[i]) == -1) return false; + if (UnHex(hex[i]) == -1) return false; } - + int R, G, B; if (hex.Length == 6) { - R = (Hex(hex[0]) << 4) | Hex(hex[1]); - G = (Hex(hex[2]) << 4) | Hex(hex[3]); - B = (Hex(hex[4]) << 4) | Hex(hex[5]); + R = (UnHex(hex[0]) << 4) | UnHex(hex[1]); + G = (UnHex(hex[2]) << 4) | UnHex(hex[3]); + B = (UnHex(hex[4]) << 4) | UnHex(hex[5]); } else { - R = Hex(hex[0]); R |= (R << 4); - G = Hex(hex[1]); G |= (G << 4); - B = Hex(hex[2]); B |= (B << 4); + R = UnHex(hex[0]); R |= (R << 4); + G = UnHex(hex[1]); G |= (G << 4); + B = UnHex(hex[2]); B |= (B << 4); } c.R = (byte)R; c.G = (byte)G; c.B = (byte)B; c.A = 255; return true; } - /// Parses an #RRGGBB hex color string. + /// Parses an #RRGGBB hex color string. public static ColorDesc ParseHex(string hex) { ColorDesc c; if (!TryParseHex(hex, out c)) throw new ArgumentException("invalid input"); return c; } - static int Hex(char value) { - if (value >= '0' && value <= '9') - return (int)(value - '0'); - if (value >= 'a' && value <= 'f') - return (int)(value - 'a') + 10; - if (value >= 'A' && value <= 'F') - return (int)(value - 'A') + 10; + public static int UnHex(char c) { + if (c >= '0' && c <= '9') { return (int)(c - '0'); } + if (c >= 'a' && c <= 'f') { return (int)(c - 'a') + 10; } + if (c >= 'A' && c <= 'F') { return (int)(c - 'A') + 10; } return -1; } @@ -386,7 +383,7 @@ namespace MCGalaxy { r = (byte)(191 * ((hex >> 2) & 1) + 64 * (hex >> 3)); g = (byte)(191 * ((hex >> 1) & 1) + 64 * (hex >> 3)); b = (byte)(191 * ((hex >> 0) & 1) + 64 * (hex >> 3)); - } + } public bool IsModified() { if ((Code >= '0' && Code <= '9') || (Code >= 'a' && Code <= 'f')) { diff --git a/MCGalaxy/Commands/CPE/CustomBlockCommand.cs b/MCGalaxy/Commands/CPE/CustomBlockCommand.cs index 59cb6f792..ba9e11f01 100644 --- a/MCGalaxy/Commands/CPE/CustomBlockCommand.cs +++ b/MCGalaxy/Commands/CPE/CustomBlockCommand.cs @@ -97,7 +97,6 @@ namespace MCGalaxy.Commands.CPE { SetBD(p, global, new BlockDefinition()); BlockDefinition def = GetBD(p, global); - def.Version2 = true; def.SetBlock(target); p.Message("Use %T{0} abort %Sat anytime to abort the creation process.", cmd); @@ -203,7 +202,7 @@ namespace MCGalaxy.Commands.CPE { if (def.Shape == 0) { p.Message(" Block is a sprite"); - p.Message(" Texture ID: {0}", def.SideTex); + p.Message(" Texture ID: {0}", def.RightTex); } else { p.Message(" Block is a cube from ({0}, {1}, {2}) to ({3}, {4}, {5})", def.MinX, def.MinZ, def.MinY, def.MaxX, def.MaxZ, def.MaxY); @@ -238,7 +237,7 @@ namespace MCGalaxy.Commands.CPE { } static string FormatBlock(BlockDefinition def) { - return "Custom block %T" + def.BlockID + " %Shas name %T" + def.Name; + return "Custom block %T" + def.RawID + " %Shas name %T" + def.Name; } static void RemoveHandler(Player p, string[] parts, bool global, string cmd) { @@ -254,7 +253,7 @@ namespace MCGalaxy.Commands.CPE { BlockDefinition.Remove(def, defs, p.IsSuper ? null : p.level); string scope = global ? "global" : "level"; - p.Message("Removed " + scope + " custom block " + def.Name + "(" + def.BlockID + ")"); + p.Message("Removed " + scope + " custom block " + def.Name + "(" + def.RawID + ")"); BlockDefinition globalDef = BlockDefinition.GlobalDefs[block]; if (!global && globalDef != null) @@ -291,8 +290,8 @@ namespace MCGalaxy.Commands.CPE { if (bd.Shape == 0) bd.SetAllTex(bd.TopTex); } } else if (step == 5) { - if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.SideTex, 0, 255)) { - bd.SetSideTex(bd.SideTex); + if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.RightTex, 0, 255)) { + bd.SetSideTex(bd.RightTex); step++; } } else if (step == 6) { @@ -401,12 +400,12 @@ namespace MCGalaxy.Commands.CPE { if (!EditUShort(p, value, "Top texture", ref def.TopTex, arg)) return; break; case "alltex": - if (!EditUShort(p, value, "All textures", ref def.SideTex, arg)) return; - def.SetAllTex(def.SideTex); + if (!EditUShort(p, value, "All textures", ref def.RightTex, arg)) return; + def.SetAllTex(def.RightTex); break; case "sidetex": - if (!EditUShort(p, value, "Side texture", ref def.SideTex, arg)) return; - def.SetSideTex(def.SideTex); + if (!EditUShort(p, value, "Side texture", ref def.RightTex, arg)) return; + def.SetSideTex(def.RightTex); break; case "lefttex": if (!EditUShort(p, value, "Left texture", ref def.LeftTex, arg)) return; @@ -481,7 +480,7 @@ namespace MCGalaxy.Commands.CPE { } // Don't let multiple blocks be assigned to same order - if (order != def.BlockID && order != 0) { + 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); @@ -489,11 +488,11 @@ namespace MCGalaxy.Commands.CPE { } } - def.InventoryOrder = order == def.BlockID ? -1 : order; + def.InventoryOrder = order == def.RawID ? -1 : order; BlockDefinition.UpdateOrder(def, global, level); BlockDefinition.Save(global, level); p.Message("Set inventory order for {0} to {1}", blockName, - order == def.BlockID ? "default" : order.ToString()); + order == def.RawID ? "default" : order.ToString()); return; default: p.Message("Unrecognised property: " + arg); return; @@ -528,7 +527,7 @@ namespace MCGalaxy.Commands.CPE { } string scope = global ? "global" : "level"; - p.Message("Created a new " + scope + " custom block " + def.Name + "(" + def.BlockID + ")"); + p.Message("Created a new " + scope + " custom block " + def.Name + "(" + def.RawID + ")"); block = def.GetBlock(); BlockDefinition.Add(def, defs, p.IsSuper ? null : p.level); diff --git a/MCGalaxy/Config/ConfigElement.cs b/MCGalaxy/Config/ConfigElement.cs index 8784fad18..b59860057 100644 --- a/MCGalaxy/Config/ConfigElement.cs +++ b/MCGalaxy/Config/ConfigElement.cs @@ -46,6 +46,8 @@ namespace MCGalaxy { ConfigElement elem; elem.Field = field; elem.Attrib = (ConfigAttribute)attributes[0]; + + if (elem.Attrib.Name == null) elem.Attrib.Name = field.Name; elems.Add(elem); } return elems.ToArray(); diff --git a/MCGalaxy/Config/JSON.cs b/MCGalaxy/Config/JSON.cs new file mode 100644 index 000000000..b0d475b9f --- /dev/null +++ b/MCGalaxy/Config/JSON.cs @@ -0,0 +1,203 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace MCGalaxy.Config { + + public class JsonContext { + public string Val; public int Idx; public bool Success = true; + public char Cur { get { return Val[Idx]; } } + internal StringBuilder strBuffer = new StringBuilder(96); + } + + public sealed class JsonArray : List { } + public sealed class JsonObject : Dictionary { + + public void Deserialise(ConfigElement[] elems, object instance, string group) { + foreach (KeyValuePair e in this) { + string key = e.Key, value = (string)e.Value; + ConfigElement.Parse(elems, group, instance, key, value); + } + } + } + + public static class Json { + const int T_NONE = 0, T_NUM = 1, T_TRUE = 2, T_FALSE = 3, T_NULL = 4; + + static bool IsWhitespace(char c) { + return c == '\r' || c == '\n' || c == '\t' || c == ' '; + } + + static bool NextConstant(JsonContext ctx, string value) { + if (ctx.Idx + value.Length > ctx.Val.Length) return false; + + for (int i = 0; i < value.Length; i++) { + if (ctx.Val[ctx.Idx + i] != value[i]) return false; + } + + ctx.Idx += value.Length; return true; + } + + static int NextToken(JsonContext ctx) { + for (; ctx.Idx < ctx.Val.Length && IsWhitespace(ctx.Cur); ctx.Idx++); + if (ctx.Idx >= ctx.Val.Length) return T_NONE; + + char c = ctx.Cur; ctx.Idx++; + if (c == '{' || c == '}') return c; + if (c == '[' || c == ']') return c; + if (c == ',' || c == '"' || c == ':') return c; + + if (IsNumber(c)) return T_NUM; + ctx.Idx--; + + if (NextConstant(ctx, "true")) return T_TRUE; + if (NextConstant(ctx, "false")) return T_FALSE; + if (NextConstant(ctx, "null")) return T_NULL; + + // invalid token + ctx.Idx++; return T_NONE; + } + + public static object ParseStream(JsonContext ctx) { + return ParseValue(NextToken(ctx), ctx); + } + + static object ParseValue(int token, JsonContext ctx) { + switch (token) { + case '{': return ParseObject(ctx); + case '[': return ParseArray(ctx); + case '"': return ParseString(ctx); + + case T_NUM: return ParseNumber(ctx); + case T_TRUE: return "true"; + case T_FALSE: return "false"; + case T_NULL: return null; + + default: return null; + } + } + + static JsonObject ParseObject(JsonContext ctx) { + JsonObject members = new JsonObject(); + while (true) { + int token = NextToken(ctx); + if (token == ',') continue; + if (token == '}') return members; + + if (token != '"') { ctx.Success = false; return null; } + string key = ParseString(ctx); + + token = NextToken(ctx); + if (token != ':') { ctx.Success = false; return null; } + + token = NextToken(ctx); + if (token == T_NONE) { ctx.Success = false; return null; } + + members[key] = ParseValue(token, ctx); + } + } + + static JsonArray ParseArray(JsonContext ctx) { + JsonArray elements = new JsonArray(); + while (true) { + int token = NextToken(ctx); + if (token == ',') continue; + if (token == ']') return elements; + + if (token == T_NONE) { ctx.Success = false; return null; } + elements.Add(ParseValue(token, ctx)); + } + } + + static string ParseString(JsonContext ctx) { + StringBuilder s = ctx.strBuffer; s.Length = 0; + + for (; ctx.Idx < ctx.Val.Length;) { + char c = ctx.Cur; ctx.Idx++; + if (c == '"') return s.ToString(); + if (c != '\\') { s.Append(c); continue; } + + if (ctx.Idx >= ctx.Val.Length) break; + c = ctx.Cur; ctx.Idx++; + if (c == '/' || c == '\\' || c == '"') { s.Append(c); continue; } + + if (c != 'u') break; + if (ctx.Idx + 4 > ctx.Val.Length) break; + + // form of \uYYYY + int aH = Colors.UnHex(ctx.Val[ctx.Idx + 0]); + int aL = Colors.UnHex(ctx.Val[ctx.Idx + 1]); + int bH = Colors.UnHex(ctx.Val[ctx.Idx + 2]); + int bL = Colors.UnHex(ctx.Val[ctx.Idx + 3]); + + if (aH == -1 || aL == -1 || bH == -1 || bL == -1) break; + int codePoint = (aH << 12) | (aL << 8) | (bH << 4) | bL; + s.Append((char)codePoint); + ctx.Idx += 4; + } + + ctx.Success = false; return null; + } + + static bool IsNumber(char c) { + return c == '-' || c == '.' || (c >= '0' && c <= '9'); + } + + static string ParseNumber(JsonContext ctx) { + int start = ctx.Idx - 1; + for (; ctx.Idx < ctx.Val.Length && IsNumber(ctx.Cur); ctx.Idx++); + return ctx.Val.Substring(start, ctx.Idx - start); + } + + + static char Hex(char c, int shift) { + int x = (c >> shift) & 0x0F; + return (char)(x <= 9 ? ('0' + x) : ('a' + (x - 10))); + } + + static void WriteString(StreamWriter w, string value) { + w.Write('"'); + foreach (char c in value) { + if (c == '/') { w.Write("\\/"); + } else if (c == '\\') { w.Write("\\\\"); + } else if (c == '"') { w.Write("\\\""); + } else if (c >= ' ' && c <= '~') { w.Write(c); + } else { + w.Write("\\u"); + w.Write(Hex(c, 12)); w.Write(Hex(c, 8)); + w.Write(Hex(c, 4)); w.Write(Hex(c, 0)); + } + } + w.Write('"'); + } + + static void WriteValue(StreamWriter w, ConfigAttribute a, string value) { + if (String.IsNullOrEmpty(value)) { + w.Write("null"); + } else if (a is ConfigBoolAttribute || a is ConfigIntAttribute || a is ConfigRealAttribute) { + w.Write(value); + } else { + WriteString(w, value); + } + } + + public static void Serialise(StreamWriter w, ConfigElement[] elems, object instance) { + w.WriteLine("{"); + for (int i = 0; i < elems.Length; i++) { + ConfigElement elem = elems[i]; + ConfigAttribute a = elem.Attrib; + + w.Write(" "); WriteString(w, a.Name); w.Write(": "); + object raw = elem.Field.GetValue(instance); + string value = elem.Attrib.Serialise(raw); + + WriteValue(w, a, value); + bool last = i == elems.Length - 1; + w.WriteLine(last ? "" : ","); + } + w.Write('}'); + } + } +} \ No newline at end of file diff --git a/MCGalaxy/Config/NumberAttributes.cs b/MCGalaxy/Config/NumberAttributes.cs index 2002c3ac6..af946259f 100644 --- a/MCGalaxy/Config/NumberAttributes.cs +++ b/MCGalaxy/Config/NumberAttributes.cs @@ -23,6 +23,8 @@ namespace MCGalaxy.Config { public class ConfigIntAttribute : ConfigAttribute { int defValue, minValue, maxValue; + public ConfigIntAttribute() + : this(null, null, 0, int.MinValue, int.MaxValue) { } public ConfigIntAttribute(string name, string section, int def, int min = int.MinValue, int max = int.MaxValue) : base(name, section) { defValue = def; minValue = min; maxValue = max; } @@ -47,8 +49,7 @@ namespace MCGalaxy.Config { } // Hacky workaround for old ExponentialFog attribute - public sealed class ConfigBoolIntAttribute : ConfigIntAttribute { - + sealed class ConfigBoolIntAttribute : ConfigIntAttribute { public ConfigBoolIntAttribute(string name, string section, int defValue) : base(name, section, defValue, -1, 1) { } @@ -60,8 +61,7 @@ namespace MCGalaxy.Config { } } - public class ConfigBlockAttribute : ConfigIntAttribute { - + public class ConfigBlockAttribute : ConfigIntAttribute { public ConfigBlockAttribute(string name, string section, int def) : base(name, section, def, 0, Block.ExtendedCount - 1) { } @@ -75,9 +75,35 @@ namespace MCGalaxy.Config { } } + public class ConfigByteAttribute : ConfigIntAttribute { + public ConfigByteAttribute() : this(null, null) { } + public ConfigByteAttribute(string name, string section) + : base(name, section, 0, 0, 255) { } + + public override object Parse(string raw) { + int value = (int)base.Parse(raw); + // Can't directly unbox object to byte - must unbox to byte, then cast to byte + return (byte)value; + } + } + + public class ConfigUShortAttribute : ConfigIntAttribute { + public ConfigUShortAttribute() : this(null, null) { } + public ConfigUShortAttribute(string name, string section) + : base(name, section, 0, 0, 65535) { } + + public override object Parse(string raw) { + int value = (int)base.Parse(raw); + // Can't directly unbox object to ushort - must unbox to ushort, then cast to ushort + return (ushort)value; + } + } + public class ConfigRealAttribute : ConfigAttribute { float defValue, minValue, maxValue; + public ConfigRealAttribute() + : this(null, null, 0, float.NegativeInfinity, float.PositiveInfinity) { } public ConfigRealAttribute(string name, string section, float def, float min = float.NegativeInfinity, float max = float.PositiveInfinity) : base(name, section) { defValue = def; minValue = min; maxValue = max; } diff --git a/MCGalaxy/Config/OtherAttributes.cs b/MCGalaxy/Config/OtherAttributes.cs index 4f9316f3d..ff41b54bc 100644 --- a/MCGalaxy/Config/OtherAttributes.cs +++ b/MCGalaxy/Config/OtherAttributes.cs @@ -23,6 +23,7 @@ namespace MCGalaxy.Config { public sealed class ConfigBoolAttribute : ConfigAttribute { bool defValue; + public ConfigBoolAttribute() : this(null, null, false) { } public ConfigBoolAttribute(string name, string section, bool def) : base(name, section) { defValue = def; } @@ -34,6 +35,11 @@ namespace MCGalaxy.Config { } return boolValue; } + + public override string Serialise(object value) { + bool boolValue = (bool)value; + return boolValue ? "true" : "false"; + } } public sealed class ConfigPermAttribute : ConfigAttribute { diff --git a/MCGalaxy/Config/StringAttributes.cs b/MCGalaxy/Config/StringAttributes.cs index fe1ba6d76..27041deb6 100644 --- a/MCGalaxy/Config/StringAttributes.cs +++ b/MCGalaxy/Config/StringAttributes.cs @@ -56,8 +56,11 @@ namespace MCGalaxy.Config { public ConfigStringAttribute(string name, string section, string def) : base(name, section) { defValue = def; } + public ConfigStringAttribute() + : base(null, null) { allowEmpty = true; } + public override object Parse(string value) { - if (value.Length == 0 && !allowEmpty) { + if (String.IsNullOrEmpty(value) && !allowEmpty) { Logger.Log(LogType.Warning, "Config key \"{0}\" has no value, using default of {1}", Name, defValue); return defValue; } diff --git a/MCGalaxy/Levels/IO/Importers/CwImporter.cs b/MCGalaxy/Levels/IO/Importers/CwImporter.cs index 8660e3df1..c378bcf3e 100644 --- a/MCGalaxy/Levels/IO/Importers/CwImporter.cs +++ b/MCGalaxy/Levels/IO/Importers/CwImporter.cs @@ -123,7 +123,7 @@ namespace MCGalaxy.Levels.IO { NbtCompound props = (NbtCompound)tag; BlockDefinition def = new BlockDefinition(); - def.BlockID = props["ID"].ByteValue; + def.RawID = props["ID"].ByteValue; def.Name = props["Name"].StringValue; def.CollideType = props["CollideType"].ByteValue; def.Speed = props["Speed"].FloatValue; @@ -154,8 +154,6 @@ namespace MCGalaxy.Levels.IO { BlockDefinition globalDef = BlockDefinition.GlobalDefs[block]; if (PropsEquals(def, globalDef)) continue; - def.SideTex = def.LeftTex; - def.Version2 = true; lvl.UpdateCustomBlock(block, def); hasBlockDefs = true; } diff --git a/MCGalaxy/MCGalaxy_.csproj b/MCGalaxy/MCGalaxy_.csproj index cc2185104..d79b82ddd 100644 --- a/MCGalaxy/MCGalaxy_.csproj +++ b/MCGalaxy/MCGalaxy_.csproj @@ -71,9 +71,6 @@ ..\MySql.Data.dll - - ..\Newtonsoft.Json.dll - @@ -377,6 +374,7 @@ + diff --git a/MCGalaxy/Network/Heartbeat/ClassiCube.cs b/MCGalaxy/Network/Heartbeat/ClassiCube.cs index c34f6a31e..3b122d0d3 100644 --- a/MCGalaxy/Network/Heartbeat/ClassiCube.cs +++ b/MCGalaxy/Network/Heartbeat/ClassiCube.cs @@ -16,11 +16,12 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; +using MCGalaxy.Config; using MCGalaxy.Events.ServerEvents; -using Newtonsoft.Json; namespace MCGalaxy.Network { @@ -62,7 +63,7 @@ namespace MCGalaxy.Network { OnSendingHeartbeatEvent.Call(this, ref name); name = Colors.Strip(name); - return + return "&port=" + ServerConfig.Port + "&max=" + ServerConfig.MaxPlayers + "&name=" + Uri.EscapeDataString(name) + @@ -76,43 +77,52 @@ namespace MCGalaxy.Network { public override void OnRequest(HttpWebRequest request) { if (proxyUrl == null) return; request.Proxy = new WebProxy(proxyUrl); - } + } public override void OnResponse(string response) { if (String.IsNullOrEmpty(response)) return; // in form of http://www.classicube.net/server/play// - if (response.EndsWith("/")) + if (response.EndsWith("/")) response = response.Substring(0, response.Length - 1); string hash = response.Substring(response.LastIndexOf('/') + 1); - // Run this code if we don't already have a hash or if the hash has changed - if (String.IsNullOrEmpty(Server.Hash) || hash != Server.Hash) { - Server.Hash = hash; - Server.URL = response; + // only need to do this when contents have changed + if (hash == Server.Hash) return; + Server.Hash = hash; + Server.URL = response; + + if (!response.Contains("\"errors\": [")) { + Server.UpdateUrl(Server.URL); + File.WriteAllText("text/externalurl.txt", Server.URL); + Logger.Log(LogType.SystemActivity, "ClassiCube URL found: " + Server.URL); + } else { + string error = GetError(response); + if (error == null) error = "Error while finding URL. Is the port open?"; - if (!response.Contains("\"errors\": [")) { - Server.UpdateUrl(Server.URL); - File.WriteAllText("text/externalurl.txt", Server.URL); - Logger.Log(LogType.SystemActivity, "ClassiCube URL found: " + Server.URL); - } else { - Response resp = JsonConvert.DeserializeObject(Server.URL); - if (resp.errors != null && resp.errors.Length > 0 && resp.errors[0].Length > 0) - Server.URL = resp.errors[0][0]; - else - Server.URL = "Error while finding URL. Is the port open?"; - Server.UpdateUrl(Server.URL); - Logger.Log(LogType.Warning, response); + Server.URL = error; + Server.UpdateUrl(Server.URL); + Logger.Log(LogType.Warning, response); + } + } + + static string GetError(string json) { + JsonContext ctx = new JsonContext(); ctx.Val = json; + JsonObject obj = (JsonObject)Json.ParseStream(ctx); + if (obj == null) return null; + + foreach (KeyValuePair e in obj) { + if (!e.Key.CaselessEq("errors")) continue; + if (e.Value == null) return null; + + // silly design, but form of json is: "errors": [ ["Error1"], ["Error2"] ] + JsonArray errors = (JsonArray)e.Value; + foreach (object raw in errors) { + JsonArray error = raw as JsonArray; + if (error != null && error.Count > 0) return (string)error[0]; } } - } - - #pragma warning disable 0649 - class Response { - public string[][] errors; - public string response; - public string status; + return null; } - #pragma warning restore 0649 } } diff --git a/MCGalaxy/Network/Packets/Packet.cs b/MCGalaxy/Network/Packets/Packet.cs index 5e02eea50..460a52936 100644 --- a/MCGalaxy/Network/Packets/Packet.cs +++ b/MCGalaxy/Network/Packets/Packet.cs @@ -385,7 +385,7 @@ namespace MCGalaxy.Network { public static byte[] UndefineBlock(BlockDefinition def, bool extBlocks) { byte[] buffer = new byte[extBlocks ? 3 : 2]; buffer[0] = Opcode.CpeUndefineBlock; - NetUtils.WriteBlock(def.BlockID, buffer, 1, extBlocks); + NetUtils.WriteBlock(def.RawID, buffer, 1, extBlocks); return buffer; } @@ -414,7 +414,7 @@ namespace MCGalaxy.Network { // speed = 2^((raw - 128) / 64); // therefore raw = 64log2(speed) + 128 byte rawSpeed = (byte)(64 * Math.Log(def.Speed, 2) + 128); - NetUtils.WriteBlock(def.BlockID, buffer, i, extBlocks); + NetUtils.WriteBlock(def.RawID, buffer, i, extBlocks); i += extBlocks ? 2 : 1; NetUtils.Write(def.Name, buffer, i, hasCP437); i += NetUtils.StringSize; @@ -426,7 +426,7 @@ namespace MCGalaxy.Network { WriteTex(buffer, ref i, def.LeftTex, extTexs); WriteTex(buffer, ref i, def.RightTex, extTexs); WriteTex(buffer, ref i, def.FrontTex, extTexs); WriteTex(buffer, ref i, def.BackTex, extTexs); } else { - WriteTex(buffer, ref i, def.SideTex, extTexs); + WriteTex(buffer, ref i, def.RightTex, extTexs); } WriteTex(buffer, ref i, def.BottomTex, extTexs); diff --git a/MCGalaxy/Network/Player.Networking.cs b/MCGalaxy/Network/Player.Networking.cs index 30186916c..1bce0c45b 100644 --- a/MCGalaxy/Network/Player.Networking.cs +++ b/MCGalaxy/Network/Player.Networking.cs @@ -236,7 +236,7 @@ namespace MCGalaxy { BlockDefinition def = defs[i]; if (def == BlockDefinition.GlobalDefs[i] || def == null) continue; - if (def.BlockID > MaxRawBlock) continue; + if (def.RawID > MaxRawBlock) continue; Send(Packet.UndefineBlock(def, hasExtBlocks)); } } diff --git a/MCGalaxy/Server/Server.cs b/MCGalaxy/Server/Server.cs index 5a56a85ae..fe1f5533e 100644 --- a/MCGalaxy/Server/Server.cs +++ b/MCGalaxy/Server/Server.cs @@ -91,7 +91,6 @@ namespace MCGalaxy { CheckFile("MySql.Data.dll"); CheckFile("sqlite3_x32.dll"); CheckFile("sqlite3_x64.dll"); - CheckFile("Newtonsoft.Json.dll"); CheckFile("LibNoise.dll"); EnsureFilesExist(); diff --git a/MCGalaxy/Server/Tasks/UpgradeTasks.cs b/MCGalaxy/Server/Tasks/UpgradeTasks.cs index f845e07a2..351cf94b9 100644 --- a/MCGalaxy/Server/Tasks/UpgradeTasks.cs +++ b/MCGalaxy/Server/Tasks/UpgradeTasks.cs @@ -20,9 +20,7 @@ using System.Collections.Generic; using System.Data; using System.IO; using MCGalaxy.Bots; -using MCGalaxy.DB; using MCGalaxy.SQL; -using Newtonsoft.Json; namespace MCGalaxy.Tasks { internal static class UpgradeTasks { @@ -137,12 +135,12 @@ namespace MCGalaxy.Tasks { Logger.Log(LogType.SystemActivity, "Making bots file per-level.. " + "saved backup of global bots file to extra/bots.json.bak"); - BotProperties[] bots = JsonConvert.DeserializeObject(json); + List bots = BotsFile.ReadAll(json); Dictionary> botsByLevel = new Dictionary>(); foreach (BotProperties bot in bots) { List levelBots; - if (bot.Level == null || bot.Level.Length == 0) continue; + if (String.IsNullOrEmpty(bot.Level)) continue; if (!botsByLevel.TryGetValue(bot.Level, out levelBots)) { levelBots = new List(); @@ -152,8 +150,10 @@ namespace MCGalaxy.Tasks { } foreach (var kvp in botsByLevel) { - json = JsonConvert.SerializeObject(kvp.Value); - File.WriteAllText(BotsFile.BotsPath(kvp.Key), json); + string path = BotsFile.BotsPath(kvp.Key); + using (StreamWriter w = new StreamWriter(path)) { + BotsFile.WriteAll(w, kvp.Value); + } } if (Server.mainLevel.Bots.Count == 0) {