Core: Block properties now save.

This commit is contained in:
UnknownShadow200 2016-10-25 20:08:04 +11:00
parent d043a3d8ed
commit b86944f59d
8 changed files with 163 additions and 40 deletions

View File

@ -51,6 +51,7 @@ namespace MCGalaxy
BlockBehaviour.SetupCoreHandlers();
BlockBehaviour.SetupCorePhysicsHandlers();
InitDefaults();
BlockProps.Load("core", Block.Props);
// Custom permissions set by the user.
if (File.Exists("properties/block.properties")) {

View File

@ -21,7 +21,7 @@ using System.Text;
using MCGalaxy.Blocks;
using Newtonsoft.Json;
namespace MCGalaxy {
namespace MCGalaxy {
public sealed class BlockDefinition {
public byte BlockID;
@ -45,7 +45,7 @@ namespace MCGalaxy {
public const string GlobalPath = "blockdefs/global.json", GlobalBackupPath = "blockdefs/global.json.bak";
public static BlockDefinition[] GlobalDefs;
public static BlockDefinition[] GlobalDefs;
public static Blocks.BlockProps[] GlobalProps;
public BlockDefinition Copy() {
@ -71,7 +71,7 @@ namespace MCGalaxy {
GlobalDefs = Load(true, null);
GlobalDefs[0] = new BlockDefinition();
GlobalDefs[0].Name = "Air fallback";
GlobalProps = new BlockProps[256];
for (int i = 0; i < GlobalProps.Length; i++)
GlobalProps[i] = new BlockProps((byte)i);
@ -84,7 +84,9 @@ namespace MCGalaxy {
} catch (Exception ex) {
Server.ErrorLog(ex);
}
Save(true, null);
BlockProps.Load("global", BlockDefinition.GlobalProps);
}
internal static BlockDefinition[] Load(bool global, Level lvl) {
@ -100,7 +102,7 @@ namespace MCGalaxy {
defs = new BlockDefinition[256];
}
for (int i = 0; i < 256; i++) {
for (int i = 0; i < 256; i++) {
if (defs[i] != null && defs[i].Name == null)
defs[i] = null;
}
@ -127,7 +129,7 @@ namespace MCGalaxy {
realDefs[i] = defs[i] == GlobalDefs[i] ? null : defs[i];
defs = realDefs;
}
string json = JsonConvert.SerializeObject(defs);
string path = global ? GlobalPath : "blockdefs/lvl_" + lvl.name + ".json";
File.WriteAllText(path, json);
@ -135,13 +137,12 @@ namespace MCGalaxy {
public static void Add(BlockDefinition def, BlockDefinition[] defs, Level level) {
byte id = def.BlockID;
bool global = defs == GlobalDefs;
bool global = defs == GlobalDefs;
if (global) {
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[id] == null) {
lvl.CustomBlockDefs[id] = def;
lvl.CustomBlockProps[id] = GlobalProps[id];
}
}
}
@ -174,7 +175,6 @@ namespace MCGalaxy {
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[id] == GlobalDefs[id]) {
lvl.CustomBlockDefs[id] = null;
lvl.CustomBlockProps[id] = new BlockProps(id);
}
}
}
@ -216,7 +216,7 @@ namespace MCGalaxy {
public static byte GetBlock(string msg, BlockDefinition[] defs) {
for (int i = 1; i < Block.Invalid; i++) {
BlockDefinition def = defs[i];
if (def == null) continue;
if (def == null) continue;
if (def.Name.Replace(" ", "").CaselessEq(msg))
return def.BlockID;
}
@ -259,7 +259,7 @@ namespace MCGalaxy {
byte rawSpeed = (byte)(64 * Math.Log(def.Speed, 2) + 128);
buffer[index++] = def.BlockID;
NetUtils.WriteAscii(def.Name, buffer, index);
index += 64;
index += 64;
buffer[index++] = def.CollideType;
buffer[index++] = rawSpeed;

View File

@ -17,6 +17,7 @@
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace MCGalaxy.Blocks {
@ -59,6 +60,9 @@ namespace MCGalaxy.Blocks {
/// <summary> Whether this block should allow trains to go over them. </summary>
public bool IsRails;
/// <summary> Whether the properties for this block have been modified and hence require saving. </summary>
public bool Changed;
public BlockProps(byte block) {
this = default(BlockProps);
BlockId = block;
@ -66,5 +70,62 @@ namespace MCGalaxy.Blocks {
Name = "unknown";
ODoorId = Block.Invalid;
}
public static void Save(string group, BlockProps[] scope) {
if (!Directory.Exists("blockprops"))
Directory.CreateDirectory("blockprops");
using (StreamWriter w = new StreamWriter("blockprops/" + group + ".txt")) {
w.WriteLine("# This represents the physics properties for blocks, in the format of:");
w.WriteLine("# id : Is rails : Is tdoor : Is door : Is message block : Is portal : " +
"Killed by water : Killed by lava : Kills players : death message");
for (int i = 0; i < scope.Length; i++) {
if (!scope[i].Changed) continue;
BlockProps props = scope[i];
string deathMsg = props.DeathMessage == null ? "" : props.DeathMessage.Replace(":", "\\;");
w.WriteLine(i + ":" + props.IsRails + ":" + props.IsTDoor + ":" + props.IsDoor + ":"
+ props.IsMessageBlock + ":" + props.IsPortal + ":" + props.WaterKills + ":"
+ props.LavaKills + ":" + props.KillerBlock + ":" + deathMsg);
}
}
}
public static void Load(string group, BlockProps[] scope) {
if (!Directory.Exists("blockprops")) return;
if (!File.Exists("blockprops/" + group + ".txt")) return;
string[] lines = File.ReadAllLines("blockprops/" + group + ".txt");
for (int i = 0; i < lines.Length; i++) {
string line = lines[i].Trim();
if (line.Length == 0 || line[0] == '#') continue;
string[] parts = line.Split(':');
if (parts.Length != 10) {
Server.s.Log("Invalid line \"" + line + "\" in " + group + " block properties");
continue;
}
byte id;
if (!Byte.TryParse(parts[0], out id)) {
Server.s.Log("Invalid line \"" + line + "\" in " + group + " block properties");
continue;
}
bool.TryParse(parts[1], out scope[id].IsRails);
bool.TryParse(parts[2], out scope[id].IsTDoor);
bool.TryParse(parts[3], out scope[id].IsDoor);
bool.TryParse(parts[4], out scope[id].IsMessageBlock);
bool.TryParse(parts[5], out scope[id].IsPortal);
bool.TryParse(parts[6], out scope[id].WaterKills);
bool.TryParse(parts[7], out scope[id].LavaKills);
bool.TryParse(parts[8], out scope[id].KillerBlock);
scope[id].Changed = true;
scope[id].DeathMessage = parts[9].Replace("\\;", ":");
if (scope[id].DeathMessage == "")
scope[id].DeathMessage = null;
}
}
}
}

View File

@ -17,6 +17,7 @@
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Blocks;
using MCGalaxy.Commands.Building;
namespace MCGalaxy.Commands.CPE {
@ -115,6 +116,7 @@ namespace MCGalaxy.Commands.CPE {
dst = src.Copy();
dst.BlockID = (byte)dstId;
AddBlockProperties(global, (byte)dstId, p);
BlockDefinition.Add(dst, defs, p == null ? null : p.level);
bool globalBlock = defs[srcId] == BlockDefinition.GlobalDefs[srcId];
@ -141,18 +143,20 @@ namespace MCGalaxy.Commands.CPE {
Player.Message(p, " Fallback ID: " + def.FallBack + ", Sound: " +
def.WalkSound + ", Speed: " + def.Speed.ToString("F2"));
if (def.FogDensity == 0)
if (def.FogDensity == 0) {
Player.Message(p, " Block does not use fog");
else
} else {
Player.Message(p, " Fog density: " + def.FogDensity + ", R: " +
def.FogR + ", G: " + def.FogG + ", B: " + def.FogB);
}
if (def.Shape == 0)
if (def.Shape == 0) {
Player.Message(p, " Block is a sprite");
else
} else {
Player.Message(p, " Block is a cube from (" +
def.MinX + "," + def.MinY + "," + def.MinZ + ") to ("
+ def.MaxX + "," + def.MaxY + "," + def.MaxZ + ")");
}
}
static void ListHandler(Player p, string[] parts, bool global, string cmd) {
@ -175,18 +179,19 @@ namespace MCGalaxy.Commands.CPE {
static void RemoveHandler(Player p, string[] parts, bool global, string cmd) {
if (parts.Length <= 1) { Help(p, cmd); return; }
int blockId;
if (!CheckBlockId(p, parts[1], global, out blockId)) return;
int id;
if (!CheckBlockId(p, parts[1], global, out id)) return;
BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : p.level.CustomBlockDefs;
BlockDefinition def = defs[blockId];
if (!ExistsInScope(def, blockId, global)) { MessageNoBlock(p, blockId, global, cmd); return; }
BlockDefinition def = defs[id];
if (!ExistsInScope(def, id, global)) { MessageNoBlock(p, id, global, cmd); return; }
RemoveBlockProperties(global, (byte)id, p);
BlockDefinition.Remove(def, defs, p == null ? null : p.level);
BlockDefinition globalDef = BlockDefinition.GlobalDefs[blockId];
if (!global && globalDef != null) {
BlockDefinition.Add(globalDef, defs, p == null ? null : p.level);
}
BlockDefinition globalDef = BlockDefinition.GlobalDefs[id];
if (!global && globalDef != null)
BlockDefinition.Add(globalDef, defs, p.level);
}
static void DefineBlockStep(Player p, string value, bool global, string cmd) {
@ -436,6 +441,7 @@ namespace MCGalaxy.Commands.CPE {
string scope = global ? "global" : "level";
Player.Message(p, "Created a new " + scope + " custom block " + bd.Name + "(" + bd.BlockID + ")");
AddBlockProperties(global, bd.BlockID, p);
BlockDefinition.Add(bd, defs, p == null ? null : p.level);
return true;
}
@ -544,6 +550,41 @@ namespace MCGalaxy.Commands.CPE {
return true;
}
static void AddBlockProperties(bool global, byte id, Player p) {
if (!global) {
p.level.CustomBlockProps[id] = new BlockProps((byte)id);
} else {
BlockDefinition.GlobalProps[id] = new BlockProps((byte)id);
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[id] != null) continue;
lvl.CustomBlockProps[id] = new BlockProps((byte)id);
}
}
}
static void RemoveBlockProperties(bool global, byte id, Player p) {
BlockDefinition globalDef = BlockDefinition.GlobalDefs[id];
// Level block reverts to using global block
if (!global && BlockDefinition.GlobalDefs[id] != null) {
p.level.CustomBlockProps[id] = BlockDefinition.GlobalProps[id];
} else if (!global) {
p.level.CustomBlockProps[id] = new BlockProps((byte)id);
} else {
BlockDefinition.GlobalProps[id] = new BlockProps((byte)id);
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[id] != BlockDefinition.GlobalDefs[id]) continue;
lvl.CustomBlockProps[id] = new BlockProps((byte)id);
}
}
}
static BlockDefinition consoleBD;
static int consoleStep, consoleTargetId;

View File

@ -37,16 +37,21 @@ namespace MCGalaxy.Commands.World {
byte id = GetBlock(p, scope, args[1]);
if (id == Block.Invalid) return;
string prop = args[2].ToLower();
// TODO: global and level custom blocks
// TODO: adding core blocks, changing core block names
SetProperty(p, scope, id, prop, args);
}
BlockProps[] GetScope(Player p, string scope) {
if (scope.CaselessEq("core")) return Block.Props;
if (scope.CaselessEq("global")) return BlockDefinition.GlobalProps;
if (scope.CaselessEq("level")) return p.level.CustomBlockProps;
if (scope.CaselessEq("level")) {
if (Player.IsSuper(p)) {
string src = p == null ? "console" : "IRC";
Player.Message(p, "Cannot use level scope from {0}.", src);
return null;
}
return p.level.CustomBlockProps;
}
Player.Message(p, "&cScope must \"core\", \"global\", or \"level\"");
return null;
@ -126,44 +131,55 @@ namespace MCGalaxy.Commands.World {
BlockProps props = scope[id];
setter(ref props);
scope[id] = props;
OnPropsChanged(scope, id);
Level lvl = Player.IsSuper(p) ? null : p.level;
Player.Message(p, "Block {0} is {1}: {2}",
BlockName(scope, p.level, id),
BlockName(scope, lvl, id),
type, getter(props) ? "&aYes" : "&cNo");
OnPropsChanged(scope, lvl, id);
}
static void SetDeathMessage(Player p, BlockProps[] scope, byte id, string msg) {
scope[id].DeathMessage = msg;
Level lvl = Player.IsSuper(p) ? null : p.level;
if (msg == null) {
Player.Message(p, "Death message for {0} removed.",
BlockName(scope, p.level, id));
BlockName(scope, lvl, id));
} else {
Player.Message(p, "Death message for {0} set to: {1}",
BlockName(scope, p.level, id), msg);
BlockName(scope, lvl, id), msg);
}
OnPropsChanged(scope, id);
OnPropsChanged(scope, lvl, id);
}
static void OnPropsChanged(BlockProps[] scope, byte id) {
static void OnPropsChanged(BlockProps[] scope, Level level, byte id) {
scope[id].Changed = true;
if (scope == Block.Props) {
BlockBehaviour.SetupCoreHandlers();
BlockProps.Save("core", scope);
} else if (scope == BlockDefinition.GlobalProps) {
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[id] != BlockDefinition.GlobalDefs[id]) continue;
lvl.CustomBlockProps[id] = BlockDefinition.GlobalProps[id];
}
BlockProps.Save("global", scope);
} else {
BlockProps.Save("lvl_" + level.name, scope);
}
}
static string BlockName(BlockProps[] scope, Level lvl, byte id) {
byte block = id, extBlock = 0;
if (scope != Block.Props) {
block = Block.custom_block; extBlock = id;
}
return lvl.BlockName(block, extBlock);
static string BlockName(BlockProps[] scope, Level lvl, byte raw) {
if (scope == Block.Props) return Block.Name(raw);
BlockDefinition def = null;
if (scope == BlockDefinition.GlobalProps)
def = BlockDefinition.GlobalDefs[raw];
else
def = lvl.CustomBlockDefs[raw];
return def == null ? raw.ToString() : def.Name.Replace(" ", "");
}
public override void Help(Player p) {

View File

@ -379,7 +379,9 @@ namespace MCGalaxy {
for (int i = 0; i < defs.Length; i++) {
if (defs[i] == null) continue;
level.CustomBlockDefs[i] = defs[i];
level.CustomBlockProps[i] = new BlockProps((byte)i);
}
BlockProps.Load("lvl_" + level.name, level.CustomBlockProps);
Bots.BotsFile.LoadBots(level);
object locker = ThreadSafeCache.DBCache.Get(name);

View File

@ -225,7 +225,7 @@ namespace MCGalaxy {
cmd = cmd.Replace(" unsigned", " UNSIGNED");
if (!Server.useMySQL) return;
// MySQL does not support the format used by the old SQLite backend for the primary key
// MySQL does not support the format used by the SQLite backend for the primary key
const string priKey = " PRIMARY KEY AUTOINCREMENT";
int priIndex = cmd.ToUpper().IndexOf(priKey);
if (priIndex == -1) return;

View File

@ -19,6 +19,7 @@ using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using MCGalaxy.Blocks;
using MCGalaxy.Games;
using MCGalaxy.Tasks;
using Newtonsoft.Json;
@ -209,6 +210,7 @@ namespace MCGalaxy {
Alias.Load();
Bots.BotsFile.Load();
BlockDefinition.LoadGlobal();
SrvProperties.Load("properties/server.properties");
Updater.Load("properties/update.properties");
Group.InitAll();