Completely separate blockprops from blocks list.

This means you can change blockprops of any block on a per-level basis, no longer only works on /lb. This also means the GUI can change block props of global blocks
This commit is contained in:
UnknownShadow200 2018-02-17 20:33:52 +11:00
parent c129acb0a4
commit d357a75a66
13 changed files with 303 additions and 382 deletions

View File

@ -20,42 +20,56 @@ using System.Collections.Generic;
using System.Windows.Forms;
using MCGalaxy.Blocks;
using BlockID = System.UInt16;
using BlockRaw = System.Byte;
namespace MCGalaxy.Gui {
public partial class PropertyWindow : Form {
bool blockSupressEvents = true;
ComboBox[] blockAllowBoxes, blockDisallowBoxes;
byte blockID;
BlockID curBlock;
List<BlockID> blockIDMap;
// need to keep a list of changed block perms, because we don't want
// to modify the server's live permissions if user clicks 'discard'
BlockPerms blockPermsOrig, blockPerms;
List<BlockPerms> blockPermsChanged = new List<BlockPerms>();
BlockProps[] blockPropsChanged = new BlockProps[Block.Props.Length];
BlockProps[] blockPropsChanged = new BlockProps[Block.Props.Length];
void LoadBlocks() {
blk_list.Items.Clear();
blockPermsChanged.Clear();
for (int i = 0; i < Block.Props.Length; i++) {
blockPropsChanged[i] = Block.Props[i];
blockPropsChanged[i].Changed = false;
if (Block.Undefined((BlockID)i)) continue;
string name = Block.GetName(null, (byte)i);
blockIDMap = new List<BlockID>();
for (int b = 0; b < blockPropsChanged.Length; b++) {
blockPropsChanged[b] = Block.Props[b];
blockPropsChanged[b].ChangedScope = 0;
BlockID block = (BlockID)b;
if (!BlockExists(block)) continue;
string name = Block.GetName(null, block);
blk_list.Items.Add(name);
blockIDMap.Add(block);
}
if (blk_list.SelectedIndex == -1)
if (blk_list.SelectedIndex == -1) {
blk_list.SelectedIndex = 0;
}
}
bool BlockExists(BlockID b) {
if (b < Block.Count) return !Block.Undefined(b);
BlockRaw raw = (BlockRaw)b;
return BlockDefinition.GlobalDefs[raw] != null;
}
void SaveBlocks() {
void SaveBlocks() {
if (!BlocksChanged()) { LoadBlocks(); return; }
for (int i = 0; i < blockPropsChanged.Length; i++) {
if (!blockPropsChanged[i].Changed) continue;
Block.Props[i] = blockPropsChanged[i];
for (int b = 0; b < blockPropsChanged.Length; b++) {
if (blockPropsChanged[b].ChangedScope == 0) continue;
Block.Props[b] = blockPropsChanged[b];
}
foreach (BlockPerms perms in blockPermsChanged) {
@ -63,28 +77,28 @@ namespace MCGalaxy.Gui {
}
BlockPerms.ResendAllBlockPermissions();
BlockProps.Save("core", Block.Props, Block.CorePropsLock, null);
BlockProps.Save("default", Block.Props, Block.PropsLock, 1);
BlockPerms.Save();
Block.SetBlocks();
LoadBlocks();
}
bool BlocksChanged() {
for (int i = 0; i < blockPropsChanged.Length; i++) {
if (blockPropsChanged[i].Changed) return true;
for (int b = 0; b < blockPropsChanged.Length; b++) {
if (blockPropsChanged[b].ChangedScope != 0) return true;
}
return blockPermsChanged.Count > 0;
}
void blk_list_SelectedIndexChanged(object sender, EventArgs e) {
blockID = Block.Byte(blk_list.SelectedItem.ToString());
blockPermsOrig = BlockPerms.List[blockID];
blockPerms = blockPermsChanged.Find(p => p.ID == blockID);
curBlock = blockIDMap[blk_list.SelectedIndex];
blockPermsOrig = BlockPerms.List[curBlock];
blockPerms = blockPermsChanged.Find(p => p.ID == curBlock);
BlockInitSpecificArrays();
blockSupressEvents = true;
BlockProps props = blockPropsChanged[blockID];
BlockProps props = blockPropsChanged[curBlock];
blk_cbMsgBlock.Checked = props.IsMessageBlock;
blk_cbPortal.Checked = props.IsPortal;
blk_cbDeath.Checked = props.KillerBlock;
@ -96,7 +110,7 @@ namespace MCGalaxy.Gui {
blk_cbRails.Checked = props.IsRails;
blk_cbLava.Checked = props.LavaKills;
blk_cbWater.Checked = props.WaterKills;
BlockPerms perms = blockPerms != null ? blockPerms : blockPermsOrig;
GuiPerms.SetDefaultIndex(blk_cmbMin, perms.MinRank);
GuiPerms.SetSpecificPerms(perms.Allowed, blockAllowBoxes);
@ -161,49 +175,55 @@ namespace MCGalaxy.Gui {
void blk_cbMsgBlock_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].IsMessageBlock = blk_cbMsgBlock.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].IsMessageBlock = blk_cbMsgBlock.Checked;
MarkBlockPropsChanged();
}
void blk_cbPortal_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].IsPortal = blk_cbPortal.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].IsPortal = blk_cbPortal.Checked;
MarkBlockPropsChanged();
}
void blk_cbDeath_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].KillerBlock = blk_cbDeath.Checked;
blockPropsChanged[curBlock].KillerBlock = blk_cbDeath.Checked;
blk_txtDeath.Enabled = blk_cbDeath.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
MarkBlockPropsChanged();
}
void blk_txtDeath_TextChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].DeathMessage = blk_txtDeath.Text;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].DeathMessage = blk_txtDeath.Text;
MarkBlockPropsChanged();
}
void blk_cbDoor_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].IsDoor = blk_cbDoor.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].IsDoor = blk_cbDoor.Checked;
MarkBlockPropsChanged();
}
void blk_cbTdoor_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].IsTDoor = blk_cbTdoor.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].IsTDoor = blk_cbTdoor.Checked;
MarkBlockPropsChanged();
}
void blk_cbRails_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].IsRails = blk_cbRails.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].IsRails = blk_cbRails.Checked;
MarkBlockPropsChanged();
}
void blk_cbLava_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].LavaKills = blk_cbLava.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].LavaKills = blk_cbLava.Checked;
MarkBlockPropsChanged();
}
void blk_cbWater_CheckedChanged(object sender, EventArgs e) {
blockPropsChanged[blockID].WaterKills = blk_cbWater.Checked;
blockPropsChanged[blockID].Changed = !blockSupressEvents;
blockPropsChanged[curBlock].WaterKills = blk_cbWater.Checked;
MarkBlockPropsChanged();
}
void MarkBlockPropsChanged() {
// don't mark props as changed when supressing events
int changed = blockSupressEvents ? 0 : 1;
blockPropsChanged[curBlock].ChangedScope = (byte)changed;
}
}
}

