mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-23 12:42:22 -04:00
Move JSON parsing into core
This commit is contained in:
parent
9f0d908559
commit
7ff12b4026
@ -18,37 +18,54 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MCGalaxy.Blocks;
|
using MCGalaxy.Blocks;
|
||||||
|
using MCGalaxy.Config;
|
||||||
using MCGalaxy.Network;
|
using MCGalaxy.Network;
|
||||||
using Newtonsoft.Json;
|
using BlockID = System.UInt16;
|
||||||
using BlockID_ = System.UInt16;
|
|
||||||
using BlockRaw = System.Byte;
|
|
||||||
|
|
||||||
namespace MCGalaxy {
|
namespace MCGalaxy {
|
||||||
public sealed class BlockDefinition {
|
public sealed class BlockDefinition {
|
||||||
|
|
||||||
public ushort BlockID; // really raw block ID
|
[ConfigUShort("BlockID", null)]
|
||||||
public string Name;
|
public ushort RawID;
|
||||||
public byte CollideType;
|
[ConfigString] public string Name;
|
||||||
public float Speed;
|
[ConfigReal] public float Speed;
|
||||||
public ushort TopTex, SideTex, BottomTex;
|
[ConfigByte] public byte CollideType;
|
||||||
public bool BlocksLight;
|
[ConfigUShort] public ushort TopTex;
|
||||||
public byte WalkSound;
|
[ConfigUShort] ushort SideTex;
|
||||||
public bool FullBright;
|
[ConfigUShort] public ushort BottomTex;
|
||||||
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;
|
|
||||||
|
|
||||||
|
[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 int InventoryOrder = -1;
|
||||||
|
|
||||||
public BlockID_ GetBlock() { return Block.FromRaw(BlockID); }
|
public BlockID GetBlock() { return Block.FromRaw(RawID); }
|
||||||
public void SetBlock(BlockID_ b) { BlockID = Block.ToRaw(b); }
|
public void SetBlock(BlockID b) { RawID = Block.ToRaw(b); }
|
||||||
|
|
||||||
public const string GlobalPath = "blockdefs/global.json", GlobalBackupPath = "blockdefs/global.json.bak";
|
public const string GlobalPath = "blockdefs/global.json", GlobalBackupPath = "blockdefs/global.json.bak";
|
||||||
|
|
||||||
@ -56,80 +73,84 @@ namespace MCGalaxy {
|
|||||||
|
|
||||||
public BlockDefinition Copy() {
|
public BlockDefinition Copy() {
|
||||||
BlockDefinition def = new BlockDefinition();
|
BlockDefinition def = new BlockDefinition();
|
||||||
def.BlockID = BlockID; def.Name = Name;
|
def.RawID = RawID; def.Name = Name;
|
||||||
def.CollideType = CollideType; def.Speed = Speed;
|
def.CollideType = CollideType; def.Speed = Speed;
|
||||||
def.TopTex = TopTex; def.SideTex = SideTex;
|
def.TopTex = TopTex; def.BottomTex = BottomTex;
|
||||||
def.BottomTex = BottomTex; def.BlocksLight = BlocksLight;
|
def.BlocksLight = BlocksLight; def.WalkSound = WalkSound;
|
||||||
def.WalkSound = WalkSound; def.FullBright = FullBright;
|
def.FullBright = FullBright; def.Shape = Shape;
|
||||||
def.Shape = Shape; def.BlockDraw = BlockDraw;
|
def.BlockDraw = BlockDraw; def.FogDensity = FogDensity;
|
||||||
def.FogDensity = FogDensity; def.FogR = FogR;
|
def.FogR = FogR; def.FogG = FogG; def.FogB = FogB;
|
||||||
def.FogG = FogG; def.FogB = FogB;
|
|
||||||
def.FallBack = FallBack;
|
def.FallBack = FallBack;
|
||||||
def.MinX = MinX; def.MinY = MinY; def.MinZ = MinZ;
|
def.MinX = MinX; def.MinY = MinY; def.MinZ = MinZ;
|
||||||
def.MaxX = MaxX; def.MaxY = MaxY; def.MaxZ = MaxZ;
|
def.MaxX = MaxX; def.MaxY = MaxY; def.MaxZ = MaxZ;
|
||||||
def.Version2 = Version2;
|
|
||||||
def.LeftTex = LeftTex; def.RightTex = RightTex;
|
def.LeftTex = LeftTex; def.RightTex = RightTex;
|
||||||
def.FrontTex = FrontTex; def.BackTex = BackTex;
|
def.FrontTex = FrontTex; def.BackTex = BackTex;
|
||||||
def.InventoryOrder = InventoryOrder;
|
def.InventoryOrder = InventoryOrder;
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ConfigElement[] elems;
|
||||||
public static BlockDefinition[] Load(bool global, string mapName) {
|
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";
|
string path = global ? GlobalPath : "blockdefs/lvl_" + mapName + ".json";
|
||||||
|
if (!File.Exists(path)) return defs;
|
||||||
|
if (elems == null) elems = ConfigElement.GetAll(typeof(BlockDefinition));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (File.Exists(path)) {
|
JsonContext ctx = new JsonContext();
|
||||||
string json = File.ReadAllText(path);
|
ctx.Val = File.ReadAllText(path);
|
||||||
defs = JsonConvert.DeserializeObject<BlockDefinition[]>(json);
|
JsonArray array = (JsonArray)Json.ParseStream(ctx);
|
||||||
}
|
if (array == null) return defs;
|
||||||
} 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;
|
|
||||||
|
|
||||||
if (!def.Version2) {
|
foreach (object raw in array) {
|
||||||
def.Version2 = true;
|
JsonObject obj = (JsonObject)raw;
|
||||||
def.SetSideTex(def.SideTex);
|
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);
|
||||||
}
|
}
|
||||||
|
return defs;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Save(bool global, Level lvl) {
|
public static void Save(bool global, Level lvl) {
|
||||||
BlockDefinition[] defs = global ? GlobalDefs : lvl.CustomBlockDefs;
|
if (elems == null) elems = ConfigElement.GetAll(typeof(BlockDefinition));
|
||||||
// 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);
|
|
||||||
string path = global ? GlobalPath : "blockdefs/lvl_" + lvl.MapName + ".json";
|
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() {
|
public static void LoadGlobal() {
|
||||||
@ -141,8 +162,8 @@ namespace MCGalaxy {
|
|||||||
if (File.Exists(GlobalPath)) {
|
if (File.Exists(GlobalPath)) {
|
||||||
File.Copy(GlobalPath, GlobalBackupPath, true);
|
File.Copy(GlobalPath, GlobalBackupPath, true);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.LogError("Error backing up global block defs", ex);
|
Logger.LogError("Error backing up global block defs", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// As the BlockDefinition instances in levels will now be different
|
// As the BlockDefinition instances in levels will now be different
|
||||||
@ -160,14 +181,14 @@ namespace MCGalaxy {
|
|||||||
if ((lvl.Props[b].ChangedScope & 2) == 0) {
|
if ((lvl.Props[b].ChangedScope & 2) == 0) {
|
||||||
lvl.Props[b] = Block.Props[b];
|
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) {
|
public static void Add(BlockDefinition def, BlockDefinition[] defs, Level level) {
|
||||||
BlockID_ block = def.GetBlock();
|
BlockID block = def.GetBlock();
|
||||||
bool global = defs == GlobalDefs;
|
bool global = defs == GlobalDefs;
|
||||||
if (global) UpdateGlobalCustom(block, def);
|
if (global) UpdateGlobalCustom(block, def);
|
||||||
|
|
||||||
@ -178,7 +199,7 @@ namespace MCGalaxy {
|
|||||||
Player[] players = PlayerInfo.Online.Items;
|
Player[] players = PlayerInfo.Online.Items;
|
||||||
foreach (Player pl in players) {
|
foreach (Player pl in players) {
|
||||||
if (!global && pl.level != level) continue;
|
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;
|
if (global && pl.level.CustomBlockDefs[block] != GlobalDefs[block]) continue;
|
||||||
|
|
||||||
pl.Send(def.MakeDefinePacket(pl));
|
pl.Send(def.MakeDefinePacket(pl));
|
||||||
@ -188,7 +209,7 @@ namespace MCGalaxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void Remove(BlockDefinition def, BlockDefinition[] defs, Level level) {
|
public static void Remove(BlockDefinition def, BlockDefinition[] defs, Level level) {
|
||||||
BlockID_ block = def.GetBlock();
|
BlockID block = def.GetBlock();
|
||||||
bool global = defs == GlobalDefs;
|
bool global = defs == GlobalDefs;
|
||||||
if (global) UpdateGlobalCustom(block, null);
|
if (global) UpdateGlobalCustom(block, null);
|
||||||
|
|
||||||
@ -199,7 +220,7 @@ namespace MCGalaxy {
|
|||||||
Player[] players = PlayerInfo.Online.Items;
|
Player[] players = PlayerInfo.Online.Items;
|
||||||
foreach (Player pl in players) {
|
foreach (Player pl in players) {
|
||||||
if (!global && pl.level != level) continue;
|
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;
|
if (global && pl.level.CustomBlockDefs[block] != null) continue;
|
||||||
|
|
||||||
pl.Send(Packet.UndefineBlock(def, pl.hasExtBlocks));
|
pl.Send(Packet.UndefineBlock(def, pl.hasExtBlocks));
|
||||||
@ -211,12 +232,12 @@ namespace MCGalaxy {
|
|||||||
Player[] players = PlayerInfo.Online.Items;
|
Player[] players = PlayerInfo.Online.Items;
|
||||||
foreach (Player pl in players) {
|
foreach (Player pl in players) {
|
||||||
if (!global && pl.level != level) continue;
|
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);
|
SendLevelInventoryOrder(pl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateGlobalCustom(BlockID_ block, BlockDefinition def) {
|
static void UpdateGlobalCustom(BlockID block, BlockDefinition def) {
|
||||||
Level[] loaded = LevelInfo.Loaded.Items;
|
Level[] loaded = LevelInfo.Loaded.Items;
|
||||||
foreach (Level lvl in loaded) {
|
foreach (Level lvl in loaded) {
|
||||||
if (lvl.CustomBlockDefs[block] != GlobalDefs[block]) continue;
|
if (lvl.CustomBlockDefs[block] != GlobalDefs[block]) continue;
|
||||||
@ -225,12 +246,11 @@ namespace MCGalaxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void SetAllTex(ushort id) {
|
public void SetAllTex(ushort id) {
|
||||||
SetSideTex(id);
|
SetSideTex(id);
|
||||||
TopTex = id; BottomTex = id;
|
TopTex = id; BottomTex = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSideTex(ushort id) {
|
public void SetSideTex(ushort id) {
|
||||||
SideTex = id;
|
|
||||||
LeftTex = id; RightTex = id; FrontTex = id; BackTex = id;
|
LeftTex = id; RightTex = id; FrontTex = id; BackTex = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +259,7 @@ namespace MCGalaxy {
|
|||||||
BlockDefinition[] defs = pl.level.CustomBlockDefs;
|
BlockDefinition[] defs = pl.level.CustomBlockDefs;
|
||||||
for (int i = 0; i < defs.Length; i++) {
|
for (int i = 0; i < defs.Length; i++) {
|
||||||
BlockDefinition def = defs[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));
|
pl.Send(def.MakeDefinePacket(pl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,23 +278,23 @@ namespace MCGalaxy {
|
|||||||
// Fill slots with explicit order
|
// Fill slots with explicit order
|
||||||
for (int i = 0; i < defs.Length; i++) {
|
for (int i = 0; i < defs.Length; i++) {
|
||||||
BlockDefinition def = defs[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 == -1) continue;
|
||||||
|
|
||||||
if (def.InventoryOrder != 0) {
|
if (def.InventoryOrder != 0) {
|
||||||
if (order_to_blocks[def.InventoryOrder] != -1) continue;
|
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
|
// Put blocks into their default slot if slot is unused
|
||||||
for (int i = 0; i < defs.Length; i++) {
|
for (int i = 0; i < defs.Length; i++) {
|
||||||
BlockDefinition def = defs[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 (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) {
|
if (order_to_blocks[raw] == -1) {
|
||||||
order_to_blocks[raw] = raw;
|
order_to_blocks[raw] = raw;
|
||||||
block_to_orders[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
|
// Push blocks whose slots conflict with other blocks into free slots at end
|
||||||
for (int i = defs.Length - 1; i >= 0; i--) {
|
for (int i = defs.Length - 1; i >= 0; i--) {
|
||||||
BlockDefinition def = defs[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 (raw > pl.MaxRawBlock || (def == null && raw >= Block.CpeCount)) continue;
|
||||||
|
|
||||||
if (block_to_orders[raw] != -1) continue;
|
if (block_to_orders[raw] != -1) continue;
|
||||||
@ -301,12 +321,12 @@ namespace MCGalaxy {
|
|||||||
int order = block_to_orders[raw];
|
int order = block_to_orders[raw];
|
||||||
if (order == -1) order = 0;
|
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;
|
if (def == null && raw >= Block.CpeCount) continue;
|
||||||
// Special case, don't want 255 getting hidden by default
|
// Special case, don't want 255 getting hidden by default
|
||||||
if (raw == 255 && def.InventoryOrder == -1) continue;
|
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;
|
Player[] players = PlayerInfo.Online.Items;
|
||||||
foreach (Player pl in players) {
|
foreach (Player pl in players) {
|
||||||
if (!global && pl.level != level) continue;
|
if (!global && pl.level != level) continue;
|
||||||
|
@ -51,7 +51,6 @@ namespace MCGalaxy.Blocks {
|
|||||||
def.FallBack = (BlockRaw)b;
|
def.FallBack = (BlockRaw)b;
|
||||||
|
|
||||||
def.MaxX = 16; def.MaxZ = Height(b); def.MaxY = 16;
|
def.MaxX = 16; def.MaxZ = Height(b); def.MaxY = 16;
|
||||||
def.Version2 = true;
|
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,67 +16,100 @@
|
|||||||
permissions and limitations under the Licenses.
|
permissions and limitations under the Licenses.
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MCGalaxy.Maths;
|
using MCGalaxy.Config;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace MCGalaxy.Bots {
|
namespace MCGalaxy.Bots {
|
||||||
|
|
||||||
/// <summary> Maintains persistent data for in-game bots. </summary>
|
/// <summary> Maintains persistent data for in-game bots. </summary>
|
||||||
public static class BotsFile {
|
public static class BotsFile {
|
||||||
|
|
||||||
public static string BotsPath(string mapName) {
|
public static string BotsPath(string map) { return "extra/bots/" + map + ".json"; }
|
||||||
return "extra/bots/" + mapName + ".json";
|
static ConfigElement[] elems;
|
||||||
}
|
|
||||||
|
|
||||||
public static void Load(Level lvl) { lock (lvl.botsIOLock) { LoadCore(lvl); } }
|
public static void Load(Level lvl) { lock (lvl.botsIOLock) { LoadCore(lvl); } }
|
||||||
static void LoadCore(Level lvl) {
|
static void LoadCore(Level lvl) {
|
||||||
string path = BotsPath(lvl.MapName);
|
string path = BotsPath(lvl.MapName);
|
||||||
if (!File.Exists(path)) return;
|
if (!File.Exists(path)) return;
|
||||||
string json = File.ReadAllText(path);
|
string json = File.ReadAllText(path);
|
||||||
BotProperties[] bots = JsonConvert.DeserializeObject<BotProperties[]>(json);
|
List<BotProperties> props = null;
|
||||||
|
|
||||||
foreach (BotProperties props in bots) {
|
try {
|
||||||
if (String.IsNullOrEmpty(props.DisplayName)) {
|
props = ReadAll(json);
|
||||||
props.DisplayName = props.Name;
|
} catch (Exception ex) {
|
||||||
}
|
Logger.LogError("Reading bots file", ex); return;
|
||||||
|
}
|
||||||
PlayerBot bot = new PlayerBot(props.Name, lvl);
|
|
||||||
props.ApplyTo(bot);
|
foreach (BotProperties data in props) {
|
||||||
|
PlayerBot bot = new PlayerBot(data.Name, lvl);
|
||||||
|
data.ApplyTo(bot);
|
||||||
|
|
||||||
bot.SetModel(bot.Model, lvl);
|
bot.SetModel(bot.Model, lvl);
|
||||||
LoadAi(props, bot);
|
LoadAi(data, bot);
|
||||||
PlayerBot.Add(bot, false);
|
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); } }
|
public static void Save(Level lvl) { lock (lvl.botsIOLock) { SaveCore(lvl); } }
|
||||||
static void SaveCore(Level lvl) {
|
static void SaveCore(Level lvl) {
|
||||||
PlayerBot[] bots = lvl.Bots.Items;
|
PlayerBot[] bots = lvl.Bots.Items;
|
||||||
string path = BotsPath(lvl.MapName);
|
string path = BotsPath(lvl.MapName);
|
||||||
if (!File.Exists(path) && bots.Length == 0) return;
|
if (!File.Exists(path) && bots.Length == 0) return;
|
||||||
|
|
||||||
BotProperties[] props = new BotProperties[bots.Length];
|
List<BotProperties> props = new List<BotProperties>(bots.Length);
|
||||||
for (int i = 0; i < props.Length; i++) {
|
for (int i = 0; i < bots.Length; i++) {
|
||||||
BotProperties savedProps = new BotProperties();
|
BotProperties data = new BotProperties();
|
||||||
savedProps.FromBot(bots[i]);
|
data.FromBot(bots[i]);
|
||||||
props[i] = savedProps;
|
props.Add(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
string json = JsonConvert.SerializeObject(props);
|
|
||||||
try {
|
try {
|
||||||
File.WriteAllText(path, json);
|
using (StreamWriter w = new StreamWriter(path)) { WriteAll(w, props); }
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.LogError("Error saving bots to " + path, 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) {
|
internal static void LoadAi(BotProperties props, PlayerBot bot) {
|
||||||
if (String.IsNullOrEmpty(props.AI)) return;
|
if (String.IsNullOrEmpty(props.AI)) return;
|
||||||
try {
|
try {
|
||||||
ScriptFile.Parse(Player.Console, bot, props.AI);
|
ScriptFile.Parse(Player.Console, bot, props.AI);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.LogError("Error loading bot AI " + props.AI, ex);
|
Logger.LogError("Error loading bot AI " + props.AI, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.cur = props.CurInstruction;
|
bot.cur = props.CurInstruction;
|
||||||
@ -85,31 +118,32 @@ namespace MCGalaxy.Bots {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sealed class BotProperties {
|
public sealed class BotProperties {
|
||||||
public string DisplayName { get; set; }
|
[ConfigString] public string DisplayName;
|
||||||
public string Name { get; set; }
|
[ConfigString] public string Name;
|
||||||
public string Level { get; set; }
|
[ConfigString] public string Level;
|
||||||
public string Skin { get; set; }
|
[ConfigString] public string Skin;
|
||||||
public string Model { get; set; }
|
[ConfigString] public string Model;
|
||||||
public string Color { get; set; }
|
[ConfigString] public string Color;
|
||||||
public string ClickedOnText { get; set; }
|
[ConfigString] public string ClickedOnText;
|
||||||
public string DeathMessage { get; set; }
|
[ConfigString] public string DeathMessage;
|
||||||
|
|
||||||
public string AI { get; set; }
|
[ConfigString] public string AI;
|
||||||
public bool Kill { get; set; }
|
[ConfigBool] public bool Kill;
|
||||||
public bool Hunt { get; set; }
|
[ConfigBool] public bool Hunt;
|
||||||
public int CurInstruction { get; set; }
|
[ConfigInt] public int CurInstruction;
|
||||||
public sbyte CurJump { get; set; }
|
[ConfigInt] public int CurJump;
|
||||||
|
|
||||||
public int X { get; set; }
|
[ConfigInt] public int X;
|
||||||
public int Y { get; set; }
|
[ConfigInt] public int Y;
|
||||||
public int Z { get; set; }
|
[ConfigInt] public int Z;
|
||||||
public byte RotX { get; set; }
|
[ConfigByte] public byte RotX;
|
||||||
public byte RotY { get; set; }
|
[ConfigByte] public byte RotY;
|
||||||
public byte BodyX { get; set; }
|
|
||||||
public byte BodyZ { get; set; }
|
[ConfigByte] public byte BodyX;
|
||||||
public float ScaleX { get; set; }
|
[ConfigByte] public byte BodyZ;
|
||||||
public float ScaleY { get; set; }
|
[ConfigReal] public float ScaleX;
|
||||||
public float ScaleZ { get; set; }
|
[ConfigReal] public float ScaleY;
|
||||||
|
[ConfigReal] public float ScaleZ;
|
||||||
|
|
||||||
public void FromBot(PlayerBot bot) {
|
public void FromBot(PlayerBot bot) {
|
||||||
Name = bot.name; Level = bot.level.name;
|
Name = bot.name; Level = bot.level.name;
|
||||||
|
@ -44,7 +44,7 @@ namespace MCGalaxy {
|
|||||||
public Position TargetPos;
|
public Position TargetPos;
|
||||||
public bool movement = false;
|
public bool movement = false;
|
||||||
public int movementSpeed = 3;
|
public int movementSpeed = 3;
|
||||||
internal sbyte curJump = 0;
|
internal int curJump = 0;
|
||||||
|
|
||||||
public PlayerBot(string n, Level lvl) {
|
public PlayerBot(string n, Level lvl) {
|
||||||
name = n; DisplayName = n; SkinName = n;
|
name = n; DisplayName = n; SkinName = n;
|
||||||
|
@ -69,22 +69,22 @@ namespace MCGalaxy {
|
|||||||
|
|
||||||
public static ColorDesc DefaultCol(char code) {
|
public static ColorDesc DefaultCol(char code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case '0': return new ColorDesc('0', "Black");
|
case '0': return new ColorDesc('0', "Black");
|
||||||
case '1': return new ColorDesc('1', "Navy");
|
case '1': return new ColorDesc('1', "Navy");
|
||||||
case '2': return new ColorDesc('2', "Green");
|
case '2': return new ColorDesc('2', "Green");
|
||||||
case '3': return new ColorDesc('3', "Teal");
|
case '3': return new ColorDesc('3', "Teal");
|
||||||
case '4': return new ColorDesc('4', "Maroon");
|
case '4': return new ColorDesc('4', "Maroon");
|
||||||
case '5': return new ColorDesc('5', "Purple");
|
case '5': return new ColorDesc('5', "Purple");
|
||||||
case '6': return new ColorDesc('6', "Gold");
|
case '6': return new ColorDesc('6', "Gold");
|
||||||
case '7': return new ColorDesc('7', "Silver");
|
case '7': return new ColorDesc('7', "Silver");
|
||||||
case '8': return new ColorDesc('8', "Gray");
|
case '8': return new ColorDesc('8', "Gray");
|
||||||
case '9': return new ColorDesc('9', "Blue");
|
case '9': return new ColorDesc('9', "Blue");
|
||||||
case 'a': return new ColorDesc('a', "Lime");
|
case 'a': return new ColorDesc('a', "Lime");
|
||||||
case 'b': return new ColorDesc('b', "Aqua");
|
case 'b': return new ColorDesc('b', "Aqua");
|
||||||
case 'c': return new ColorDesc('c', "Red");
|
case 'c': return new ColorDesc('c', "Red");
|
||||||
case 'd': return new ColorDesc('d', "Pink");
|
case 'd': return new ColorDesc('d', "Pink");
|
||||||
case 'e': return new ColorDesc('e', "Yellow");
|
case 'e': return new ColorDesc('e', "Yellow");
|
||||||
case 'f': return new ColorDesc('f', "White");
|
case 'f': return new ColorDesc('f', "White");
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorDesc col = default(ColorDesc);
|
ColorDesc col = default(ColorDesc);
|
||||||
@ -120,21 +120,21 @@ namespace MCGalaxy {
|
|||||||
if (code >= 'A' && code <= 'F') code += ' ';
|
if (code >= 'A' && code <= 'F') code += ' ';
|
||||||
return IsDefined(code) ? Get(code).Name : "";
|
return IsDefined(code) ? Get(code).Name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static readonly string[] ircColors = new string[] {
|
static readonly string[] ircColors = new string[] {
|
||||||
"\u000300", "\u000301", "\u000302", "\u000303", "\u000304", "\u000305",
|
"\u000300", "\u000301", "\u000302", "\u000303", "\u000304", "\u000305",
|
||||||
"\u000306", "\u000307", "\u000308", "\u000309", "\u000310", "\u000311",
|
"\u000306", "\u000307", "\u000308", "\u000309", "\u000310", "\u000311",
|
||||||
"\u000312", "\u000313", "\u000314", "\u000315",
|
"\u000312", "\u000313", "\u000314", "\u000315",
|
||||||
};
|
};
|
||||||
static readonly string[] ircSingle = new string[] {
|
static readonly string[] ircSingle = new string[] {
|
||||||
"\u00030", "\u00031", "\u00032", "\u00033", "\u00034", "\u00035",
|
"\u00030", "\u00031", "\u00032", "\u00033", "\u00034", "\u00035",
|
||||||
"\u00036", "\u00037", "\u00038", "\u00039",
|
"\u00036", "\u00037", "\u00038", "\u00039",
|
||||||
};
|
};
|
||||||
static readonly string[] ircReplacements = new string[] {
|
static readonly string[] ircReplacements = new string[] {
|
||||||
white, black, navy, green, red, maroon, purple, gold,
|
white, black, navy, green, red, maroon, purple, gold,
|
||||||
yellow, lime, teal, aqua, blue, pink, gray, silver,
|
yellow, lime, teal, aqua, blue, pink, gray, silver,
|
||||||
};
|
};
|
||||||
static readonly Regex IrcTwoColorCode = new Regex("(\x03\\d{1,2}),\\d{1,2}");
|
static readonly Regex IrcTwoColorCode = new Regex("(\x03\\d{1,2}),\\d{1,2}");
|
||||||
|
|
||||||
public static string ConvertIRCToMC(string input) {
|
public static string ConvertIRCToMC(string input) {
|
||||||
@ -187,7 +187,7 @@ namespace MCGalaxy {
|
|||||||
if (col == 'I') { col = ServerConfig.IRCColor[1]; return true; }
|
if (col == 'I') { col = ServerConfig.IRCColor[1]; return true; }
|
||||||
if (col == 'W') { col = ServerConfig.WarningErrorColor[1]; return true; }
|
if (col == 'W') { col = ServerConfig.WarningErrorColor[1]; return true; }
|
||||||
return IsDefined(col);
|
return IsDefined(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Converts percentage color codes to their actual/real color codes. </summary>
|
/// <summary> Converts percentage color codes to their actual/real color codes. </summary>
|
||||||
@ -234,8 +234,8 @@ namespace MCGalaxy {
|
|||||||
char color = chars[i + 1];
|
char color = chars[i + 1];
|
||||||
if (!Map(ref color)) continue;
|
if (!Map(ref color)) continue;
|
||||||
|
|
||||||
chars[i] = '&';
|
chars[i] = '&';
|
||||||
chars[i + 1] = color;
|
chars[i + 1] = color;
|
||||||
i++; // skip over color code
|
i++; // skip over color code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,8 +254,8 @@ namespace MCGalaxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new string(output, 0, usedChars);
|
return new string(output, 0, usedChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Removes all non-existent color codes, and converts
|
/// <summary> Removes all non-existent color codes, and converts
|
||||||
/// custom colors to their fallback standard color codes if required. </summary>
|
/// custom colors to their fallback standard color codes if required. </summary>
|
||||||
public static string Cleanup(string value, bool supportsCustomCols) {
|
public static string Cleanup(string value, bool supportsCustomCols) {
|
||||||
@ -322,38 +322,35 @@ namespace MCGalaxy {
|
|||||||
if (!(hex.Length == 3 || hex.Length == 6)) return false;
|
if (!(hex.Length == 3 || hex.Length == 6)) return false;
|
||||||
|
|
||||||
for (int i = 0; i < hex.Length; i++) {
|
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;
|
int R, G, B;
|
||||||
if (hex.Length == 6) {
|
if (hex.Length == 6) {
|
||||||
R = (Hex(hex[0]) << 4) | Hex(hex[1]);
|
R = (UnHex(hex[0]) << 4) | UnHex(hex[1]);
|
||||||
G = (Hex(hex[2]) << 4) | Hex(hex[3]);
|
G = (UnHex(hex[2]) << 4) | UnHex(hex[3]);
|
||||||
B = (Hex(hex[4]) << 4) | Hex(hex[5]);
|
B = (UnHex(hex[4]) << 4) | UnHex(hex[5]);
|
||||||
} else {
|
} else {
|
||||||
R = Hex(hex[0]); R |= (R << 4);
|
R = UnHex(hex[0]); R |= (R << 4);
|
||||||
G = Hex(hex[1]); G |= (G << 4);
|
G = UnHex(hex[1]); G |= (G << 4);
|
||||||
B = Hex(hex[2]); B |= (B << 4);
|
B = UnHex(hex[2]); B |= (B << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.R = (byte)R; c.G = (byte)G; c.B = (byte)B; c.A = 255;
|
c.R = (byte)R; c.G = (byte)G; c.B = (byte)B; c.A = 255;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Parses an #RRGGBB hex color string. </summary>
|
/// <summary> Parses an #RRGGBB hex color string. </summary>
|
||||||
public static ColorDesc ParseHex(string hex) {
|
public static ColorDesc ParseHex(string hex) {
|
||||||
ColorDesc c;
|
ColorDesc c;
|
||||||
if (!TryParseHex(hex, out c)) throw new ArgumentException("invalid input");
|
if (!TryParseHex(hex, out c)) throw new ArgumentException("invalid input");
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Hex(char value) {
|
public static int UnHex(char c) {
|
||||||
if (value >= '0' && value <= '9')
|
if (c >= '0' && c <= '9') { return (int)(c - '0'); }
|
||||||
return (int)(value - '0');
|
if (c >= 'a' && c <= 'f') { return (int)(c - 'a') + 10; }
|
||||||
if (value >= 'a' && value <= 'f')
|
if (c >= 'A' && c <= 'F') { return (int)(c - 'A') + 10; }
|
||||||
return (int)(value - 'a') + 10;
|
|
||||||
if (value >= 'A' && value <= 'F')
|
|
||||||
return (int)(value - 'A') + 10;
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -386,7 +383,7 @@ namespace MCGalaxy {
|
|||||||
r = (byte)(191 * ((hex >> 2) & 1) + 64 * (hex >> 3));
|
r = (byte)(191 * ((hex >> 2) & 1) + 64 * (hex >> 3));
|
||||||
g = (byte)(191 * ((hex >> 1) & 1) + 64 * (hex >> 3));
|
g = (byte)(191 * ((hex >> 1) & 1) + 64 * (hex >> 3));
|
||||||
b = (byte)(191 * ((hex >> 0) & 1) + 64 * (hex >> 3));
|
b = (byte)(191 * ((hex >> 0) & 1) + 64 * (hex >> 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsModified() {
|
public bool IsModified() {
|
||||||
if ((Code >= '0' && Code <= '9') || (Code >= 'a' && Code <= 'f')) {
|
if ((Code >= '0' && Code <= '9') || (Code >= 'a' && Code <= 'f')) {
|
||||||
|
@ -97,7 +97,6 @@ namespace MCGalaxy.Commands.CPE {
|
|||||||
|
|
||||||
SetBD(p, global, new BlockDefinition());
|
SetBD(p, global, new BlockDefinition());
|
||||||
BlockDefinition def = GetBD(p, global);
|
BlockDefinition def = GetBD(p, global);
|
||||||
def.Version2 = true;
|
|
||||||
def.SetBlock(target);
|
def.SetBlock(target);
|
||||||
|
|
||||||
p.Message("Use %T{0} abort %Sat anytime to abort the creation process.", cmd);
|
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) {
|
if (def.Shape == 0) {
|
||||||
p.Message(" Block is a sprite");
|
p.Message(" Block is a sprite");
|
||||||
p.Message(" Texture ID: {0}", def.SideTex);
|
p.Message(" Texture ID: {0}", def.RightTex);
|
||||||
} else {
|
} else {
|
||||||
p.Message(" Block is a cube from ({0}, {1}, {2}) to ({3}, {4}, {5})",
|
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);
|
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) {
|
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) {
|
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);
|
BlockDefinition.Remove(def, defs, p.IsSuper ? null : p.level);
|
||||||
|
|
||||||
string scope = global ? "global" : "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];
|
BlockDefinition globalDef = BlockDefinition.GlobalDefs[block];
|
||||||
if (!global && globalDef != null)
|
if (!global && globalDef != null)
|
||||||
@ -291,8 +290,8 @@ namespace MCGalaxy.Commands.CPE {
|
|||||||
if (bd.Shape == 0) bd.SetAllTex(bd.TopTex);
|
if (bd.Shape == 0) bd.SetAllTex(bd.TopTex);
|
||||||
}
|
}
|
||||||
} else if (step == 5) {
|
} else if (step == 5) {
|
||||||
if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.SideTex, 0, 255)) {
|
if (CommandParser.GetUShort(p, value, "Texture ID", ref bd.RightTex, 0, 255)) {
|
||||||
bd.SetSideTex(bd.SideTex);
|
bd.SetSideTex(bd.RightTex);
|
||||||
step++;
|
step++;
|
||||||
}
|
}
|
||||||
} else if (step == 6) {
|
} else if (step == 6) {
|
||||||
@ -401,12 +400,12 @@ namespace MCGalaxy.Commands.CPE {
|
|||||||
if (!EditUShort(p, value, "Top texture", ref def.TopTex, arg)) return;
|
if (!EditUShort(p, value, "Top texture", ref def.TopTex, arg)) return;
|
||||||
break;
|
break;
|
||||||
case "alltex":
|
case "alltex":
|
||||||
if (!EditUShort(p, value, "All textures", ref def.SideTex, arg)) return;
|
if (!EditUShort(p, value, "All textures", ref def.RightTex, arg)) return;
|
||||||
def.SetAllTex(def.SideTex);
|
def.SetAllTex(def.RightTex);
|
||||||
break;
|
break;
|
||||||
case "sidetex":
|
case "sidetex":
|
||||||
if (!EditUShort(p, value, "Side texture", ref def.SideTex, arg)) return;
|
if (!EditUShort(p, value, "Side texture", ref def.RightTex, arg)) return;
|
||||||
def.SetSideTex(def.SideTex);
|
def.SetSideTex(def.RightTex);
|
||||||
break;
|
break;
|
||||||
case "lefttex":
|
case "lefttex":
|
||||||
if (!EditUShort(p, value, "Left texture", ref def.LeftTex, arg)) return;
|
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
|
// 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++) {
|
for (int i = 0; i < defs.Length; i++) {
|
||||||
if (defs[i] == null || defs[i].InventoryOrder != order) continue;
|
if (defs[i] == null || defs[i].InventoryOrder != order) continue;
|
||||||
p.Message("Block {0} already had order {1}", defs[i].Name, order);
|
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.UpdateOrder(def, global, level);
|
||||||
BlockDefinition.Save(global, level);
|
BlockDefinition.Save(global, level);
|
||||||
p.Message("Set inventory order for {0} to {1}", blockName,
|
p.Message("Set inventory order for {0} to {1}", blockName,
|
||||||
order == def.BlockID ? "default" : order.ToString());
|
order == def.RawID ? "default" : order.ToString());
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
p.Message("Unrecognised property: " + arg); return;
|
p.Message("Unrecognised property: " + arg); return;
|
||||||
@ -528,7 +527,7 @@ namespace MCGalaxy.Commands.CPE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string scope = global ? "global" : "level";
|
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();
|
block = def.GetBlock();
|
||||||
BlockDefinition.Add(def, defs, p.IsSuper ? null : p.level);
|
BlockDefinition.Add(def, defs, p.IsSuper ? null : p.level);
|
||||||
|
@ -46,6 +46,8 @@ namespace MCGalaxy {
|
|||||||
ConfigElement elem;
|
ConfigElement elem;
|
||||||
elem.Field = field;
|
elem.Field = field;
|
||||||
elem.Attrib = (ConfigAttribute)attributes[0];
|
elem.Attrib = (ConfigAttribute)attributes[0];
|
||||||
|
|
||||||
|
if (elem.Attrib.Name == null) elem.Attrib.Name = field.Name;
|
||||||
elems.Add(elem);
|
elems.Add(elem);
|
||||||
}
|
}
|
||||||
return elems.ToArray();
|
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 {
|
public class ConfigIntAttribute : ConfigAttribute {
|
||||||
int defValue, minValue, maxValue;
|
int defValue, minValue, maxValue;
|
||||||
|
|
||||||
|
public ConfigIntAttribute()
|
||||||
|
: this(null, null, 0, int.MinValue, int.MaxValue) { }
|
||||||
public ConfigIntAttribute(string name, string section, int def,
|
public ConfigIntAttribute(string name, string section, int def,
|
||||||
int min = int.MinValue, int max = int.MaxValue)
|
int min = int.MinValue, int max = int.MaxValue)
|
||||||
: base(name, section) { defValue = def; minValue = min; maxValue = max; }
|
: base(name, section) { defValue = def; minValue = min; maxValue = max; }
|
||||||
@ -47,8 +49,7 @@ namespace MCGalaxy.Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hacky workaround for old ExponentialFog attribute
|
// Hacky workaround for old ExponentialFog attribute
|
||||||
public sealed class ConfigBoolIntAttribute : ConfigIntAttribute {
|
sealed class ConfigBoolIntAttribute : ConfigIntAttribute {
|
||||||
|
|
||||||
public ConfigBoolIntAttribute(string name, string section, int defValue)
|
public ConfigBoolIntAttribute(string name, string section, int defValue)
|
||||||
: base(name, section, defValue, -1, 1) {
|
: 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)
|
public ConfigBlockAttribute(string name, string section, int def)
|
||||||
: base(name, section, def, 0, Block.ExtendedCount - 1) {
|
: 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 {
|
public class ConfigRealAttribute : ConfigAttribute {
|
||||||
float defValue, minValue, maxValue;
|
float defValue, minValue, maxValue;
|
||||||
|
|
||||||
|
public ConfigRealAttribute()
|
||||||
|
: this(null, null, 0, float.NegativeInfinity, float.PositiveInfinity) { }
|
||||||
public ConfigRealAttribute(string name, string section, float def,
|
public ConfigRealAttribute(string name, string section, float def,
|
||||||
float min = float.NegativeInfinity, float max = float.PositiveInfinity)
|
float min = float.NegativeInfinity, float max = float.PositiveInfinity)
|
||||||
: base(name, section) { defValue = def; minValue = min; maxValue = max; }
|
: base(name, section) { defValue = def; minValue = min; maxValue = max; }
|
||||||
|
@ -23,6 +23,7 @@ namespace MCGalaxy.Config {
|
|||||||
public sealed class ConfigBoolAttribute : ConfigAttribute {
|
public sealed class ConfigBoolAttribute : ConfigAttribute {
|
||||||
bool defValue;
|
bool defValue;
|
||||||
|
|
||||||
|
public ConfigBoolAttribute() : this(null, null, false) { }
|
||||||
public ConfigBoolAttribute(string name, string section, bool def)
|
public ConfigBoolAttribute(string name, string section, bool def)
|
||||||
: base(name, section) { defValue = def; }
|
: base(name, section) { defValue = def; }
|
||||||
|
|
||||||
@ -34,6 +35,11 @@ namespace MCGalaxy.Config {
|
|||||||
}
|
}
|
||||||
return boolValue;
|
return boolValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string Serialise(object value) {
|
||||||
|
bool boolValue = (bool)value;
|
||||||
|
return boolValue ? "true" : "false";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ConfigPermAttribute : ConfigAttribute {
|
public sealed class ConfigPermAttribute : ConfigAttribute {
|
||||||
|
@ -56,8 +56,11 @@ namespace MCGalaxy.Config {
|
|||||||
public ConfigStringAttribute(string name, string section, string def)
|
public ConfigStringAttribute(string name, string section, string def)
|
||||||
: base(name, section) { defValue = def; }
|
: base(name, section) { defValue = def; }
|
||||||
|
|
||||||
|
public ConfigStringAttribute()
|
||||||
|
: base(null, null) { allowEmpty = true; }
|
||||||
|
|
||||||
public override object Parse(string value) {
|
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);
|
Logger.Log(LogType.Warning, "Config key \"{0}\" has no value, using default of {1}", Name, defValue);
|
||||||
return defValue;
|
return defValue;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ namespace MCGalaxy.Levels.IO {
|
|||||||
|
|
||||||
NbtCompound props = (NbtCompound)tag;
|
NbtCompound props = (NbtCompound)tag;
|
||||||
BlockDefinition def = new BlockDefinition();
|
BlockDefinition def = new BlockDefinition();
|
||||||
def.BlockID = props["ID"].ByteValue;
|
def.RawID = props["ID"].ByteValue;
|
||||||
def.Name = props["Name"].StringValue;
|
def.Name = props["Name"].StringValue;
|
||||||
def.CollideType = props["CollideType"].ByteValue;
|
def.CollideType = props["CollideType"].ByteValue;
|
||||||
def.Speed = props["Speed"].FloatValue;
|
def.Speed = props["Speed"].FloatValue;
|
||||||
@ -154,8 +154,6 @@ namespace MCGalaxy.Levels.IO {
|
|||||||
BlockDefinition globalDef = BlockDefinition.GlobalDefs[block];
|
BlockDefinition globalDef = BlockDefinition.GlobalDefs[block];
|
||||||
if (PropsEquals(def, globalDef)) continue;
|
if (PropsEquals(def, globalDef)) continue;
|
||||||
|
|
||||||
def.SideTex = def.LeftTex;
|
|
||||||
def.Version2 = true;
|
|
||||||
lvl.UpdateCustomBlock(block, def);
|
lvl.UpdateCustomBlock(block, def);
|
||||||
hasBlockDefs = true;
|
hasBlockDefs = true;
|
||||||
}
|
}
|
||||||
|
@ -71,9 +71,6 @@
|
|||||||
<Reference Include="MySql.Data">
|
<Reference Include="MySql.Data">
|
||||||
<HintPath>..\MySql.Data.dll</HintPath>
|
<HintPath>..\MySql.Data.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json">
|
|
||||||
<HintPath>..\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
@ -377,6 +374,7 @@
|
|||||||
<Compile Include="Commands\World\CmdUnload.cs" />
|
<Compile Include="Commands\World\CmdUnload.cs" />
|
||||||
<Compile Include="Commands\World\PermissionCmds.cs" />
|
<Compile Include="Commands\World\PermissionCmds.cs" />
|
||||||
<Compile Include="Config\ConfigAttribute.cs" />
|
<Compile Include="Config\ConfigAttribute.cs" />
|
||||||
|
<Compile Include="Config\JSON.cs" />
|
||||||
<Compile Include="Config\NumberAttributes.cs" />
|
<Compile Include="Config\NumberAttributes.cs" />
|
||||||
<Compile Include="Config\OtherAttributes.cs" />
|
<Compile Include="Config\OtherAttributes.cs" />
|
||||||
<Compile Include="Config\ConfigElement.cs" />
|
<Compile Include="Config\ConfigElement.cs" />
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
permissions and limitations under the Licenses.
|
permissions and limitations under the Licenses.
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using MCGalaxy.Config;
|
||||||
using MCGalaxy.Events.ServerEvents;
|
using MCGalaxy.Events.ServerEvents;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace MCGalaxy.Network {
|
namespace MCGalaxy.Network {
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ namespace MCGalaxy.Network {
|
|||||||
OnSendingHeartbeatEvent.Call(this, ref name);
|
OnSendingHeartbeatEvent.Call(this, ref name);
|
||||||
name = Colors.Strip(name);
|
name = Colors.Strip(name);
|
||||||
|
|
||||||
return
|
return
|
||||||
"&port=" + ServerConfig.Port +
|
"&port=" + ServerConfig.Port +
|
||||||
"&max=" + ServerConfig.MaxPlayers +
|
"&max=" + ServerConfig.MaxPlayers +
|
||||||
"&name=" + Uri.EscapeDataString(name) +
|
"&name=" + Uri.EscapeDataString(name) +
|
||||||
@ -76,43 +77,52 @@ namespace MCGalaxy.Network {
|
|||||||
public override void OnRequest(HttpWebRequest request) {
|
public override void OnRequest(HttpWebRequest request) {
|
||||||
if (proxyUrl == null) return;
|
if (proxyUrl == null) return;
|
||||||
request.Proxy = new WebProxy(proxyUrl);
|
request.Proxy = new WebProxy(proxyUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnResponse(string response) {
|
public override void OnResponse(string response) {
|
||||||
if (String.IsNullOrEmpty(response)) return;
|
if (String.IsNullOrEmpty(response)) return;
|
||||||
|
|
||||||
// in form of http://www.classicube.net/server/play/<hash>/
|
// in form of http://www.classicube.net/server/play/<hash>/
|
||||||
if (response.EndsWith("/"))
|
if (response.EndsWith("/"))
|
||||||
response = response.Substring(0, response.Length - 1);
|
response = response.Substring(0, response.Length - 1);
|
||||||
string hash = response.Substring(response.LastIndexOf('/') + 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
|
// only need to do this when contents have changed
|
||||||
if (String.IsNullOrEmpty(Server.Hash) || hash != Server.Hash) {
|
if (hash == Server.Hash) return;
|
||||||
Server.Hash = hash;
|
Server.Hash = hash;
|
||||||
Server.URL = response;
|
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.URL = error;
|
||||||
Server.UpdateUrl(Server.URL);
|
Server.UpdateUrl(Server.URL);
|
||||||
File.WriteAllText("text/externalurl.txt", Server.URL);
|
Logger.Log(LogType.Warning, response);
|
||||||
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)
|
static string GetError(string json) {
|
||||||
Server.URL = resp.errors[0][0];
|
JsonContext ctx = new JsonContext(); ctx.Val = json;
|
||||||
else
|
JsonObject obj = (JsonObject)Json.ParseStream(ctx);
|
||||||
Server.URL = "Error while finding URL. Is the port open?";
|
if (obj == null) return null;
|
||||||
Server.UpdateUrl(Server.URL);
|
|
||||||
Logger.Log(LogType.Warning, response);
|
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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
|
|
||||||
#pragma warning disable 0649
|
|
||||||
class Response {
|
|
||||||
public string[][] errors;
|
|
||||||
public string response;
|
|
||||||
public string status;
|
|
||||||
}
|
}
|
||||||
#pragma warning restore 0649
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ namespace MCGalaxy.Network {
|
|||||||
public static byte[] UndefineBlock(BlockDefinition def, bool extBlocks) {
|
public static byte[] UndefineBlock(BlockDefinition def, bool extBlocks) {
|
||||||
byte[] buffer = new byte[extBlocks ? 3 : 2];
|
byte[] buffer = new byte[extBlocks ? 3 : 2];
|
||||||
buffer[0] = Opcode.CpeUndefineBlock;
|
buffer[0] = Opcode.CpeUndefineBlock;
|
||||||
NetUtils.WriteBlock(def.BlockID, buffer, 1, extBlocks);
|
NetUtils.WriteBlock(def.RawID, buffer, 1, extBlocks);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,7 +414,7 @@ namespace MCGalaxy.Network {
|
|||||||
// speed = 2^((raw - 128) / 64);
|
// speed = 2^((raw - 128) / 64);
|
||||||
// therefore raw = 64log2(speed) + 128
|
// therefore raw = 64log2(speed) + 128
|
||||||
byte rawSpeed = (byte)(64 * Math.Log(def.Speed, 2) + 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;
|
i += extBlocks ? 2 : 1;
|
||||||
NetUtils.Write(def.Name, buffer, i, hasCP437);
|
NetUtils.Write(def.Name, buffer, i, hasCP437);
|
||||||
i += NetUtils.StringSize;
|
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.LeftTex, extTexs); WriteTex(buffer, ref i, def.RightTex, extTexs);
|
||||||
WriteTex(buffer, ref i, def.FrontTex, extTexs); WriteTex(buffer, ref i, def.BackTex, extTexs);
|
WriteTex(buffer, ref i, def.FrontTex, extTexs); WriteTex(buffer, ref i, def.BackTex, extTexs);
|
||||||
} else {
|
} else {
|
||||||
WriteTex(buffer, ref i, def.SideTex, extTexs);
|
WriteTex(buffer, ref i, def.RightTex, extTexs);
|
||||||
}
|
}
|
||||||
WriteTex(buffer, ref i, def.BottomTex, extTexs);
|
WriteTex(buffer, ref i, def.BottomTex, extTexs);
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ namespace MCGalaxy {
|
|||||||
BlockDefinition def = defs[i];
|
BlockDefinition def = defs[i];
|
||||||
if (def == BlockDefinition.GlobalDefs[i] || def == null) continue;
|
if (def == BlockDefinition.GlobalDefs[i] || def == null) continue;
|
||||||
|
|
||||||
if (def.BlockID > MaxRawBlock) continue;
|
if (def.RawID > MaxRawBlock) continue;
|
||||||
Send(Packet.UndefineBlock(def, hasExtBlocks));
|
Send(Packet.UndefineBlock(def, hasExtBlocks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,6 @@ namespace MCGalaxy {
|
|||||||
CheckFile("MySql.Data.dll");
|
CheckFile("MySql.Data.dll");
|
||||||
CheckFile("sqlite3_x32.dll");
|
CheckFile("sqlite3_x32.dll");
|
||||||
CheckFile("sqlite3_x64.dll");
|
CheckFile("sqlite3_x64.dll");
|
||||||
CheckFile("Newtonsoft.Json.dll");
|
|
||||||
CheckFile("LibNoise.dll");
|
CheckFile("LibNoise.dll");
|
||||||
|
|
||||||
EnsureFilesExist();
|
EnsureFilesExist();
|
||||||
|
@ -20,9 +20,7 @@ using System.Collections.Generic;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MCGalaxy.Bots;
|
using MCGalaxy.Bots;
|
||||||
using MCGalaxy.DB;
|
|
||||||
using MCGalaxy.SQL;
|
using MCGalaxy.SQL;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace MCGalaxy.Tasks {
|
namespace MCGalaxy.Tasks {
|
||||||
internal static class UpgradeTasks {
|
internal static class UpgradeTasks {
|
||||||
@ -137,12 +135,12 @@ namespace MCGalaxy.Tasks {
|
|||||||
Logger.Log(LogType.SystemActivity, "Making bots file per-level.. " +
|
Logger.Log(LogType.SystemActivity, "Making bots file per-level.. " +
|
||||||
"saved backup of global bots file to extra/bots.json.bak");
|
"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>>();
|
Dictionary<string, List<BotProperties>> botsByLevel = new Dictionary<string, List<BotProperties>>();
|
||||||
|
|
||||||
foreach (BotProperties bot in bots) {
|
foreach (BotProperties bot in bots) {
|
||||||
List<BotProperties> levelBots;
|
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)) {
|
if (!botsByLevel.TryGetValue(bot.Level, out levelBots)) {
|
||||||
levelBots = new List<BotProperties>();
|
levelBots = new List<BotProperties>();
|
||||||
@ -152,8 +150,10 @@ namespace MCGalaxy.Tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kvp in botsByLevel) {
|
foreach (var kvp in botsByLevel) {
|
||||||
json = JsonConvert.SerializeObject(kvp.Value);
|
string path = BotsFile.BotsPath(kvp.Key);
|
||||||
File.WriteAllText(BotsFile.BotsPath(kvp.Key), json);
|
using (StreamWriter w = new StreamWriter(path)) {
|
||||||
|
BotsFile.WriteAll(w, kvp.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Server.mainLevel.Bots.Count == 0) {
|
if (Server.mainLevel.Bots.Count == 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user