Add extended collide types to lb/gb, and document lb/gb properties. Fixes #464 and fixes #465

This commit is contained in:
UnknownShadow200 2017-07-24 23:13:46 +10:00
parent 2b5f0406af
commit 4d15eed405
19 changed files with 211 additions and 201 deletions

View File

@ -196,7 +196,7 @@ namespace MCGalaxy {
case 209: case 209:
case 210: case 210:
case 213: case 213:
case Door_Air2_air: case 214:
case 215: case 215:
case 216: case 216:
case Door_Air_air: case Door_Air_air:

View File

@ -278,7 +278,7 @@ namespace MCGalaxy
public const byte Door_Green_air = 211; public const byte Door_Green_air = 211;
public const byte Door_TNT_air = 212; public const byte Door_TNT_air = 212;
//public const byte Door_Slab_air = 213; // unused in core //public const byte Door_Slab_air = 213; // unused in core
public const byte Door_Air2_air = 214; //public const byte Door_AirActivatable_air = 214;
//public const byte Door_Water_air = 215; // unused in core //public const byte Door_Water_air = 215; // unused in core
//public const byte Door_Lava_air = 216; // unused in core //public const byte Door_Lava_air = 216; // unused in core
public const byte Door_Air_air = 217; public const byte Door_Air_air = 217;

View File

@ -216,9 +216,17 @@ namespace MCGalaxy.Blocks {
} }
public static class CollideType { public static class CollideType {
public const byte WalkThrough = 0; // i.e. gas or sprite public const byte WalkThrough = 0; // Gas (usually also used by sprite)
public const byte SwimThrough = 1; // i.e. liquid public const byte SwimThrough = 1; // Liquid
public const byte Solid = 2; // i.e. solid public const byte Solid = 2; // Solid
public const byte Ice = 3; // Solid and partially slidable on.
public const byte SlipperyIce = 4; // Solid and fully slidable on.
public const byte LiquidWater = 5; // Water style 'swimming'/'bobbing'
public const byte LiquidLava = 6; // Lava style 'swimming'/'bobbing'
public static bool IsSolid(byte collide) {
return collide >= Solid && collide <= SlipperyIce;
}
} }
public enum SoundType : byte { public enum SoundType : byte {

View File

@ -148,7 +148,7 @@ namespace MCGalaxy.Commands.CPE {
bool tinted = (def.FogR != 0 || def.FogG != 0 || def.FogB != 0) && def.Name.IndexOf('#') >= 0; bool tinted = (def.FogR != 0 || def.FogG != 0 || def.FogB != 0) && def.Name.IndexOf('#') >= 0;
if (tinted) { if (tinted) {
Player.Message(p, " Tint color: {0}", Utils.Hex(def.FogR, def.FogG, def.FogB)); Player.Message(p, " Tint color: {0}", Utils.Hex(def.FogR, def.FogG, def.FogB));
} }
if (def.Shape == 0) { if (def.Shape == 0) {
@ -297,9 +297,9 @@ namespace MCGalaxy.Commands.CPE {
static void EditHandler(Player p, string[] parts, bool global, string cmd) { static void EditHandler(Player p, string[] parts, bool global, string cmd) {
if (parts.Length <= 3) { if (parts.Length <= 3) {
if (parts.Length == 1) { if (parts.Length == 1) {
Player.Message(p, "Valid properties: name, collide, speed, toptex, alltex, sidetex, " + Player.Message(p, "Valid properties: " + helpSections.Keys.Join());
"bottomtex, blockslight, sound, fullbright, shape, blockdraw, min, max, " + } else if (parts.Length == 3) {
"fogdensity, fogcolor, fallback, lefttex, righttex, fronttex, backtex"); Help(p, cmd, "edit " + parts[2]);
} else { } else {
Help(p, cmd); Help(p, cmd);
} }
@ -307,7 +307,7 @@ namespace MCGalaxy.Commands.CPE {
} }
ExtBlock block; ExtBlock block;
if (!CheckBlock(p, parts[1], out block)) return; if (!CheckBlock(p, parts[1], out block)) return;
BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : p.level.CustomBlockDefs; BlockDefinition[] defs = global ? BlockDefinition.GlobalDefs : p.level.CustomBlockDefs;
BlockDefinition def = defs[block.RawID]; BlockDefinition def = defs[block.RawID];
@ -321,125 +321,89 @@ namespace MCGalaxy.Commands.CPE {
float fTemp; float fTemp;
bool temp = false, changedFallback = false; bool temp = false, changedFallback = false;
switch (parts[2].ToLower()) { string arg = MapPropertyName(parts[2].ToLower());
switch (arg) {
case "name": case "name":
def.Name = value; break; def.Name = value; break;
case "collide": case "collide":
if (!EditByte(p, value, "Collide type", ref def.CollideType, 9, 1, 0, 6)) return; if (!EditByte(p, value, "Collide type", ref def.CollideType, "collide", 0, 6)) return;
break; break;
case "speed": case "speed":
if (!Utils.TryParseDecimal(value, out fTemp) || fTemp < 0.25f || fTemp > 3.96f) { if (!Utils.TryParseDecimal(value, out fTemp) || fTemp < 0.25f || fTemp > 3.96f) {
SendEditHelp(p, 10, 0); return; SendEditHelp(p, "speed"); return;
} }
def.Speed = fTemp; break; def.Speed = fTemp; break;
case "top":
case "toptex": case "toptex":
if (!EditByte(p, value, "Top texture", ref def.TopTex)) return; if (!EditByte(p, value, "Top texture", ref def.TopTex, "top")) return;
break; break;
case "all":
case "alltex": case "alltex":
if (!EditByte(p, value, "All textures", ref def.SideTex)) return; if (!EditByte(p, value, "All textures", ref def.SideTex, "all")) return;
def.SetAllTex(def.SideTex); def.SetAllTex(def.SideTex);
break; break;
case "side":
case "sidetex": case "sidetex":
if (!EditByte(p, value, "Side texture", ref def.SideTex)) return; if (!EditByte(p, value, "Side texture", ref def.SideTex, "sides")) return;
def.SetSideTex(def.SideTex); def.SetSideTex(def.SideTex);
break; break;
case "left":
case "lefttex": case "lefttex":
if (!EditByte(p, value, "Left texture", ref def.LeftTex)) return; if (!EditByte(p, value, "Left texture", ref def.LeftTex, "left")) return;
break; break;
case "right":
case "righttex": case "righttex":
if (!EditByte(p, value, "Right texture", ref def.RightTex)) return; if (!EditByte(p, value, "Right texture", ref def.RightTex, "right")) return;
break; break;
case "front":
case "fronttex": case "fronttex":
if (!EditByte(p, value, "Front texture", ref def.FrontTex)) return; if (!EditByte(p, value, "Front texture", ref def.FrontTex, "front")) return;
break; break;
case "back":
case "backtex": case "backtex":
if (!EditByte(p, value, "Back texture", ref def.BackTex)) return; if (!EditByte(p, value, "Back texture", ref def.BackTex, "back")) return;
break; break;
case "bottom":
case "bottomtex": case "bottomtex":
if (!EditByte(p, value, "Bottom texture", ref def.BottomTex)) return; if (!EditByte(p, value, "Bottom texture", ref def.BottomTex, "bottom")) return;
break; break;
case "light":
case "blockslight": case "blockslight":
if (!CommandParser.GetBool(p, value, ref temp)) { if (!CommandParser.GetBool(p, value, ref temp)) {
SendEditHelp(p, 11, 0); return; SendEditHelp(p, "shadow"); return;
} }
def.BlocksLight = temp; def.BlocksLight = temp;
break; break;
case "sound": case "sound":
case "walksound": if (!EditByte(p, value, "Walk sound", ref def.WalkSound, "sound", 0, 11)) return;
if (!EditByte(p, value, "Walk sound", ref def.WalkSound, 12, 1, 0, 11)) return;
break; break;
case "bright":
case "fullbright": case "fullbright":
if (!CommandParser.GetBool(p, value, ref temp)) { if (!CommandParser.GetBool(p, value, ref temp)) {
SendEditHelp(p, 13, 0); return; SendEditHelp(p, "bright"); return;
} }
def.FullBright = temp; def.FullBright = temp;
break; break;
case "shape": case "shape":
if (!CommandParser.GetBool(p, value, ref temp)) { if (!CommandParser.GetBool(p, value, ref temp)) {
SendEditHelp(p, 3, 0); return; SendEditHelp(p,"shape"); return;
} }
def.Shape = temp ? (byte)0 : def.MaxZ; def.Shape = temp ? (byte)0 : def.MaxZ;
break; break;
case "draw":
case "blockdraw": case "blockdraw":
if (!EditByte(p, value, "Block draw", ref def.BlockDraw, 14, 1, 0, 255)) return; if (!EditByte(p, value, "Block draw", ref def.BlockDraw, "draw", 0, 255)) return;
break; break;
case "min": case "min":
case "mincoords":
if (!ParseCoords(value, ref def.MinX, ref def.MinY, ref def.MinZ)) { if (!ParseCoords(value, ref def.MinX, ref def.MinY, ref def.MinZ)) {
SendEditHelp(p, 7, 0); return; SendEditHelp(p, "min"); return;
} } break;
break;
case "max": case "max":
case "maxcoords":
if (!ParseCoords(value, ref def.MaxX, ref def.MaxY, ref def.MaxZ)) { if (!ParseCoords(value, ref def.MaxX, ref def.MaxY, ref def.MaxZ)) {
SendEditHelp(p, 8, 0); return; SendEditHelp(p, "max"); return;
} } break;
break;
case "density":
case "fogdensity": case "fogdensity":
if (!EditByte(p, value, "Fog density", ref def.FogDensity)) return; if (!EditByte(p, value, "Fog density", ref def.FogDensity, "fog")) return;
break; break;
case "col":
case "fogcol":
case "fogcolor": case "fogcolor":
CustomColor rgb = default(CustomColor); CustomColor rgb = default(CustomColor);
if (!CommandParser.GetHex(p, value, ref rgb)) return; if (!CommandParser.GetHex(p, value, ref rgb)) return;
def.FogR = rgb.R; def.FogG = rgb.G; def.FogB = rgb.B; def.FogR = rgb.R; def.FogG = rgb.G; def.FogB = rgb.B;
break; break;
case "fallback": case "fallback":
case "fallbackid":
case "fallbackblock":
byte fallback = GetFallback(p, value); byte fallback = GetFallback(p, value);
if (fallback == Block.Invalid) return; if (fallback == Block.Invalid) return;
changedFallback = true; changedFallback = true;
@ -447,10 +411,10 @@ namespace MCGalaxy.Commands.CPE {
value = Block.Name(fallback); value = Block.Name(fallback);
def.FallBack = fallback; break; def.FallBack = fallback; break;
default: default:
Player.Message(p, "Unrecognised property: " + parts[2]); return; Player.Message(p, "Unrecognised property: " + arg); return;
} }
Player.Message(p, "Set {0} for {1} to {2}", parts[2], blockName, value); Player.Message(p, "Set {0} for {1} to {2}", arg, blockName, value);
BlockDefinition.Add(def, defs, p == null ? null : p.level); BlockDefinition.Add(def, defs, p == null ? null : p.level);
if (changedFallback) if (changedFallback)
BlockDefinition.UpdateFallback(global, def.BlockID, p == null ? null : p.level); BlockDefinition.UpdateFallback(global, def.BlockID, p == null ? null : p.level);
@ -480,7 +444,7 @@ namespace MCGalaxy.Commands.CPE {
string scope = global ? "global" : "level"; string scope = global ? "global" : "level";
Player.Message(p, "Created a new " + scope + " custom block " + def.Name + "(" + def.BlockID + ")"); Player.Message(p, "Created a new " + scope + " custom block " + def.Name + "(" + def.BlockID + ")");
block = ExtBlock.FromRaw(def.BlockID); block = ExtBlock.FromRaw(def.BlockID);
BlockDefinition.Add(def, defs, p == null ? null : p.level); BlockDefinition.Add(def, defs, p == null ? null : p.level);
UpdateBlockProps(global, p, block, props); UpdateBlockProps(global, p, block, props);
return true; return true;
@ -530,18 +494,17 @@ namespace MCGalaxy.Commands.CPE {
Player.Message(p, "Type \"%T{0} list\" %Sto see a list of {1} custom blocks.", cmd, scope); Player.Message(p, "Type \"%T{0} list\" %Sto see a list of {1} custom blocks.", cmd, scope);
} }
static bool EditByte(Player p, string arg, string propName, ref byte target) { static bool EditByte(Player p, string arg, string propName, ref byte target, string help) {
return EditByte(p, arg, propName, ref target, -1, 0, 0, 255); return EditByte(p, arg, propName, ref target, help, 0, 255);
} }
static bool EditByte(Player p, string value, string propName, ref byte target, static bool EditByte(Player p, string value, string propName, ref byte target,
int step, int offset, byte min, byte max) { string help, byte min, byte max) {
int temp = 0; int temp = 0;
if (!CommandParser.GetInt(p, value, propName, ref temp, min, max)) { if (!CommandParser.GetInt(p, value, propName, ref temp, min, max)) {
if (step != -1) SendEditHelp(p, step, offset); SendEditHelp(p, help);
return false; return false;
} }
target = (byte)temp; return true; target = (byte)temp; return true;
} }
@ -573,14 +536,14 @@ namespace MCGalaxy.Commands.CPE {
p.level.BlockProps[block.Index] = props; p.level.BlockProps[block.Index] = props;
p.level.UpdateBlockHandler(block); p.level.UpdateBlockHandler(block);
return; return;
} }
BlockDefinition.GlobalProps[block.Index] = props; BlockDefinition.GlobalProps[block.Index] = props;
Level[] loaded = LevelInfo.Loaded.Items; Level[] loaded = LevelInfo.Loaded.Items;
byte raw = block.RawID; byte raw = block.RawID;
foreach (Level lvl in loaded) { foreach (Level lvl in loaded) {
if (lvl.CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw]) continue; if (lvl.CustomBlockDefs[raw] != BlockDefinition.GlobalDefs[raw]) continue;
lvl.BlockProps[block.Index] = props; lvl.BlockProps[block.Index] = props;
lvl.UpdateBlockHandler(block); lvl.UpdateBlockHandler(block);
} }
@ -595,7 +558,7 @@ namespace MCGalaxy.Commands.CPE {
} }
BlockProps props = BlockProps.MakeDefault(); BlockProps props = BlockProps.MakeDefault();
BlockDefinition.GlobalProps[block.Index] = props; BlockDefinition.GlobalProps[block.Index] = props;
Level[] loaded = LevelInfo.Loaded.Items; Level[] loaded = LevelInfo.Loaded.Items;
byte raw = block.RawID; byte raw = block.RawID;
if (!block.IsCustomType) props = Block.Props[raw]; if (!block.IsCustomType) props = Block.Props[raw];
@ -638,7 +601,7 @@ namespace MCGalaxy.Commands.CPE {
static void SendStepHelp(Player p, bool global) { static void SendStepHelp(Player p, bool global) {
int step = GetStep(p, global); int step = GetStep(p, global);
string[] help = stepsHelp[step]; string[] help = helpSections[stepsHelp[step]];
BlockDefinition bd = GetBD(p, global); BlockDefinition bd = GetBD(p, global);
if (step == 4 && bd.Shape == 0) if (step == 4 && bd.Shape == 0)
@ -649,59 +612,80 @@ namespace MCGalaxy.Commands.CPE {
Player.Message(p, "%f--------------------------"); Player.Message(p, "%f--------------------------");
} }
static void SendEditHelp(Player p, int step, int offset) { static void SendEditHelp(Player p, string section) {
string[] help = stepsHelp[step]; string[] help = helpSections[section];
for (int i = offset; i < help.Length; i++) for (int i = 0; i < help.Length; i++)
Player.Message(p, help[i].Replace("Type", "Use")); Player.Message(p, help[i].Replace("Type", "Use"));
} }
static string[][] stepsHelp = new string[][] { static string MapPropertyName(string prop) {
null, // step 0 if (prop == "side" || prop == "all" || prop == "top" || prop == "bottom"
null, // step 1 || prop == "left" || prop == "right" || prop == "front" || prop == "back") return prop + "tex";
new string[] { "Type the name for the block." },
new string[] { "Type '0' if the block is a cube, '1' if a sprite (e.g roses)." },
new string[] { "Type a number between '0' and '255' for the top texture.", if (prop == "sides" || prop == "sidestex") return "sidetex";
"Textures in terrain.png are numbered from left to right, increasing downwards", if (prop == "light") return "blockslight";
}, if (prop == "bright") return "fullbright";
new string[] { "Type a number between '0' and '255' for the sides texture.", if (prop == "walksound") return "sound";
"Textures in terrain.png are numbered from left to right, increasing downwards.", if (prop == "draw") return "blockdraw";
}, if (prop == "mincoords") return "min";
new string[] { "Type a number between '0' and '255' for the bottom texture.", if (prop == "maxcoords") return "max";
"Textures in terrain.png are numbered from left to right, increasing downwards.", if (prop == "density") return "fogdensity";
}, if (prop == "col" || prop == "fogcol") return "fogcolor";
if (prop == "fallbackid" || prop == "fallbackblock") return "fallback";
new string[] { "Enter the three minimum coordinates of the cube in units (separated by spaces). 1 block = 16 units.", return prop;
"Minimum coordinates for a normal block are &40 &20 &10." }, }
new string[] { "Enter the three maximum coordinates of the cube in units (separated by spaces). 1 block = 16 units.",
"Maximum coordinates for a normal block are &416 &216 &116." },
static string[] stepsHelp = new string[] {
null, null, "name", "shape", "toptex", "sidetex", "bottomtex", "min", "max", "collide",
"speed", "blockslight", "sound", "fullbright", "blockdraw", "fogdensity", "fogcolor", "fallback" };
const string texLine = "Textures in terrain.png are numbered from left to right, increasing downwards";
static Dictionary<string, string[]> helpSections = new Dictionary<string, string[]>() {
{ "name", new string[] { "Type the name for the block." } },
{ "shape", new string[] { "Type '0' if the block is a cube, '1' if a sprite (e.g roses)." } },
{ "blockslight", new string[] { "Type 'yes' if the block casts a shadow, 'no' if it doesn't." } },
{ "fullbright", new string[] { "Type 'yes' if the block is fully lit (e.g. lava), 'no' if not." } },
new string[] { "Type a number between '0' and '6' for collision type of this block.", { "alltex", new string[] { "Type a number between '0' and '255' for all textures.", texLine } },
"0 - block is walk-through (e.g. air).", "1 - block is swim-through/climable (e.g. rope).", { "sidetex", new string[] { "Type a number between '0' and '255' for sides texture.", texLine } },
"2 - block is solid (e.g. dirt).", { "lefttex", new string[] { "Type a number between '0' and '255' for the left side texture.", texLine } },
{ "righttex", new string[] { "Type a number between '0' and '255' for the right side texture.", texLine } },
{ "fronttex", new string[] { "Type a number between '0' and '255' for the front side texture.", texLine } },
{ "backtex", new string[] { "Type a number between '0' and '255' for the back side texture.", texLine } },
{ "toptex", new string[] { "Type a number between '0' and '255' for the top texture.", texLine } },
{ "bottomtex", new string[] { "Type a number between '0' and '255' for the bottom texture.", texLine } },
{ "min", new string[] { "Enter the three minimum coordinates of the cube in units (separated by spaces). 1 block = 16 units.",
"Minimum coordinates for a normal block are &40 &20 &10." } },
{ "max", new string[] { "Enter the three maximum coordinates of the cube in units (separated by spaces). 1 block = 16 units.",
"Maximum coordinates for a normal block are &416 &216 &116." } },
{ "collide", new string[] { "Type a number between '0' and '6' for collision type.",
"0 - block is walk-through (e.g. air).", "1 - block is swim-through/climbable (e.g. rope).",
"2 - block is solid (e.g. dirt).", "3 - block is solid, but slippery like ice",
"4 - block is solid, but even slipperier than ice", "5 - block is swim-through like water",
"6 - block is swim-through like lava" } },
{ "speed", new string[] { "Type a number between '0.25' (25% speed) and '3.96' (396% speed).",
"This speed is used when inside or walking on the block. Default speed is 1" }
}, },
new string[] { "Type a number between '0.25' (25% speed) and '3.96' (396% speed).", { "sound", new string[] { "Type a number between '0' and '9' for the sound played when walking on it and breaking.",
"This speed is used when inside or walking on the block. Default speed is 1", "0 = None, 1 = Wood, 2 = Gravel, 3 = Grass, 4 = Stone",
"5 = Metal, 6 = Glass, 7 = Cloth, 8 = Sand, 9 = Snow" }
}, },
new string[] { "Type 'yes' if the block casts a shadow, 'no' if it doesn't" }, { "blockdraw", new string[] { "Enter the block's draw method.", "0 = Opaque, 1 = Transparent (Like glass)",
new string[] { "Type a number between '0' and '9' for the sound played when walking on it and breaking.", "2 = Transparent (Like leaves), 3 = Translucent (Like ice), 4 = Gas (Like air)" }
"0 = None, 1 = Wood, 2 = Gravel, 3 = Grass, 4 = Stone",
"5 = Metal, 6 = Glass, 7 = Cloth, 8 = Sand, 9 = Snow",
}, },
new string[] { "Type 'yes' if the block is fully lit (e.g. lava), 'no' if not." }, { "fogdensity", new string[] { "Enter the fog density for the block. 0 = No fog at all",
new string[] { "Enter the block's draw method.", "0 = Opaque, 1 = Transparent (Like glass)", "1 - 255 = Increasing density (e.g. water has 12, lava 255)" }
"2 = Transparent (Like leaves), 3 = Translucent (Like ice), 4 = Gas (Like air)",
}, },
{ "fogcolor", new string[] { "Enter the fog color (hex color)" } },
new string[] { "Enter the fog density for the block. 0 = No fog at all", { "fallback", new string[] { "Enter the fallback block (Block shown to players who can't see custom blocks).",
"1 - 255 = Increasing density (e.g. water has 12, lava 255)", "You can use any block name or block ID from the normal blocks." }
},
new string[] { "Enter the fog color (hex color)", },
new string[] { "Enter the fallback block (Block shown to players who can't see custom blocks).",
"You can use any block name or block ID from the normal blocks.",
}, },
}; };
internal static void Help(Player p, string cmd) { internal static void Help(Player p, string cmd) {
Player.Message(p, "%T{0} add [id] %H- begins creating a new custom block.", cmd); Player.Message(p, "%T{0} add [id] %H- begins creating a new custom block.", cmd);
Player.Message(p, "%T{0} copy [source id] [new id] %H- clones a new custom block from an existing custom block.", cmd); Player.Message(p, "%T{0} copy [source id] [new id] %H- clones a new custom block from an existing custom block.", cmd);
@ -711,6 +695,18 @@ namespace MCGalaxy.Commands.CPE {
Player.Message(p, "%T{0} info [id] %H- shows info about that custom block.", cmd); Player.Message(p, "%T{0} info [id] %H- shows info about that custom block.", cmd);
Player.Message(p, "%HTo see the list of editable properties, type {0} edit.", cmd); Player.Message(p, "%HTo see the list of editable properties, type {0} edit.", cmd);
} }
internal static void Help(Player p, string cmd, string args) {
if (!args.CaselessStarts("edit ")) { Help(p, cmd); return; }
string prop = args.Substring(args.IndexOf(' ') + 1);
prop = MapPropertyName(prop.ToLower());
if (!helpSections.ContainsKey(prop)) {
Player.Message(p, "Valid properties: " + helpSections.Keys.Join());
} else {
SendEditHelp(p, prop);
}
}
} }
public sealed class CmdGlobalBlock : Command { public sealed class CmdGlobalBlock : Command {
@ -727,6 +723,10 @@ namespace MCGalaxy.Commands.CPE {
public override void Help(Player p) { public override void Help(Player p) {
CustomBlockCommand.Help(p, "/gb"); CustomBlockCommand.Help(p, "/gb");
} }
public override void Help(Player p, string message) {
CustomBlockCommand.Help(p, "/gb", message);
}
} }
public sealed class CmdLevelBlock : Command { public sealed class CmdLevelBlock : Command {
@ -744,5 +744,9 @@ namespace MCGalaxy.Commands.CPE {
public override void Help(Player p) { public override void Help(Player p) {
CustomBlockCommand.Help(p, "/lb"); CustomBlockCommand.Help(p, "/lb");
} }
public override void Help(Player p, string message) {
CustomBlockCommand.Help(p, "/lb", message);
}
} }
} }

View File

@ -74,7 +74,7 @@ namespace MCGalaxy.Commands.Fun {
for (; y <= lvl.Height; y++) { for (; y <= lvl.Height; y++) {
ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z); ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z);
if (above.IsInvalid) continue; if (above.IsInvalid) continue;
if (lvl.CollideType(above) != CollideType.Solid) continue; if (!CollideType.IsSolid(lvl.CollideType(above))) continue;
int posY = (y + 1) * 32 - 6; int posY = (y + 1) * 32 - 6;
BlockDefinition def = lvl.GetBlockDef(above); BlockDefinition def = lvl.GetBlockDef(above);

View File

@ -102,7 +102,7 @@ namespace MCGalaxy.Commands.Building {
static void PlaceMark(Player p, int x, int y, int z) { static void PlaceMark(Player p, int x, int y, int z) {
ExtBlock block = p.GetHeldBlock(); ExtBlock block = p.GetHeldBlock();
p.ManualChange((ushort)x, (ushort)y, (ushort)z, 0, block, false); p.ManualChange((ushort)x, (ushort)y, (ushort)z, false, block, false);
Player.Message(p, "Mark placed at &b({0}, {1}, {2})", x, y, z); Player.Message(p, "Mark placed at &b({0}, {1}, {2})", x, y, z);
} }

View File

@ -51,12 +51,13 @@ namespace MCGalaxy.Commands.Misc {
static int FindYAbove(Level lvl, ushort x, ushort y, ushort z) { static int FindYAbove(Level lvl, ushort x, ushort y, ushort z) {
for (; y < lvl.Height; y++) { for (; y < lvl.Height; y++) {
ExtBlock block = lvl.GetBlock(x, y, z); ExtBlock block = lvl.GetBlock(x, y, z);
if (!block.IsInvalid && lvl.CollideType(block) == CollideType.Solid) continue; if (!block.IsInvalid && CollideType.IsSolid(lvl.CollideType(block))) continue;
ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z); ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z);
if (!above.IsInvalid && lvl.CollideType(above) == CollideType.Solid) continue; if (!above.IsInvalid && CollideType.IsSolid(lvl.CollideType(above))) continue;
ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z); ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z);
if (!below.IsInvalid && lvl.CollideType(below) == CollideType.Solid) if (!below.IsInvalid && CollideType.IsSolid(lvl.CollideType(below)))
return y; return y;
} }
return -1; return -1;

View File

@ -54,12 +54,13 @@ namespace MCGalaxy.Commands.Misc {
static int FindYBelow(Level lvl, ushort x, ushort y, ushort z) { static int FindYBelow(Level lvl, ushort x, ushort y, ushort z) {
for (; y > 0; y--) { for (; y > 0; y--) {
ExtBlock block = lvl.GetBlock(x, y, z); ExtBlock block = lvl.GetBlock(x, y, z);
if (!block.IsInvalid && lvl.CollideType(block) == CollideType.Solid) continue; if (!block.IsInvalid && CollideType.IsSolid(lvl.CollideType(block))) continue;
ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z); ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z);
if (!above.IsInvalid && lvl.CollideType(above) == CollideType.Solid) continue; if (!above.IsInvalid && CollideType.IsSolid(lvl.CollideType(above))) continue;
ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z); ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z);
if (!below.IsInvalid && lvl.CollideType(below) == CollideType.Solid) if (!below.IsInvalid && CollideType.IsSolid(lvl.CollideType(below)))
return y; return y;
} }
return -1; return -1;

View File

@ -112,13 +112,14 @@ namespace MCGalaxy.Events.PlayerEvents {
} }
} }
public delegate void OnBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block); public delegate void SelectionBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block);
public delegate void OnBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool placing);
/// <summary> Called whenever a player places or deletes a block. </summary> /// <summary> Called whenever a player places or deletes a block. </summary>
public sealed class OnBlockChangeEvent : IEvent<OnBlockChange> { public sealed class OnBlockChangeEvent : IEvent<OnBlockChange> {
public static void Call(Player p, ushort x, ushort y, ushort z, ExtBlock block) { public static void Call(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool placing) {
if (handlers.Count == 0) return; if (handlers.Count == 0) return;
CallCommon(pl => pl(p, x, y, z, block)); CallCommon(pl => pl(p, x, y, z, block, placing));
} }
} }

View File

@ -101,7 +101,7 @@ namespace MCGalaxy.Games {
p.cancelchat = true; p.cancelchat = true;
} }
void HandleBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block) { void HandleBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool placing) {
if (!Game.started || p.level != Game.Map) return; if (!Game.started || p.level != Game.Map) return;
CtfTeam2 team = Game.TeamOf(p); CtfTeam2 team = Game.TeamOf(p);
if (team == null) { if (team == null) {

View File

@ -24,12 +24,6 @@ namespace MCGalaxy.Games {
/// <summary> Whether players are allowed to teleport to others when not in referee mode. </summary> /// <summary> Whether players are allowed to teleport to others when not in referee mode. </summary>
public virtual bool TeleportAllowed { get { return true; } } public virtual bool TeleportAllowed { get { return true; } }
/// <summary> Returns whether this game handed the player manually placing a block. </summary>
public virtual bool HandlesManualChange(Player p, ushort x, ushort y, ushort z,
byte action, byte block, byte old) {
return false;
}
/// <summary> Returns whether this game handled the player sending a chat message. </summary> /// <summary> Returns whether this game handled the player sending a chat message. </summary>
public virtual bool HandlesChatMessage(Player p, string message) { public virtual bool HandlesChatMessage(Player p, string message) {
return false; return false;

View File

@ -17,6 +17,7 @@
permissions and limitations under the Licenses. permissions and limitations under the Licenses.
*/ */
using System; using System;
using MCGalaxy.Blocks;
using MCGalaxy.Events; using MCGalaxy.Events;
namespace MCGalaxy.Games.ZS { namespace MCGalaxy.Games.ZS {
@ -24,10 +25,10 @@ namespace MCGalaxy.Games.ZS {
internal static class Pillaring { internal static class Pillaring {
internal static bool Handles(Player p, ushort x, ushort y, ushort z, internal static bool Handles(Player p, ushort x, ushort y, ushort z,
byte action, byte block, byte old, ZSGame game) { bool placing, ExtBlock block, ExtBlock old, ZSGame game) {
if (action == 1 && !game.CurLevel.Config.Pillaring && !p.Game.Referee) { if (placing && !game.CurLevel.Config.Pillaring && !p.Game.Referee) {
if (NotPillaring(block, old)) { if (NotPillaring(game.CurLevel, block, old)) {
p.Game.BlocksStacked = 0; p.Game.BlocksStacked = 0;
} else if (CheckCoords(p, x, y, z)) { } else if (CheckCoords(p, x, y, z)) {
p.Game.BlocksStacked++; p.Game.BlocksStacked++;
@ -41,10 +42,13 @@ namespace MCGalaxy.Games.ZS {
return false; return false;
} }
static bool NotPillaring(byte b, byte old) { static bool NotPillaring(Level lvl, ExtBlock b, ExtBlock old) {
if (Block.Walkthrough(b)) return true; byte collide = lvl.CollideType(b);
old = Block.Convert(old); if (collide == CollideType.WalkThrough) return true;
return old >= Block.Water && old <= Block.StillLava;
collide = lvl.CollideType(old);
return collide == CollideType.SwimThrough || collide == CollideType.LiquidWater
|| collide == CollideType.LiquidLava;
} }
static bool CheckCoords(Player p, ushort x, ushort y, ushort z) { static bool CheckCoords(Player p, ushort x, ushort y, ushort z) {

View File

@ -37,6 +37,7 @@ namespace MCGalaxy.Games.ZS {
OnPlayerMoveEvent.Register(HandlePlayerMove, Priority.High); OnPlayerMoveEvent.Register(HandlePlayerMove, Priority.High);
OnPlayerActionEvent.Register(HandlePlayerAction, Priority.High); OnPlayerActionEvent.Register(HandlePlayerAction, Priority.High);
OnPlayerSpawningEvent.Register(HandlePlayerSpawning, Priority.High); OnPlayerSpawningEvent.Register(HandlePlayerSpawning, Priority.High);
OnBlockChangeEvent.Register(HandleBlockChange, Priority.High);
} }
public override void Unload(bool shutdown) { public override void Unload(bool shutdown) {
@ -47,6 +48,7 @@ namespace MCGalaxy.Games.ZS {
OnPlayerMoveEvent.Unregister(HandlePlayerMove); OnPlayerMoveEvent.Unregister(HandlePlayerMove);
OnPlayerActionEvent.Unregister(HandlePlayerAction); OnPlayerActionEvent.Unregister(HandlePlayerAction);
OnPlayerSpawningEvent.Unregister(HandlePlayerSpawning); OnPlayerSpawningEvent.Unregister(HandlePlayerSpawning);
OnBlockChangeEvent.Unregister(HandleBlockChange);
} }
void HandleTabListEntryAdded(Entity entity, ref string tabName, ref string tabGroup, Player dst) { void HandleTabListEntryAdded(Entity entity, ref string tabName, ref string tabGroup, Player dst) {
@ -116,7 +118,35 @@ namespace MCGalaxy.Games.ZS {
if (p.level != Game.CurLevel) return; if (p.level != Game.CurLevel) return;
if (!p.Game.Referee && !p.Game.Infected && Game.RoundInProgress) { if (!p.Game.Referee && !p.Game.Infected && Game.RoundInProgress) {
Game.InfectPlayer(p, null); Game.InfectPlayer(p, null);
}
}
void HandleBlockChange(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool placing) {
if (p.level != Game.CurLevel) return;
ExtBlock old = Game.CurLevel.GetBlock(x, y, z);
if (Game.CurLevel.Config.BuildType == BuildType.NoModify) {
p.RevertBlock(x, y, z); p.cancelBlock = true; return;
}
if (Game.CurLevel.Config.BuildType == BuildType.ModifyOnly && Game.CurLevel.BlockProps[old.Index].OPBlock) {
p.RevertBlock(x, y, z); p.cancelBlock = true; return;
}
if (Pillaring.Handles(p, x, y, z, placing, block, old, Game)) {
p.cancelBlock = true; return;
}
if (placing || (!placing && p.painting)) {
if (p.Game.Referee) return;
if (p.Game.BlocksLeft == 0) {
Player.Message(p, "You have no blocks left.");
p.RevertBlock(x, y, z); p.cancelBlock = true; return;
}
p.Game.BlocksLeft--;
if ((p.Game.BlocksLeft % 10) == 0 || (p.Game.BlocksLeft >= 0 && p.Game.BlocksLeft <= 10))
Player.Message(p, "Blocks Left: &4" + p.Game.BlocksLeft);
} }
} }
} }

View File

@ -36,33 +36,6 @@ namespace MCGalaxy.Games {
HUD.UpdateAllPrimary(this); HUD.UpdateAllPrimary(this);
} }
public override bool HandlesManualChange(Player p, ushort x, ushort y, ushort z,
byte action, byte block, byte old) {
if (!Running || (p.level == null || !p.level.name.CaselessEq(CurLevelName))) return false;
if (CurLevel.Config.BuildType == BuildType.NoModify) {
p.RevertBlock(x, y, z); return true;
}
if (CurLevel.Config.BuildType == BuildType.ModifyOnly && Block.Props[old].OPBlock) {
p.RevertBlock(x, y, z); return true;
}
if (Pillaring.Handles(p, x, y, z, action, block, old, this)) return true;
if (action == 1 || (action == 0 && p.painting)) {
if (!p.level.name.CaselessEq(CurLevelName) || p.Game.Referee) return false;
if (p.Game.BlocksLeft == 0) {
Player.Message(p, "You have no blocks left.");
p.RevertBlock(x, y, z); return true;
}
p.Game.BlocksLeft--;
if ((p.Game.BlocksLeft % 10) == 0 || (p.Game.BlocksLeft >= 0 && p.Game.BlocksLeft <= 10))
Player.Message(p, "Blocks Left: &4" + p.Game.BlocksLeft);
}
return false;
}
public override bool HandlesChatMessage(Player p, string message) { public override bool HandlesChatMessage(Player p, string message) {
if (!Running || (p.level == null || !p.level.name.CaselessEq(CurLevelName))) return false; if (!Running || (p.level == null || !p.level.name.CaselessEq(CurLevelName))) return false;
if (Server.votingforlevel && HandleVote(p, message)) return true; if (Server.votingforlevel && HandleVote(p, message)) return true;

View File

@ -494,7 +494,7 @@ namespace MCGalaxy {
} }
public void UpdateBlockHandler(ExtBlock block) { public void UpdateBlockHandler(ExtBlock block) {
bool nonSolid = CollideType(block) != MCGalaxy.Blocks.CollideType.Solid; bool nonSolid = !MCGalaxy.Blocks.CollideType.IsSolid(CollideType(block));
int i = block.Index; int i = block.Index;
deleteHandlers[i] = BlockBehaviour.GetDeleteHandler(block, BlockProps); deleteHandlers[i] = BlockBehaviour.GetDeleteHandler(block, BlockProps);

View File

@ -252,7 +252,7 @@ namespace MCGalaxy {
/// <summary> Called when a player removes or places a block. /// <summary> Called when a player removes or places a block.
/// NOTE: Currently this prevents the OnBlockChange event from being called. </summary> /// NOTE: Currently this prevents the OnBlockChange event from being called. </summary>
public event OnBlockChange Blockchange; public event SelectionBlockChange Blockchange;
internal bool HasBlockchange { get { return Blockchange != null; } } internal bool HasBlockchange { get { return Blockchange != null; } }
public void ClearBlockchange() { ClearSelection(); } public void ClearBlockchange() { ClearSelection(); }

View File

@ -46,12 +46,8 @@ namespace MCGalaxy {
} }
} }
} }
public void ManualChange(ushort x, ushort y, ushort z, byte action, ExtBlock block) { public void ManualChange(ushort x, ushort y, ushort z, bool placing,
ManualChange(x, y, z, action, block, true);
}
public void ManualChange(ushort x, ushort y, ushort z, byte action,
ExtBlock block, bool checkPlaceDist) { ExtBlock block, bool checkPlaceDist) {
ExtBlock old = level.GetBlock(x, y, z); ExtBlock old = level.GetBlock(x, y, z);
if (old.IsInvalid) return; if (old.IsInvalid) return;
@ -62,21 +58,14 @@ namespace MCGalaxy {
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
} }
if (level.IsMuseum && Blockchange == null) return; if (level.IsMuseum && Blockchange == null) return;
if (action > 1) { bool deletingBlock = !painting && !placing;
const string msg = "Unknown block action!";
Leave(msg, msg, true); return;
}
bool doDelete = !painting && action == 0;
if (ServerConfig.verifyadmins && adminpen) { if (ServerConfig.verifyadmins && adminpen) {
SendMessage("&cYou must first verify with %T/pass [Password]"); SendMessage("&cYou must first verify with %T/pass [Password]");
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
} }
if (Server.zombie.Running && Server.zombie.HandlesManualChange(this, x, y, z, action, block.BlockID, old.BlockID))
return;
if ( Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this) ) { if ( Server.lava.active && Server.lava.HasPlayer(this) && Server.lava.IsPlayerDead(this) ) {
SendMessage("You are out of the round, and cannot build."); SendMessage("You are out of the round, and cannot build.");
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
@ -86,7 +75,7 @@ namespace MCGalaxy {
if (Blockchange != null) { if (Blockchange != null) {
Blockchange(this, x, y, z, block); return; Blockchange(this, x, y, z, block); return;
} }
OnBlockChangeEvent.Call(this, x, y, z, block); OnBlockChangeEvent.Call(this, x, y, z, block, placing);
if (cancelBlock) { cancelBlock = false; return; } if (cancelBlock) { cancelBlock = false; return; }
if (old.BlockID >= Block.Air_Flood && old.BlockID <= Block.Door_Air_air) { if (old.BlockID >= Block.Air_Flood && old.BlockID <= Block.Door_Air_air) {
@ -94,7 +83,7 @@ namespace MCGalaxy {
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
} }
if (!deleteMode) { if (!deletingBlock) {
PhysicsArgs args = level.foundInfo(x, y, z); PhysicsArgs args = level.foundInfo(x, y, z);
if (args.HasWait) return; if (args.HasWait) return;
} }
@ -113,19 +102,19 @@ namespace MCGalaxy {
ExtBlock held = block; ExtBlock held = block;
block = BlockBindings[block.RawID]; block = BlockBindings[block.RawID];
if (!CheckManualChange(old, block, doDelete)) { if (!CheckManualChange(old, block, deletingBlock)) {
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
} }
if (!ModeBlock.IsAir) block = ModeBlock; if (!ModeBlock.IsAir) block = ModeBlock;
//Ignores updating blocks that are the same and revert block back only to the player //Ignores updating blocks that are the same and revert block back only to the player
ExtBlock newB = (painting || action == 1) ? block : ExtBlock.Air; ExtBlock newB = deletingBlock ? ExtBlock.Air : block;
if (old == newB) { if (old == newB) {
if (painting || !old.VisuallyEquals(held)) RevertBlock(x, y, z); if (painting || !old.VisuallyEquals(held)) RevertBlock(x, y, z);
return; return;
} }
if (doDelete) { if (deletingBlock) {
bool deleted = DeleteBlock(old, x, y, z, block); bool deleted = DeleteBlock(old, x, y, z, block);
} else { } else {
bool placed = PlaceBlock(old, x, y, z, block); bool placed = PlaceBlock(old, x, y, z, block);
@ -280,6 +269,11 @@ namespace MCGalaxy {
if (frozen) { RevertBlock(x, y, z); return; } if (frozen) { RevertBlock(x, y, z); return; }
byte action = packet[7]; byte action = packet[7];
if (action > 1) {
const string msg = "Unknown block action!";
Leave(msg, msg, true); return;
}
ExtBlock held = ExtBlock.FromRaw(packet[8]); ExtBlock held = ExtBlock.FromRaw(packet[8]);
RawHeldBlock = held; RawHeldBlock = held;
@ -297,7 +291,7 @@ namespace MCGalaxy {
RevertBlock(x, y, z); return; RevertBlock(x, y, z); return;
} }
} }
ManualChange(x, y, z, action, held); ManualChange(x, y, z, action != 0, held, true);
} catch ( Exception e ) { } catch ( Exception e ) {
// Don't ya just love it when the server tattles? // Don't ya just love it when the server tattles?
Chat.MessageOps(DisplayName + " has triggered a block change error"); Chat.MessageOps(DisplayName + " has triggered a block change error");

View File

@ -65,10 +65,10 @@ namespace MCGalaxy.Blocks.Physics {
for (int x = min.X; x <= max.X; x++) for (int x = min.X; x <= max.X; x++)
{ {
ExtBlock block = GetSurvivalBlock(p, x, min.Y, z); ExtBlock block = GetSurvivalBlock(p, x, min.Y, z);
byte collideType = p.level.CollideType(block); byte collide = p.level.CollideType(block);
allGas = allGas && collideType == CollideType.WalkThrough; allGas = allGas && collide == CollideType.WalkThrough;
if (collideType != CollideType.Solid) continue; if (!CollideType.IsSolid(collide)) continue;
if (p.fallCount > p.level.Config.FallHeight) if (p.fallCount > p.level.Config.FallHeight)
p.HandleDeath(ExtBlock.Air, null, false, true); p.HandleDeath(ExtBlock.Air, null, false, true);

View File

@ -158,7 +158,7 @@ namespace MCGalaxy.Maths {
BlockDefinition def = lvl.GetBlockDef(block); BlockDefinition def = lvl.GetBlockDef(block);
if (def != null) { if (def != null) {
if (def.CollideType == CollideType.Solid) return true; if (CollideType.IsSolid(def.CollideType)) return true;
} else { } else {
if (block.BlockID == Block.Invalid || !Block.Walkthrough(Block.Convert(block.BlockID))) return true; if (block.BlockID == Block.Invalid || !Block.Walkthrough(Block.Convert(block.BlockID))) return true;
} }