diff --git a/MCGalaxy/CorePlugin/MiscHandlers.cs b/MCGalaxy/CorePlugin/MiscHandlers.cs index 6c3111032..2af486cf4 100644 --- a/MCGalaxy/CorePlugin/MiscHandlers.cs +++ b/MCGalaxy/CorePlugin/MiscHandlers.cs @@ -58,10 +58,7 @@ namespace MCGalaxy.Core { foreach (Zone zn in zones) { zn.Show(p); } } - if (p.aiming && !level.Config.Guns) { - p.aiming = false; - p.ClearBlockchange(); - } + if (p.weapon != null && !level.Config.Guns) p.weapon.Disable(); if (!level.Config.UseBlockDB) { p.Message("BlockDB is disabled here, %Wyou will not be able to /undo or /redo"); } diff --git a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs index 2530afa05..75257f85c 100644 --- a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs +++ b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs @@ -175,10 +175,10 @@ namespace MCGalaxy.Drawing.Ops { if (old == b.Block || !p.group.Blocks[old] || !p.group.Blocks[b.Block]) return; // Check if player can affect block at coords in world - AccessController denied = lvl.CanAffect(p, b.X, b.Y, b.Z); - if (denied != null) { + AccessController denier = lvl.CanAffect(p, b.X, b.Y, b.Z); + if (denier != null) { if (p.lastAccessStatus < DateTime.UtcNow) { - denied.CheckDetailed(p); + denier.CheckDetailed(p); p.lastAccessStatus = DateTime.UtcNow.AddSeconds(2); } return; diff --git a/MCGalaxy/Games/CTF/CtfGame.Round.cs b/MCGalaxy/Games/CTF/CtfGame.Round.cs index 60ca94c1d..762e05666 100644 --- a/MCGalaxy/Games/CTF/CtfGame.Round.cs +++ b/MCGalaxy/Games/CTF/CtfGame.Round.cs @@ -75,12 +75,9 @@ namespace MCGalaxy.Games { void ResetPlayerFlag(Player p, CtfData data) { Vec3S32 last = data.LastHeadPos; ushort x = (ushort)last.X, y = (ushort)last.Y, z = (ushort)last.Z; - data.LastHeadPos = default(Vec3S32); - BlockID origBlock = Map.GetBlock(x, y, z); - if (origBlock != Block.Invalid) { - Map.BroadcastChange(x, y, z, origBlock); - } + data.LastHeadPos = default(Vec3S32); + Map.BroadcastRevert(x, y, z); } void DrawPlayerFlag(Player p, CtfData data) { diff --git a/MCGalaxy/Games/Weapons/Guns.cs b/MCGalaxy/Games/Weapons/Guns.cs index f5fc5c460..6176e52e9 100644 --- a/MCGalaxy/Games/Weapons/Guns.cs +++ b/MCGalaxy/Games/Weapons/Guns.cs @@ -52,7 +52,7 @@ namespace MCGalaxy.Games { if (args.iterations > 12) { Vec3U16 pos = args.visible[0]; args.visible.RemoveAt(0); - p.level.Blockchange(pos.X, pos.Y, pos.Z, Block.Air, true); + p.level.BroadcastRevert(pos.X, pos.Y, pos.Z); } return true; } @@ -63,7 +63,7 @@ namespace MCGalaxy.Games { if (args.visible.Count > 0) { Vec3U16 pos = args.visible[0]; args.visible.RemoveAt(0); - p.level.Blockchange(pos.X, pos.Y, pos.Z, Block.Air, true); + p.level.BroadcastRevert(pos.X, pos.Y, pos.Z); } return args.visible.Count > 0; } @@ -88,7 +88,7 @@ namespace MCGalaxy.Games { if (cur != Block.Air && !args.all.Contains(pos) && OnHitBlock(args, pos, cur)) return false; - p.level.Blockchange(pos.X, pos.Y, pos.Z, args.block); + p.level.BroadcastChange(pos.X, pos.Y, pos.Z, args.block); args.visible.Add(pos); args.all.Add(pos); @@ -145,7 +145,7 @@ namespace MCGalaxy.Games { args.all.Clear(); } else { foreach (Vec3U16 pos in args.visible) { - p.level.Blockchange(pos.X, pos.Y, pos.Z, Block.Air, true); + p.level.BroadcastRevert(pos.X, pos.Y, pos.Z); } args.visible.Clear(); } diff --git a/MCGalaxy/Games/Weapons/Weapon.cs b/MCGalaxy/Games/Weapons/Weapon.cs index a95b6bbb1..857121693 100644 --- a/MCGalaxy/Games/Weapons/Weapon.cs +++ b/MCGalaxy/Games/Weapons/Weapon.cs @@ -25,171 +25,172 @@ using BlockID = System.UInt16; namespace MCGalaxy.Games { - /// Represents a weapon which can interact with blocks or players until it dies. - /// Activated by clicking through either PlayerClick or a glass box around the player. - public abstract class Weapon { + /// Represents a weapon which can interact with blocks or players until it dies. + /// Activated by clicking through either PlayerClick or a glass box around the player. + public abstract class Weapon { - public abstract string Name { get; } - static bool hookedEvents; - - protected Player p; - AimBox aimer; - - public void Enable(Player p) { - if (!hookedEvents) { - OnPlayerClickEvent.Register(PlayerClickCallback, Priority.Low); - hookedEvents = true; - } - this.p = p; - p.ClearBlockchange(); - - if (p.Supports(CpeExt.PlayerClick)) { - p.Message(Name + " engaged, click to fire at will"); - } else { - p.Blockchange += BlockClickCallback; - p.Message(Name + " engaged, fire at will"); - aimer = new AimBox(); - aimer.Hook(p); - } - } + public abstract string Name { get; } + static bool hookedEvents; + + protected Player p; + AimBox aimer; + + public void Enable(Player p) { + if (!hookedEvents) { + OnPlayerClickEvent.Register(PlayerClickCallback, Priority.Low); + hookedEvents = true; + } + this.p = p; + p.ClearBlockchange(); + + if (p.Supports(CpeExt.PlayerClick)) { + p.Message(Name + " engaged, click to fire at will"); + } else { + p.Blockchange += BlockClickCallback; + p.Message(Name + " engaged, fire at will"); + aimer = new AimBox(); + aimer.Hook(p); + } + } - public void Disable() { - p.aiming = false; - p.ClearBlockchange(); - p.Message(Name + " disabled"); - } - - protected abstract void OnActivated(byte yaw, byte pitch, BlockID block); + public void Disable() { + p.aiming = false; + p.ClearBlockchange(); + p.Message(Name + " disabled"); + p.weapon = null; + } + + protected abstract void OnActivated(byte yaw, byte pitch, BlockID block); - - static void BlockClickCallback(Player p, ushort x, ushort y, ushort z, BlockID block) { - Weapon weapon = p.weapon; - if (weapon == null) return; - - p.RevertBlock(x, y, z); - // defer to player click handler - if (weapon.aimer == null) return; - - if (!p.level.Config.Guns) { weapon.Disable(); return; } - if (!CommandParser.IsBlockAllowed(p, "use", block)) return; + + static void BlockClickCallback(Player p, ushort x, ushort y, ushort z, BlockID block) { + Weapon weapon = p.weapon; + if (weapon == null) return; + + p.RevertBlock(x, y, z); + // defer to player click handler + if (weapon.aimer == null) return; + + if (!p.level.Config.Guns) { weapon.Disable(); return; } + if (!CommandParser.IsBlockAllowed(p, "use", block)) return; - weapon.OnActivated(p.Rot.RotY, p.Rot.HeadX, block); - } - - static void PlayerClickCallback(Player p, MouseButton btn, MouseAction action, - ushort yaw, ushort pitch, byte entity, - ushort x, ushort y, ushort z, TargetBlockFace face) { - Weapon weapon = p.weapon; - if (weapon == null || action != MouseAction.Pressed) return; - - if (!(btn == MouseButton.Left || btn == MouseButton.Right)) return; - if (!p.level.Config.Guns) { weapon.Disable(); return; } - - BlockID held = p.RawHeldBlock; - if (!CommandParser.IsBlockAllowed(p, "use", held)) return; - weapon.OnActivated((byte)(yaw >> 8), (byte)(pitch >> 8), held); - } - - protected static Player PlayerAt(Player p, Vec3U16 pos, bool skipSelf) { - Player[] players = PlayerInfo.Online.Items; - foreach (Player pl in players) { - if (pl.level != p.level) continue; - if (p == pl && skipSelf) continue; - - if (Math.Abs(pl.Pos.BlockX - pos.X) <= 1 - && Math.Abs(pl.Pos.BlockY - pos.Y) <= 1 - && Math.Abs(pl.Pos.BlockZ - pos.Z) <= 1) - { - return pl; - } - } - return null; - } - } - - public class AmmunitionData { - public BlockID block; - public Vec3U16 pos, start; - public Vec3F32 dir; - public bool moving = true; - - // positions of all currently visible "trailing" blocks - public List visible = new List(); - // position of all blocks this ammunition has touched/gone through - public List all = new List(); - public int iterations; - - public Vec3U16 PosAt(int i) { - Vec3U16 target; - target.X = (ushort)Math.Round(start.X + (double)(dir.X * i)); - target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i)); - target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i)); - return target; - } - } - - /// Manages the glass box around the player. Adjusts based on where player is looking. - internal sealed class AimBox { - - Player player; - List lastGlass = new List(); - List curGlass = new List(); - - public void Hook(Player p) { - player = p; - SchedulerTask task = new SchedulerTask(AimCallback, null, TimeSpan.Zero, true); - p.CriticalTasks.Add(task); - } - - void AimCallback(SchedulerTask task) { - Player p = player; - if (p.aiming) { Update(); return; } - - foreach (Vec3U16 pos in lastGlass) { - if (!p.level.IsValidPos(pos)) continue; - p.RevertBlock(pos.X, pos.Y, pos.Z); - } - task.Repeating = false; - } - - void Update() { - Player p = player; - Vec3F32 dir = DirUtils.GetDirVector(p.Rot.RotY, p.Rot.HeadX); - ushort x = (ushort)Math.Round(p.Pos.BlockX + dir.X * 3); - ushort y = (ushort)Math.Round(p.Pos.BlockY + dir.Y * 3); - ushort z = (ushort)Math.Round(p.Pos.BlockZ + dir.Z * 3); + weapon.OnActivated(p.Rot.RotY, p.Rot.HeadX, block); + } + + static void PlayerClickCallback(Player p, MouseButton btn, MouseAction action, + ushort yaw, ushort pitch, byte entity, + ushort x, ushort y, ushort z, TargetBlockFace face) { + Weapon weapon = p.weapon; + if (weapon == null || action != MouseAction.Pressed) return; + + if (!(btn == MouseButton.Left || btn == MouseButton.Right)) return; + if (!p.level.Config.Guns) { weapon.Disable(); return; } + + BlockID held = p.RawHeldBlock; + if (!CommandParser.IsBlockAllowed(p, "use", held)) return; + weapon.OnActivated((byte)(yaw >> 8), (byte)(pitch >> 8), held); + } + + protected static Player PlayerAt(Player p, Vec3U16 pos, bool skipSelf) { + Player[] players = PlayerInfo.Online.Items; + foreach (Player pl in players) { + if (pl.level != p.level) continue; + if (p == pl && skipSelf) continue; + + if (Math.Abs(pl.Pos.BlockX - pos.X) <= 1 + && Math.Abs(pl.Pos.BlockY - pos.Y) <= 1 + && Math.Abs(pl.Pos.BlockZ - pos.Z) <= 1) + { + return pl; + } + } + return null; + } + } + + public class AmmunitionData { + public BlockID block; + public Vec3U16 pos, start; + public Vec3F32 dir; + public bool moving = true; + + // positions of all currently visible "trailing" blocks + public List visible = new List(); + // position of all blocks this ammunition has touched/gone through + public List all = new List(); + public int iterations; + + public Vec3U16 PosAt(int i) { + Vec3U16 target; + target.X = (ushort)Math.Round(start.X + (double)(dir.X * i)); + target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i)); + target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i)); + return target; + } + } + + /// Manages the glass box around the player. Adjusts based on where player is looking. + internal sealed class AimBox { + + Player player; + List lastGlass = new List(); + List curGlass = new List(); + + public void Hook(Player p) { + player = p; + SchedulerTask task = new SchedulerTask(AimCallback, null, TimeSpan.Zero, true); + p.CriticalTasks.Add(task); + } + + void AimCallback(SchedulerTask task) { + Player p = player; + if (p.aiming) { Update(); return; } + + foreach (Vec3U16 pos in lastGlass) { + if (!p.level.IsValidPos(pos)) continue; + p.RevertBlock(pos.X, pos.Y, pos.Z); + } + task.Repeating = false; + } + + void Update() { + Player p = player; + Vec3F32 dir = DirUtils.GetDirVector(p.Rot.RotY, p.Rot.HeadX); + ushort x = (ushort)Math.Round(p.Pos.BlockX + dir.X * 3); + ushort y = (ushort)Math.Round(p.Pos.BlockY + dir.Y * 3); + ushort z = (ushort)Math.Round(p.Pos.BlockZ + dir.Z * 3); - int dx = Math.Sign(dir.X) >= 0 ? 1 : -1, dz = Math.Sign(dir.Z) >= 0 ? 1 : -1; - Check(p.level, x, y, z ); - Check(p.level, x + dx, y, z ); - Check(p.level, x, y, z + dz); - Check(p.level, x + dx, y, z + dz); + int dx = Math.Sign(dir.X) >= 0 ? 1 : -1, dz = Math.Sign(dir.Z) >= 0 ? 1 : -1; + Check(p.level, x, y, z ); + Check(p.level, x + dx, y, z ); + Check(p.level, x, y, z + dz); + Check(p.level, x + dx, y, z + dz); - // Revert all glass blocks now not in the ray from the player's direction - for (int i = 0; i < lastGlass.Count; i++) { - Vec3U16 pos = lastGlass[i]; - if (curGlass.Contains(pos)) continue; - - if (p.level.IsValidPos(pos)) - p.RevertBlock(pos.X, pos.Y, pos.Z); - lastGlass.RemoveAt(i); i--; - } + // Revert all glass blocks now not in the ray from the player's direction + for (int i = 0; i < lastGlass.Count; i++) { + Vec3U16 pos = lastGlass[i]; + if (curGlass.Contains(pos)) continue; + + if (p.level.IsValidPos(pos)) + p.RevertBlock(pos.X, pos.Y, pos.Z); + lastGlass.RemoveAt(i); i--; + } - // Place the new glass blocks that are in the ray from the player's direction - foreach (Vec3U16 pos in curGlass) { - if (lastGlass.Contains(pos)) continue; - lastGlass.Add(pos); - p.SendBlockchange(pos.X, pos.Y, pos.Z, Block.Glass); - } - curGlass.Clear(); - } - - void Check(Level lvl, int x, int y, int z) { - Vec3U16 pos = new Vec3U16((ushort)x, (ushort)(y - 1), (ushort)z); - if (lvl.IsAirAt(pos.X, pos.Y, pos.Z)) curGlass.Add(pos); - - pos.Y++; - if (lvl.IsAirAt(pos.X, pos.Y, pos.Z)) curGlass.Add(pos); - } - } + // Place the new glass blocks that are in the ray from the player's direction + foreach (Vec3U16 pos in curGlass) { + if (lastGlass.Contains(pos)) continue; + lastGlass.Add(pos); + p.SendBlockchange(pos.X, pos.Y, pos.Z, Block.Glass); + } + curGlass.Clear(); + } + + void Check(Level lvl, int x, int y, int z) { + Vec3U16 pos = new Vec3U16((ushort)x, (ushort)(y - 1), (ushort)z); + if (lvl.IsAirAt(pos.X, pos.Y, pos.Z)) curGlass.Add(pos); + + pos.Y++; + if (lvl.IsAirAt(pos.X, pos.Y, pos.Z)) curGlass.Add(pos); + } + } } diff --git a/MCGalaxy/Generator/Foliage/Tree.cs b/MCGalaxy/Generator/Foliage/Tree.cs index bedb1bf20..da433ba71 100644 --- a/MCGalaxy/Generator/Foliage/Tree.cs +++ b/MCGalaxy/Generator/Foliage/Tree.cs @@ -35,7 +35,7 @@ namespace MCGalaxy.Generator.Foliage { public virtual int MinSize { get { return 3; } } /// Maximum allowed size (usually means height) for this tree. - public virtual int MaxSize { get { return 100; } } + public virtual int MaxSize { get { return 4096; } } /// Estimated the maximum number of blocks affected by this tree. public abstract int EstimateBlocksAffected(); diff --git a/MCGalaxy/Levels/Level.Blocks.cs b/MCGalaxy/Levels/Level.Blocks.cs index 2f6d8696c..05e06ac25 100644 --- a/MCGalaxy/Levels/Level.Blocks.cs +++ b/MCGalaxy/Levels/Level.Blocks.cs @@ -180,6 +180,8 @@ namespace MCGalaxy { return block >= Block.Water && block <= Block.StillLava; } + /// Returns the AccessController denying the player from changing blocks at the given coordinates. + /// If no AccessController denies the player, returns null. public AccessController CanAffect(Player p, ushort x, ushort y, ushort z) { Zone[] zones = Zones.Items; if (zones.Length == 0) goto checkRank; // TODO: avoid this @@ -216,11 +218,11 @@ namespace MCGalaxy { public bool CheckAffect(Player p, ushort x, ushort y, ushort z, BlockID old, BlockID block) { if (!p.group.Blocks[old] || !p.group.Blocks[block]) return false; - AccessController denied = CanAffect(p, x, y, z); - if (denied == null) return true; + AccessController denier = CanAffect(p, x, y, z); + if (denier == null) return true; if (p.lastAccessStatus < DateTime.UtcNow) { - denied.CheckDetailed(p); + denier.CheckDetailed(p); p.lastAccessStatus = DateTime.UtcNow.AddSeconds(2); } return false; @@ -234,6 +236,13 @@ namespace MCGalaxy { } } + /// Sends a block update packet to all players in this level. + /// The block sent is the current block at the given coordinates. + public void BroadcastRevert(ushort x, ushort y, ushort z) { + BlockID block = GetBlock(x, y, z); + if (block != Block.Invalid) BroadcastChange(x, y, z, block); + } + public void Blockchange(Player p, ushort x, ushort y, ushort z, BlockID block) { if (DoBlockchange(p, x, y, z, block) == 2) BroadcastChange(x, y, z, block);