View File

@ -18,104 +18,118 @@
using System;
using System.Collections.Generic;
using MCGalaxy.Blocks;
using BlockID = System.UInt16;
namespace MCGalaxy {
public sealed partial class Block {
public static BlockProps[] Props = new BlockProps[Block.Count];
public static readonly object CorePropsLock = new object();
public static BlockProps[] Props = new BlockProps[Block.ExtendedCount];
public static readonly object PropsLock = new object();
public static Dictionary<string, byte> Aliases = new Dictionary<string, byte>();
static void SetCoreProperties() {
for (int i = 0; i < Block.Count; i++)
Props[i] = BlockProps.MakeDefault();
for (int i = 0; i < Block.Count; i++) {
if ((i >= Op_Glass && i <= Op_Lava) || i == Invalid || i == RocketStart || i == Bedrock) {
Props[i].OPBlock = true;
internal static void ChangeGlobalProps(BlockID block, BlockProps props) {
Level[] loaded = LevelInfo.Loaded.Items;
Block.Props[block] = props;
foreach (Level lvl in loaded) {
if (lvl.HasCustomProps(block)) continue;
lvl.Props[block] = props;
lvl.UpdateBlockHandler(block);
}
}
internal static void MakeDefaultProps(BlockProps[] props) {
for (int b = 0; b < props.Length; b++) {
props[b] = BlockProps.MakeDefault();
if ((b >= Op_Glass && b <= Op_Lava) || b == Invalid || b == RocketStart || b == Bedrock) {
props[b].OPBlock = true;
}
if ((i >= tDoor_Log && i <= tDoor_Green) || (i >= tDoor_TNT && i <= tDoor_Lava)) {
Props[i].IsTDoor = true;
if ((b >= tDoor_Log && b <= tDoor_Green) || (b >= tDoor_TNT && b <= tDoor_Lava)) {
props[b].IsTDoor = true;
}
if (i >= MB_White && i <= MB_Lava) {
Props[i].IsMessageBlock = true;
if (b >= MB_White && b <= MB_Lava) {
props[b].IsMessageBlock = true;
}
if (i == Portal_Blue || i == Portal_Orange || (i >= Portal_Air && i <= Portal_Lava)) {
Props[i].IsPortal = true;
if (b == Portal_Blue || b == Portal_Orange || (b >= Portal_Air && b <= Portal_Lava)) {
props[b].IsPortal = true;
}
// oDoor blocks
if (i >= oDoor_Log && i <= oDoor_Wood) {
Props[i].oDoorBlock = (ushort)(oDoor_Log_air + (i - oDoor_Log));
if (b >= oDoor_Log && b <= oDoor_Wood) {
props[b].oDoorBlock = (ushort)(oDoor_Log_air + (b - oDoor_Log));
}
if (i >= oDoor_Green && i <= oDoor_Water) {
Props[i].oDoorBlock = (ushort)(oDoor_Green_air + (i - oDoor_Green));
if (b >= oDoor_Green && b <= oDoor_Water) {
props[b].oDoorBlock = (ushort)(oDoor_Green_air + (b - oDoor_Green));
}
if (i >= oDoor_Log_air && i <= oDoor_Wood_air) {
Props[i].oDoorBlock = (ushort)(oDoor_Log + (i - oDoor_Log_air));
if (b >= oDoor_Log_air && b <= oDoor_Wood_air) {
props[b].oDoorBlock = (ushort)(oDoor_Log + (b - oDoor_Log_air));
}
if (i >= oDoor_Green_air && i <= oDoor_Water_air) {
Props[i].oDoorBlock = (ushort)(oDoor_Green + (i - oDoor_Green_air));
if (b >= oDoor_Green_air && b <= oDoor_Water_air) {
props[b].oDoorBlock = (ushort)(oDoor_Green + (b - oDoor_Green_air));
}
if ((i >= Red && i <= White) || (i >= LightPink && i <= turquoise)) {
Props[i].LavaKills = true;
if ((b >= Red && b <= White) || (b >= LightPink && b <= turquoise)) {
props[b].LavaKills = true;
}
if (i == Air || i == Sapling || (i >= Dandelion && i <= RedMushroom)) {
Props[i].LavaKills = true;
Props[i].WaterKills = true;
if (b == Air || b == Sapling || (b >= Dandelion && b <= RedMushroom)) {
props[b].LavaKills = true;
props[b].WaterKills = true;
}
// Door blocks
if (i >= Door_Obsidian && i <= Door_Slab) Props[i].IsDoor = true;
if (i >= Door_Iron && i <= Door_Bookshelf) Props[i].IsDoor = true;
if (i >= Door_Orange && i <= Door_White) Props[i].IsDoor = true;
if (b >= Door_Obsidian && b <= Door_Slab) props[b].IsDoor = true;
if (b >= Door_Iron && b <= Door_Bookshelf) props[b].IsDoor = true;
if (b >= Door_Orange && b <= Door_White) props[b].IsDoor = true;
}
// Other door blocks, since they aren't in a consistent order
Props[Door_Log].IsDoor = true;
Props[Door_Red].IsDoor = true;
Props[Door_Cobblestone].IsDoor = true;
Props[Door_Gold].IsDoor = true;
Props[Door_Air].IsDoor = true;
Props[Door_AirActivatable].IsDoor = true;
Props[Door_Water].IsDoor = true;
Props[Door_Lava].IsDoor = true;
props[Door_Log].IsDoor = true;
props[Door_Red].IsDoor = true;
props[Door_Cobblestone].IsDoor = true;
props[Door_Gold].IsDoor = true;
props[Door_Air].IsDoor = true;
props[Door_AirActivatable].IsDoor = true;
props[Door_Water].IsDoor = true;
props[Door_Lava].IsDoor = true;
// Block specific properties
Props[Wood].LavaKills = true; Props[Log].LavaKills = true;
Props[Sponge].LavaKills = true; Props[Bookshelf].LavaKills = true;
Props[Leaves].LavaKills = true; Props[Crate].LavaKills = true;
Props[Red].IsRails = true; Props[Op_Air].IsRails = true;
Props[Slab].StackBlock = DoubleSlab;
Props[CobblestoneSlab].StackBlock = Cobblestone;
Props[Water].Drownable = true; Props[StillWater].Drownable = true;
Props[Lava].Drownable = true; Props[StillLava].Drownable = true;
Props[Dirt].GrassBlock = Block.Grass; Props[Grass].DirtBlock = Block.Dirt;
props[Wood].LavaKills = true; props[Log].LavaKills = true;
props[Sponge].LavaKills = true; props[Bookshelf].LavaKills = true;
props[Leaves].LavaKills = true; props[Crate].LavaKills = true;
props[Red].IsRails = true; props[Op_Air].IsRails = true;
props[Slab].StackBlock = DoubleSlab;
props[CobblestoneSlab].StackBlock = Cobblestone;
props[Water].Drownable = true; props[StillWater].Drownable = true;
props[Lava].Drownable = true; props[StillLava].Drownable = true;
props[Dirt].GrassBlock = Block.Grass; props[Grass].DirtBlock = Block.Dirt;
// Block specific physics properties
Props[Block.Bird_Black].AnimalAI = AnimalAI.Fly;
Props[Block.Bird_White].AnimalAI = AnimalAI.Fly;
Props[Block.Bird_Lava].AnimalAI = AnimalAI.Fly;
Props[Block.Bird_Water].AnimalAI = AnimalAI.Fly;
props[Block.Bird_Black].AnimalAI = AnimalAI.Fly;
props[Block.Bird_White].AnimalAI = AnimalAI.Fly;
props[Block.Bird_Lava].AnimalAI = AnimalAI.Fly;
props[Block.Bird_Water].AnimalAI = AnimalAI.Fly;
Props[Block.Bird_Red].AnimalAI = AnimalAI.KillerAir;
Props[Block.Bird_Blue].AnimalAI = AnimalAI.KillerAir;
Props[Block.Bird_Killer].AnimalAI = AnimalAI.KillerAir;
props[Block.Bird_Red].AnimalAI = AnimalAI.KillerAir;
props[Block.Bird_Blue].AnimalAI = AnimalAI.KillerAir;
props[Block.Bird_Killer].AnimalAI = AnimalAI.KillerAir;
Props[Block.Fish_Betta].AnimalAI = AnimalAI.KillerWater;
Props[Block.Fish_Shark].AnimalAI = AnimalAI.KillerWater;
Props[Block.Fish_LavaShark].AnimalAI = AnimalAI.KillerLava;
Props[Block.Fish_Gold].AnimalAI = AnimalAI.FleeWater;
Props[Block.Fish_Salmon].AnimalAI = AnimalAI.FleeWater;
Props[Block.Fish_Sponge].AnimalAI = AnimalAI.FleeWater;
props[Block.Fish_Betta].AnimalAI = AnimalAI.KillerWater;
props[Block.Fish_Shark].AnimalAI = AnimalAI.KillerWater;
props[Block.Fish_LavaShark].AnimalAI = AnimalAI.KillerLava;
props[Block.Fish_Gold].AnimalAI = AnimalAI.FleeWater;
props[Block.Fish_Salmon].AnimalAI = AnimalAI.FleeWater;
props[Block.Fish_Sponge].AnimalAI = AnimalAI.FleeWater;
}
static void SetCoreProperties() {
MakeDefaultProps(Props);
SetDefaultNames();
SetDefaultDeaths();
}
internal static void SetDefaultNames() {
string[] names = new string[] { "Air", "Stone", "Grass", "Dirt", "Cobblestone",
"Wood", "Sapling", "Bedrock", "Active_Water", "Water", "Active_Lava", "Lava",

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses.
*/
using System;
using System.IO;
using MCGalaxy.Blocks;
using MCGalaxy.Maths;
using BlockID = System.UInt16;
@ -151,15 +152,23 @@ namespace MCGalaxy {
def.MaxX * 2, def.MaxZ * 2, def.MaxY * 2);
}
if (block >= Block.Extended) return new AABB(0, 0, 0, 32, 32, 32);
if (block >= Block.Extended) return new AABB(0, 0, 0, 32, 32, 32);
BlockID core = Convert(block);
return new AABB(0, 0, 0, 32, DefaultSet.Height(core) * 2, 32);
}
}
public static void SetBlocks() {
SetCoreProperties();
BlockProps.Load("core", Props, CorePropsLock, false);
BlockDefinition.UpdateGlobalBlockProps();
string propsPath = BlockProps.PropsPath("default");
// backwards compatibility with older versions
if (!File.Exists(propsPath)) {
BlockProps.Load("core", Props, PropsLock, 1, false);
BlockProps.Load("global", Props, PropsLock, 1, true);
} else {
BlockProps.Load("default", Props, PropsLock, 1, false);
}
BlockPerms.Load();
UpdateLoadedLevels();
}
@ -169,7 +178,7 @@ namespace MCGalaxy {
foreach (Level lvl in loaded) {
lvl.UpdateBlockProps();
lvl.UpdateBlockHandlers();
}
}
}
public static BlockID FromRaw(byte raw) {
@ -181,6 +190,7 @@ namespace MCGalaxy {
}
public static BlockID MapOldRaw(BlockID raw) {
// old raw form was: 0 - 65 core block ids, 66 - 255 custom block ids
return IsPhysicsType(raw) ? ((BlockID)(Block.Extended | raw)) : raw;
}

View File

@ -50,7 +50,6 @@ namespace MCGalaxy {
public const string GlobalPath = "blockdefs/global.json", GlobalBackupPath = "blockdefs/global.json.bak";
public static BlockDefinition[] GlobalDefs;
public static BlockProps[] GlobalProps = new BlockProps[Block.Count];
internal static readonly object GlobalPropsLock = new object();
public BlockDefinition Copy() {
@ -145,26 +144,6 @@ namespace MCGalaxy {
if (oldDefs != null) UpdateLoadedLevels(oldDefs);
}
public static void UpdateGlobalBlockProps() {
for (int i = 0; i < GlobalProps.Length; i++) {
BlockID_ block = Block.FromRaw((byte)i);
GlobalProps[i] = BlockProps.MakeDefault();
GlobalProps[i] = DefaultProps(block);
}
BlockProps.Load("global", GlobalProps, GlobalPropsLock, false);
}
internal static BlockProps DefaultProps(BlockID_ block) {
BlockRaw raw = (BlockRaw)block;
if (Block.IsPhysicsType(block)) {
return Block.Props[block];
} else if (block < Block.Extended && GlobalDefs[raw] == null) {
return Block.Props[raw];
} else {
return GlobalProps[raw];
}
}
static void UpdateLoadedLevels(BlockDefinition[] oldGlobalDefs) {
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
@ -172,7 +151,7 @@ namespace MCGalaxy {
if (lvl.CustomBlockDefs[i] != oldGlobalDefs[i]) continue;
BlockID_ block = Block.FromRaw((byte)i);
lvl.Props[block] = DefaultProps(block);
lvl.Props[block] = Block.Props[block];
lvl.UpdateCustomBlock((BlockRaw)block, GlobalDefs[i]);
}
}

View File

@ -163,13 +163,12 @@ namespace MCGalaxy.Blocks {
}
static void SetDefaultPerms() {
BlockProps defProps = BlockProps.MakeDefault();
for (int i = 0; i < Block.ExtendedCount; i++) {
for (BlockID block = 0; block < Block.ExtendedCount; block++) {
BlockPerms perms = new BlockPerms();
perms.ID = (BlockID)i;
BlockProps props = i < Block.Count ? Block.Props[i] : defProps;
perms.ID = block;
BlockProps props = Block.Props[block];
if (i == Block.Invalid) {
if (block == Block.Invalid) {
perms.MinRank = LevelPermission.Admin;
} else if (props.OPBlock) {
perms.MinRank = LevelPermission.Operator;
@ -178,9 +177,9 @@ namespace MCGalaxy.Blocks {
} else if (props.IsPortal || props.IsMessageBlock) {
perms.MinRank = LevelPermission.AdvBuilder;
} else {
perms.MinRank = DefaultPerm(i);
perms.MinRank = DefaultPerm(block);
}
List[i] = perms;
List[block] = perms;
}
}

View File

@ -75,7 +75,7 @@ namespace MCGalaxy.Blocks {
public BlockID DirtBlock;
/// <summary> Whether the properties for this block have been modified and hence require saving. </summary>
public bool Changed;
public byte ChangedScope;
public static BlockProps MakeDefault() {
BlockProps props = default(BlockProps);
@ -86,29 +86,27 @@ namespace MCGalaxy.Blocks {
}
public static void Save(string group, BlockProps[] scope, object locker, Predicate<int> selector) {
public static void Save(string group, BlockProps[] list, object locker, byte scope) {
lock (locker) {
if (!Directory.Exists("blockprops"))
Directory.CreateDirectory("blockprops");
SaveCore(group, scope, selector);
SaveCore(group, list, scope);
}
}
static void SaveCore(string group, BlockProps[] scope, Predicate<int> selector) {
static void SaveCore(string group, BlockProps[] list, byte scope) {
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 : " +
"Animal AI type : Stack block : Is OP block : oDoor block : Drownable : " +
"Grass block : Dirt block");
for (int i = 0; i < scope.Length; i++) {
if (!scope[i].Changed || (selector != null && !selector(i))) continue;
BlockProps props = scope[i];
// Convert ext to raw ids
int id = i >= Block.Count ? (i - Block.Count) : i;
for (int b = 0; b < list.Length; b++) {
if ((list[b].ChangedScope & scope) == 0) continue;
BlockProps props = list[b];
string deathMsg = props.DeathMessage == null ? "" : props.DeathMessage.Replace(":", "\\;");
w.WriteLine(id + ":" + props.IsRails + ":" + props.IsTDoor + ":" + props.IsDoor + ":"
w.WriteLine(b + ":" + props.IsRails + ":" + props.IsTDoor + ":" + props.IsDoor + ":"
+ props.IsMessageBlock + ":" + props.IsPortal + ":" + props.WaterKills + ":"
+ props.LavaKills + ":" + props.KillerBlock + ":" + deathMsg + ":"
+ (byte)props.AnimalAI + ":" + props.StackBlock + ":" + props.OPBlock + ":"
@ -118,71 +116,71 @@ namespace MCGalaxy.Blocks {
}
}
public static void Load(string group, BlockProps[] scope, object locker, bool lbScope) {
public static string PropsPath(string group) { return "blockprops/" + group + ".txt"; }
public static void Load(string group, BlockProps[] list, object locker, byte scope, bool mapOld) {
lock (locker) {
if (!Directory.Exists("blockprops")) return;
if (!File.Exists("blockprops/" + group + ".txt")) return;
LoadCore(group, scope, lbScope);
string path = PropsPath(group);
if (File.Exists(path)) LoadCore(path, list, scope, mapOld);
}
}
static void LoadCore(string group, BlockProps[] scope, bool lbScope) {
string[] lines = File.ReadAllLines("blockprops/" + group + ".txt");
static void LoadCore(string path, BlockProps[] list, byte scope, bool mapOld) {
string[] lines = File.ReadAllLines(path);
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) {
Logger.Log(LogType.Warning, "Invalid line \"{0}\" in {1} block properties", line, group);
Logger.Log(LogType.Warning, "Invalid line \"{0}\" in {1}", line, path);
continue;
}
// TODO fix fix fix
byte raw;
if (!Byte.TryParse(parts[0], out raw)) {
Logger.Log(LogType.Warning, "Invalid line \"{0}\" in {1} block properties", line, group);
BlockID b;
if (!BlockID.TryParse(parts[0], out b)) {
Logger.Log(LogType.Warning, "Invalid line \"{0}\" in {1}", line, path);
continue;
}
int idx = raw;
if (lbScope && raw >= Block.CpeCount) idx += Block.Count;
if (mapOld) b = Block.MapOldRaw(b);
bool.TryParse(parts[1], out scope[idx].IsRails);
bool.TryParse(parts[2], out scope[idx].IsTDoor);
bool.TryParse(parts[3], out scope[idx].IsDoor);
bool.TryParse(parts[4], out scope[idx].IsMessageBlock);
bool.TryParse(parts[5], out scope[idx].IsPortal);
bool.TryParse(parts[6], out scope[idx].WaterKills);
bool.TryParse(parts[7], out scope[idx].LavaKills);
bool.TryParse(parts[8], out scope[idx].KillerBlock);
bool.TryParse(parts[1], out list[b].IsRails);
bool.TryParse(parts[2], out list[b].IsTDoor);
bool.TryParse(parts[3], out list[b].IsDoor);
bool.TryParse(parts[4], out list[b].IsMessageBlock);
bool.TryParse(parts[5], out list[b].IsPortal);
bool.TryParse(parts[6], out list[b].WaterKills);
bool.TryParse(parts[7], out list[b].LavaKills);
bool.TryParse(parts[8], out list[b].KillerBlock);
scope[idx].Changed = true;
scope[idx].DeathMessage = parts[9].Replace("\\;", ":");
if (scope[idx].DeathMessage.Length == 0)
scope[idx].DeathMessage = null;
list[b].ChangedScope = scope;
list[b].DeathMessage = parts[9].Replace("\\;", ":");
if (list[b].DeathMessage.Length == 0)
list[b].DeathMessage = null;
if (parts.Length > 10) {
byte ai; byte.TryParse(parts[10], out ai);
scope[idx].AnimalAI = (AnimalAI)ai;
list[b].AnimalAI = (AnimalAI)ai;
}
if (parts.Length > 11) {
BlockID.TryParse(parts[11], out scope[idx].StackBlock);
scope[idx].StackBlock = Block.MapOldRaw(scope[idx].StackBlock);
BlockID.TryParse(parts[11], out list[b].StackBlock);
list[b].StackBlock = Block.MapOldRaw(list[b].StackBlock);
}
if (parts.Length > 12) {
bool.TryParse(parts[12], out scope[idx].OPBlock);
bool.TryParse(parts[12], out list[b].OPBlock);
}
if (parts.Length > 13) {
BlockID.TryParse(parts[13], out scope[idx].oDoorBlock);
BlockID.TryParse(parts[13], out list[b].oDoorBlock);
}
if (parts.Length > 14) {
bool.TryParse(parts[14], out scope[idx].Drownable);
bool.TryParse(parts[14], out list[b].Drownable);
}
if (parts.Length > 15) {
BlockID.TryParse(parts[15], out scope[idx].GrassBlock);
BlockID.TryParse(parts[15], out list[b].GrassBlock);
}
if (parts.Length > 16) {
BlockID.TryParse(parts[16], out scope[idx].DirtBlock);
BlockID.TryParse(parts[16], out list[b].DirtBlock);
}
}
}

View File

@ -119,7 +119,7 @@ namespace MCGalaxy.Commands.CPE {
if (srcDef == null) { MessageNoBlock(p, src, global, cmd); return; }
if (ExistsInScope(dstDef, dst, global)) { MessageAlreadyBlock(p, dst, global, cmd); return; }
BlockProps props = global ? BlockDefinition.GlobalProps[srcRaw] : p.level.Props[src];
BlockProps props = global ? Block.Props[src] : p.level.Props[src];
dstDef = srcDef.Copy();
dstDef.BlockID = dstRaw;
dstDef.InventoryOrder = -1;
@ -287,8 +287,7 @@ namespace MCGalaxy.Commands.CPE {
bd.FallBack = fallback;
BlockID block = Block.FromRaw(bd.BlockID);
BlockProps props = BlockDefinition.DefaultProps(block);
if (!AddBlock(p, bd, global, cmd, props)) return;
if (!AddBlock(p, bd, global, cmd, Block.Props[block])) return;
SetBD(p, global, null);
SetStep(p, global, 0);
@ -314,17 +313,17 @@ namespace MCGalaxy.Commands.CPE {
BlockID block;
if (!CheckBlock(p, parts[1], out block)) return;
BlockRaw raw = (BlockRaw)block;
BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : p.level.CustomBlockDefs;
BlockDefinition def = defs[raw], globalDef = BlockDefinition.GlobalDefs[raw];
if (def == null && block < Block.CpeCount) {
def = DefaultSet.MakeCustomBlock(block);
AddBlock(p, def, global, cmd, BlockDefinition.DefaultProps(block));
AddBlock(p, def, global, cmd, Block.Props[block]);
}
if (def != null && !global && def == globalDef) {
def = globalDef.Copy();
AddBlock(p, def, global, cmd, BlockDefinition.DefaultProps(block));
AddBlock(p, def, global, cmd, Block.Props[block]);
}
if (!ExistsInScope(def, block, global)) { MessageNoBlock(p, block, global, cmd); return; }
@ -432,7 +431,7 @@ namespace MCGalaxy.Commands.CPE {
def.InventoryOrder = order == def.BlockID ? -1 : order;
BlockDefinition.UpdateOrder(def, global, level);
BlockDefinition.Save(global, level);
Player.Message(p, "Set inventory order for {0} to {1}", blockName,
Player.Message(p, "Set inventory order for {0} to {1}", blockName,
order == def.BlockID ? "default" : order.ToString());
return;
default:
@ -557,39 +556,19 @@ namespace MCGalaxy.Commands.CPE {
if (!global) {
p.level.Props[block] = props;
p.level.UpdateBlockHandler(block);
return;
}
BlockRaw raw = (BlockRaw)block;
BlockDefinition.GlobalProps[raw] = props;
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw]) continue;
lvl.Props[block] = props;
lvl.UpdateBlockHandler(block);
} else {
Block.ChangeGlobalProps(block, props);
}
}
static void RemoveBlockProps(bool global, BlockID block, Player p) {
// Level block reverts to using global block
if (!global) {
p.level.Props[block] = BlockDefinition.DefaultProps(block);
p.level.Props[block] = Block.Props[block];
p.level.UpdateBlockHandler(block);
return;
}
BlockProps props = BlockProps.MakeDefault();
if (block < Block.Extended) props = Block.Props[block];
BlockRaw raw = (BlockRaw)block;
BlockDefinition.GlobalProps[raw] = props;
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw]) continue;
lvl.Props[block] = BlockDefinition.GlobalProps[raw];
lvl.UpdateBlockHandler(block);
} else {
BlockProps[] defProps = new BlockProps[Block.ExtendedCount];
Block.MakeDefaultProps(defProps);
Block.ChangeGlobalProps(block, defProps[block]);
}
}
@ -724,7 +703,7 @@ namespace MCGalaxy.Commands.CPE {
}
internal static void Help(Player p, string cmd, string args) {
if (!args.CaselessStarts("edit ")) { Help(p, cmd); return; }
if (!args.CaselessStarts("edit ")) { Help(p, cmd); return; }
string prop = args.Substring(args.IndexOf(' ') + 1);
prop = MapPropertyName(prop.ToLower());

View File

@ -34,17 +34,20 @@ namespace MCGalaxy.Commands.World {
BlockProps[] scope = GetScope(p, args[0]);
if (scope == null) return;
BlockID block = GetBlock(p, scope, args[1]);
if (block == Block.Invalid) return;
Player pScope = scope == Block.Props ? null : p;
BlockID block = CommandParser.RawGetBlock(pScope, args[1]);
if (block == Block.Invalid) {
Player.Message(p, "&cThere is no block \"{0}\".", args[1]); return;
}
string prop = args[2].ToLower();
SetProperty(p, scope, block, prop, args);
}
static BlockProps[] GetScope(Player p, string scope) {
if (scope.CaselessEq("core")) return Block.Props;
if (scope.CaselessEq("global")) return BlockDefinition.GlobalProps;
if (scope.CaselessEq("core") || scope.CaselessEq("global")) return Block.Props;
if (scope.CaselessEq("level")) {
if (Player.IsSuper(p)) {
string src = p == null ? "console" : "IRC";
@ -56,84 +59,47 @@ namespace MCGalaxy.Commands.World {
return p.level.Props;
}
Player.Message(p, "&cScope must \"core\", \"global\", or \"level\"");
Player.Message(p, "&cScope must be: core/global, or level");
return null;
}
static BlockID GetBlock(Player p, BlockProps[] scope, string input) {
if (scope == Block.Props) {
byte raw;
if (!byte.TryParse(input, out raw))
raw = Block.Byte(input);
if (Block.Undefined(raw)) {
Player.Message(p, "&cThere is no block with id or name \"{0}\"", input);
return Block.Invalid;
}
return raw;
} else if (scope == BlockDefinition.GlobalProps) {
int raw = BlockDefinition.GetBlock(input, BlockDefinition.GlobalDefs);
if (raw == -1) {
Player.Message(p, "&cThere is no global custom block with id or name \"{0}\"", input);
return Block.Invalid;
}
return Block.FromRaw((byte)raw);
} else {
int raw = BlockDefinition.GetBlock(input, p.level.CustomBlockDefs);
if (raw == -1) {
Player.Message(p, "&cThere is no level custom block with id or name \"{0}\"", input);
return Block.Invalid;
}
if (p.level.CustomBlockDefs[raw] == BlockDefinition.GlobalDefs[raw]) {
Player.Message(p, "&cUse %T/BlockProps global &cto modify this custom block."); return Block.Invalid;
}
return Block.FromRaw((byte)raw);
}
}
static int GetIndex(BlockProps[] scope, BlockID block) {
return scope == BlockDefinition.GlobalProps ? (BlockRaw)block : block;
}
void SetProperty(Player p, BlockProps[] scope, BlockID block,
string prop, string[] args) {
int i = GetIndex(scope, block);
string text = args.Length > 3 ? args[3] : null;
if (prop == "portal") {
Toggle(p, scope, block, "a portal", ref scope[i].IsPortal);
Toggle(p, scope, block, "a portal", ref scope[block].IsPortal);
} else if (prop == "mb" || prop == "messageblock") {
Toggle(p, scope, block, "a message block", ref scope[i].IsMessageBlock);
Toggle(p, scope, block, "a message block", ref scope[block].IsMessageBlock);
} else if (prop == "rails") {
Toggle(p, scope, block, "train rails", ref scope[i].IsRails);
Toggle(p, scope, block, "train rails", ref scope[block].IsRails);
} else if (prop == "waterkills") {
Toggle(p, scope, block, "killed by water", ref scope[i].WaterKills);
Toggle(p, scope, block, "killed by water", ref scope[block].WaterKills);
} else if (prop == "lavakills") {
Toggle(p, scope, block, "killed by lava", ref scope[i].LavaKills);
Toggle(p, scope, block, "killed by lava", ref scope[block].LavaKills);
} else if (prop == "door") {
Toggle(p, scope, block, "a door", ref scope[i].IsDoor);
Toggle(p, scope, block, "a door", ref scope[block].IsDoor);
} else if (prop == "tdoor") {
Toggle(p, scope, block, "a tdoor", ref scope[i].IsTDoor);
Toggle(p, scope, block, "a tdoor", ref scope[block].IsTDoor);
} else if (prop == "killer" || prop == "death") {
Toggle(p, scope, block, "a killer block", ref scope[i].KillerBlock);
Toggle(p, scope, block, "a killer block", ref scope[block].KillerBlock);
} else if (prop == "deathmsg" || prop == "deathmessage") {
SetDeathMessage(p, scope, block, i, text);
SetDeathMessage(p, scope, block, text);
} else if (prop == "animalai" || prop == "animal") {
SetEnum(p, scope, block, i, text);
SetEnum(p, scope, block, text);
} else if (prop == "stackid" || prop == "stackblock") {
SetStackId(p, scope, block, i, text);
SetStackId(p, scope, block, text);
} else if (prop == "opblock" || prop == "op") {
Toggle(p, scope, block, "an OP block", ref scope[i].OPBlock);
Toggle(p, scope, block, "an OP block", ref scope[block].OPBlock);
} else if (prop == "odoor") {
SetBlock(p, scope, block, i, text, ref scope[i].oDoorBlock, "oDoor");
SetBlock(p, scope, block, text, ref scope[block].oDoorBlock, "oDoor");
} else if (prop == "grass") {
SetBlock(p, scope, block, i, text, ref scope[i].GrassBlock, "Grass form");
SetBlock(p, scope, block, text, ref scope[block].GrassBlock, "Grass form");
} else if (prop == "dirt") {
SetBlock(p, scope, block, i, text, ref scope[i].DirtBlock, "Dirt form");
SetBlock(p, scope, block, text, ref scope[block].DirtBlock, "Dirt form");
} else if (prop == "drownable" || prop == "drown") {
Toggle(p, scope, block, "drowns players", ref scope[i].Drownable);
Toggle(p, scope, block, "drowns players", ref scope[block].Drownable);
} else {
Help(p);
}
@ -142,122 +108,84 @@ namespace MCGalaxy.Commands.World {
static void Toggle(Player p, BlockProps[] scope, BlockID block, string type, ref bool on) {
on = !on;
Level lvl = Player.IsSuper(p) ? null : p.level;
Player.Message(p, "Block {0} is {1}: {2}",
BlockName(scope, lvl, block), type, on ? "&aYes" : "&cNo");
OnPropsChanged(scope, lvl, block);
string blockName = BlockName(scope, p, block);
Player.Message(p, "Block {0} is {1}: {2}", blockName, type, on ? "&aYes" : "&cNo");
OnPropsChanged(scope, p, block);
}
static void SetEnum(Player p, BlockProps[] scope, BlockID block, int i, string msg) {
Level lvl = Player.IsSuper(p) ? null : p.level;
static void SetEnum(Player p, BlockProps[] scope, BlockID block, string msg) {
AnimalAI ai = AnimalAI.None;
if (!CommandParser.GetEnum(p, msg, "Animal AI", ref ai)) return;
scope[block].AnimalAI = ai;
scope[i].AnimalAI = ai;
Player.Message(p, "Animal AI for {0} set to: {1}",
BlockName(scope, lvl, block), ai);
OnPropsChanged(scope, lvl, block);
string blockName = BlockName(scope, p, block);
Player.Message(p, "Animal AI for {0} set to: {1}", blockName, ai);
OnPropsChanged(scope, p, block);
}
static void SetDeathMessage(Player p, BlockProps[] scope, BlockID block, int i, string msg) {
scope[i].DeathMessage = msg;
Level lvl = Player.IsSuper(p) ? null : p.level;
static void SetDeathMessage(Player p, BlockProps[] scope, BlockID block, string msg) {
scope[block].DeathMessage = msg;
string blockName = BlockName(scope, p, block);
if (msg == null) {
Player.Message(p, "Death message for {0} removed.",
BlockName(scope, lvl, block));
Player.Message(p, "Death message for {0} removed.", blockName);
} else {
Player.Message(p, "Death message for {0} set to: {1}",
BlockName(scope, lvl, block), msg);
Player.Message(p, "Death message for {0} set to: {1}", blockName, msg);
}
OnPropsChanged(scope, lvl, block);
OnPropsChanged(scope, p, block);
}
static void SetStackId(Player p, BlockProps[] scope, BlockID block, int i, string msg) {
Level lvl = Player.IsSuper(p) ? null : p.level;
static void SetStackId(Player p, BlockProps[] scope, BlockID block, string msg) {
BlockID stackBlock;
if (msg == null) {
stackBlock = Block.Air;
} else {
if (!CommandParser.GetBlock(p, msg, out stackBlock)) return;
}
scope[i].StackBlock = stackBlock;
scope[block].StackBlock = stackBlock;
string blockName = BlockName(scope, p, block);
if (stackBlock == Block.Air) {
Player.Message(p, "Removed stack block for {0}", BlockName(scope, lvl, block));
Player.Message(p, "Removed stack block for {0}", blockName);
} else {
Player.Message(p, "Stack block for {0} set to: {1}",
BlockName(scope, lvl, block), Block.GetName(p, stackBlock));
blockName, BlockName(scope, p, stackBlock));
}
OnPropsChanged(scope, lvl, block);
OnPropsChanged(scope, p, block);
}
static void SetBlock(Player p, BlockProps[] scope, BlockID block,
int i, string msg, ref BlockID target, string type) {
Level lvl = Player.IsSuper(p) ? null : p.level;
static void SetBlock(Player p, BlockProps[] scope, BlockID block,
string msg, ref BlockID target, string type) {
string blockName = BlockName(scope, p, block);
if (msg == null) {
target = Block.Invalid;
Player.Message(p, "{1} for {0} removed.", BlockName(scope, lvl, block), type);
Player.Message(p, "{1} for {0} removed.", blockName, type);
} else {
BlockID other;
if (!CommandParser.GetBlock(p, msg, out other)) return;
if (other == block) { Player.Message(p, "ID of {0} must be different.", type); return; }
target = other;
Player.Message(p, "{2} for {0} set to: {1}", BlockName(scope, lvl, block),
BlockName(scope, lvl, other), type);
target = other;
Player.Message(p, "{2} for {0} set to: {1}", blockName, BlockName(scope, p, other), type);
}
OnPropsChanged(scope, lvl, block);
}
OnPropsChanged(scope, p, block);
}
static void OnPropsChanged(BlockProps[] scope, Level level, BlockID block) {
scope[GetIndex(scope, block)].Changed = true;
BlockRaw raw = (BlockRaw)block;
static void OnPropsChanged(BlockProps[] scope, Player p, BlockID block) {
if (scope == Block.Props) {
BlockProps.Save("core", scope, Block.CorePropsLock, null);
Level[] loaded = LevelInfo.Loaded.Items;
if (!Block.IsPhysicsType(block)) {
BlockDefinition.GlobalProps[raw] = BlockDefinition.DefaultProps(block);
}
foreach (Level lvl in loaded) {
if (lvl.HasCustomProps(block)) continue;
lvl.Props[block] = BlockDefinition.DefaultProps(block);
lvl.UpdateBlockHandler(block);
}
} else if (scope == BlockDefinition.GlobalProps) {
Level[] loaded = LevelInfo.Loaded.Items;
BlockProps.Save("global", scope, BlockDefinition.GlobalPropsLock, null);
foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw]) continue;
if (lvl.HasCustomProps(block)) continue;
lvl.Props[block] = BlockDefinition.DefaultProps(block);
lvl.UpdateBlockHandler(block);
}
scope[block].ChangedScope |= 1;
BlockProps.Save("default", Block.Props, Block.PropsLock, 1);
Block.ChangeGlobalProps(block, scope[block]);
} else {
BlockProps.Save("lvl_" + level.name, scope, level.PropsLock, idx => SelectLevel(level, idx));
level.UpdateBlockHandler(block);
scope[block].ChangedScope |= 2;
BlockProps.Save("_" + p.level.name, scope, p.level.PropsLock, 2);
p.level.UpdateBlockHandler(block);
}
}
static bool SelectLevel(Level lvl, int i) { return lvl.HasCustomProps((BlockID)i); }
static string BlockName(BlockProps[] scope, Level lvl, BlockID block) {
BlockRaw raw = (BlockRaw)block;
if (scope == Block.Props) return Block.coreNames[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(" ", "");
static string BlockName(BlockProps[] scope, Player p, BlockID block) {
return scope == Block.Props ? Block.GetName(null, block) : Block.GetName(p, block);
}

View File

@ -225,7 +225,7 @@ namespace MCGalaxy.Commands.World {
if (name.Length == 0) { Player.Message(p, "You need to provide a player name."); return; }
AddBuildPlayer(p, name);
} else if (cmd == "DEL") {
if (name.Length == 0) { Player.Message(p, "You need to provide a player name, or \"ALL\"."); return; }
if (name.Length == 0) { Player.Message(p, "You need to provide a player name."); return; }
DeleteBuildPlayer(p, name);
} else if (cmd == "BLOCK") {
if (name.Length == 0) { Player.Message(p, "You need to provide a player name."); return; }

View File

@ -192,28 +192,21 @@ namespace MCGalaxy.Commands.Building {
return Block.GetName(p, block);
}
static void AllNames(Player p, List<string> names) {
for (int i = 0; i < Block.ExtendedCount; i++) {
string name = Format((BlockID)i, p, p.level.Props);
if (name != null) names.Add(name);
}
}
static void CoreNames(List<string> names) {
for (int i = 0; i < Block.Count; i++) {
string name = Format((BlockID)i, null, Block.Props);
static List<string> SupportedBlocks(Player p) {
List<string> names = new List<string>();
BlockProps[] props = Player.IsSuper(p) ? Block.Props : p.level.Props;
for (int i = 0; i < props.Length; i++) {
string name = Format((BlockID)i, p, props);
if (name != null) names.Add(name);
}
return names;
}
public override void Help(Player p) {
Player.Message(p, "%T/MB [block] [message]");
Player.Message(p, "%HPlaces a message in your next block.");
List<string> names = new List<string>();
if (Player.IsSuper(p)) CoreNames(names);
else AllNames(p, names);
List<string> names = SupportedBlocks(p);
Player.Message(p, "%H Supported blocks: %S{0}", names.Join());
Player.Message(p, "%H Use | to separate commands, e.g. /say 1 |/say 2");
Player.Message(p, "%H Note: \"@p\" is a placeholder for player who clicked.");

View File

@ -195,18 +195,15 @@ namespace MCGalaxy.Commands.Building {
return Block.GetName(p, block);
}
static void AllNames(Player p, List<string> names) {
for (int i = 0; i < Block.ExtendedCount; i++) {
string name = Format((ushort)i, p, p.level.Props);
if (name != null) names.Add(name);
}
}
static void CoreNames(List<string> names) {
for (int i = 0; i < Block.Count; i++) {
string name = Format((ushort)i, null, Block.Props);
static List<string> SupportedBlocks(Player p) {
List<string> names = new List<string>();
BlockProps[] props = Player.IsSuper(p) ? Block.Props : p.level.Props;
for (int i = 0; i < props.Length; i++) {
string name = Format((BlockID)i, p, props);
if (name != null) names.Add(name);
}
return names;
}
public override void Help(Player p) {
@ -215,11 +212,7 @@ namespace MCGalaxy.Commands.Building {
Player.Message(p, "%T/Portal [block] multi");
Player.Message(p, "%HPlace multiple blocks for entries, then a red block for exit.");
Player.Message(p, "%H Note: The exit can be on a different level.");
List<string> names = new List<string>();
if (Player.IsSuper(p)) CoreNames(names);
else AllNames(p, names);
List<string> names = SupportedBlocks(p);
Player.Message(p, "%H Supported blocks: %S{0}", names.Join());
Player.Message(p, "%T/Portal show %H- Shows portals (green = entry, red = exit)");
}

View File

@ -444,6 +444,8 @@ namespace MCGalaxy {
}
internal bool HasCustomProps(BlockID block) {
if ((Props[block].ChangedScope & 2) != 0) return true;
if (Block.IsPhysicsType(block)) return false;
BlockRaw raw = (BlockRaw)block;
return CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw];
@ -453,7 +455,7 @@ namespace MCGalaxy {
for (int i = 0; i < Props.Length; i++) {
BlockID block = (BlockID)i;
if (!HasCustomProps(block)) {
Props[i] = BlockDefinition.DefaultProps(block);
Props[i] = Block.Props[i];
} else {
Props[i] = BlockProps.MakeDefault();
}
@ -462,7 +464,14 @@ namespace MCGalaxy {
public void UpdateBlockProps() {
LoadCoreProps();
BlockProps.Load("lvl_" + MapName, Props, PropsLock, true);
string propsPath = BlockProps.PropsPath("_" + MapName);
// backwards compatibility with older versions
if (!File.Exists(propsPath)) {
BlockProps.Load("lvl_" + MapName, Props, PropsLock, 2, true);
} else {
BlockProps.Load("_" + MapName, Props, PropsLock, 2, false);
}
}
public void UpdateBlockHandlers() {

View File

@ -201,7 +201,6 @@ namespace MCGalaxy {
Command.InitAll();
CommandPerms.Load();
Block.SetBlocks();
BlockDefinition.UpdateGlobalBlockProps();
Awards.Load();
Economy.Load();
WarpList.Global.Filename = "extra/warps.save";