mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 12:05:51 -04:00
Move JSON parsing into core
This commit is contained in:
parent
9f0d908559
commit
7ff12b4026
@ -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<BlockDefinition[]>(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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
/// <summary> Maintains persistent data for in-game bots. </summary>
|
||||
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<BotProperties[]>(json);
|
||||
List<BotProperties> 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<BotProperties> ReadAll(string json) {
|
||||
List<BotProperties> props = new List<BotProperties>();
|
||||
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<BotProperties> props = new List<BotProperties>(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<BotProperties> 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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Converts percentage color codes to their actual/real color codes. </summary>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> Removes all non-existent color codes, and converts
|
||||
/// custom colors to their fallback standard color codes if required. </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary> Parses an #RRGGBB hex color string. </summary>
|
||||
/// <summary> Parses an #RRGGBB hex color string. </summary>
|
||||
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')) {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
203
MCGalaxy/Config/JSON.cs
Normal file
203
MCGalaxy/Config/JSON.cs
Normal file
@ -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<object> { }
|
||||
public sealed class JsonObject : Dictionary<string, object> {
|
||||
|
||||
public void Deserialise(ConfigElement[] elems, object instance, string group) {
|
||||
foreach (KeyValuePair<string, object> 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('}');
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -71,9 +71,6 @@
|
||||
<Reference Include="MySql.Data">
|
||||
<HintPath>..\MySql.Data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@ -377,6 +374,7 @@
|
||||
<Compile Include="Commands\World\CmdUnload.cs" />
|
||||
<Compile Include="Commands\World\PermissionCmds.cs" />
|
||||
<Compile Include="Config\ConfigAttribute.cs" />
|
||||
<Compile Include="Config\JSON.cs" />
|
||||
<Compile Include="Config\NumberAttributes.cs" />
|
||||
<Compile Include="Config\OtherAttributes.cs" />
|
||||
<Compile Include="Config\ConfigElement.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/<hash>/
|
||||
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<Response>(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<string, object> 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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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<BotProperties[]>(json);
|
||||
List<BotProperties> bots = BotsFile.ReadAll(json);
|
||||
Dictionary<string, List<BotProperties>> botsByLevel = new Dictionary<string, List<BotProperties>>();
|
||||
|
||||
foreach (BotProperties bot in bots) {
|
||||
List<BotProperties> 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<BotProperties>();
|
||||
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user