Esempio n. 1
0
        private void OnChangePlayerModeMessage(IPlayer fromPlayer, ChangePlayerModePacket plrmode)
        {
            IServerPlayer plr = fromPlayer as IServerPlayer;

            bool freeMoveAllowed  = plr.HasPrivilege(Privilege.freemove);
            bool gameModeAllowed  = plr.HasPrivilege(Privilege.gamemode);
            bool pickRangeAllowed = plr.HasPrivilege(Privilege.pickingrange);

            if (plrmode.axisLock != null)
            {
                fromPlayer.WorldData.FreeMovePlaneLock = (EnumFreeMovAxisLock)plrmode.axisLock;
            }
            if (plrmode.pickingRange != null && pickRangeAllowed)
            {
                fromPlayer.WorldData.PickingRange = (float)plrmode.pickingRange;
            }
            if (plrmode.fly != null)
            {
                fromPlayer.WorldData.FreeMove = (bool)plrmode.fly && freeMoveAllowed;
            }
            if (plrmode.noclip != null)
            {
                fromPlayer.WorldData.NoClip = (bool)plrmode.noclip && freeMoveAllowed;
            }
        }
Esempio n. 2
0
        public void GiveKit(IServerPlayer player, string kitName)
        {
            var kit = GetLoadedKits().kits.Find(
                x => x.name == kitName
                );

            if (kit != null)
            {
                if (!player.HasPrivilege(Privilege.ignoreCooldowns))
                {
                    var cooldown =
                        GetCooldownManager().GetCooldown(player.PlayerUID, kitName);
                    if (cooldown > 0)
                    {
                        player.SendErr($"You must wait {cooldown} sec. to use this kit");
                        return;
                    }
                }
                if (!player.HasPrivilege($"{Privilege.kit}.{kit.name}"))
                {
                    player.SendErr($"You don't have access to kit {kit.name}");
                    return;
                }
                player.SendOk($"Giving kit {kit.name}");
                // TODO: if inventory full, should use player.Entity.World.SpawnItemEntity();
                kit.items.ForEach(
                    item => player.GiveItemStack(item.type, item.code, item.amount)
                    );
                GetCooldownManager().SetCooldown(player.PlayerUID, kitName, kit.delay);
            }
            else
            {
                player.SendErr($"{kitName} not found");
            }
        }
Esempio n. 3
0
 public List <string> GetAccessedKits(IServerPlayer player)
 {
     return(GetLoadedKits()
            .kits
            .Where(kit => player.HasPrivilege($"{Privilege.kit}.{kit.name}"))
            .Select(kit => kit.name)
            .ToList());
 }
        private void impactOnEntity(Entity entity)
        {
            if (!Alive)
            {
                return;
            }

            EntityPos pos = SidedPos;

            IServerPlayer fromPlayer = null;

            if (FiredBy is EntityPlayer)
            {
                fromPlayer = (FiredBy as EntityPlayer).Player as IServerPlayer;
            }

            bool targetIsPlayer   = entity is EntityPlayer;
            bool targetIsCreature = entity is EntityAgent;
            bool canDamage        = true;

            ICoreServerAPI sapi = World.Api as ICoreServerAPI;

            if (fromPlayer != null)
            {
                if (targetIsPlayer && (!sapi.Server.Config.AllowPvP || !fromPlayer.HasPrivilege("attackplayers")))
                {
                    canDamage = false;
                }
                if (targetIsCreature && !fromPlayer.HasPrivilege("attackcreatures"))
                {
                    canDamage = false;
                }
            }

            msCollide = World.ElapsedMilliseconds;
            World.PlaySoundAt(new AssetLocation("sounds/arrow-impact"), this, null, false, 24);

            if (canDamage)
            {
                float dmg = Damage;
                dmg *= FiredBy.Stats.GetBlended("rangedWeaponsDamage");

                bool didDamage = entity.ReceiveDamage(new DamageSource()
                {
                    Source       = EnumDamageSource.Entity,
                    SourceEntity = FiredBy == null ? this : FiredBy,
                    Type         = EnumDamageType.PiercingAttack
                }, dmg);

                float kbresist = entity.Properties.KnockbackResistance;
                entity.SidedPos.Motion.Add(kbresist * pos.Motion.X * Weight, kbresist * pos.Motion.Y * Weight, kbresist * pos.Motion.Z * Weight);

                int leftDurability = ProjectileStack == null ? 1 : ProjectileStack.Attributes.GetInt("durability", 1);

                if (World.Rand.NextDouble() < DropOnImpactChance && leftDurability > 0)
                {
                    pos.Motion.Set(0, 0, 0);
                }
                else
                {
                    Die();
                }

                if (FiredBy is EntityPlayer && didDamage)
                {
                    World.PlaySoundFor(new AssetLocation("sounds/player/projectilehit"), (FiredBy as EntityPlayer).Player, false, 24);
                }
            }
            else
            {
                pos.Motion.Set(0, 0, 0);
            }
        }
Esempio n. 5
0
        private void CmdEditServer(IServerPlayer player, int groupId, CmdArgs args)
        {
            this.fromPlayer = player;
            this.groupId    = groupId;

            if (!CanUseWorldEdit(player, true))
            {
                return;
            }

            this.workspace = GetOrCreateWorkSpace(player);


            BlockPos centerPos             = player.Entity.Pos.AsBlockPos;
            IPlayerInventoryManager plrInv = player.InventoryManager;
            ItemStack stack = plrInv.ActiveHotbarSlot.Itemstack;


            if (args.Length == 0)
            {
                Bad("No arguments supplied. Check the wiki for help, or did you mean to type .we?");
                return;
            }

            string cmd = args.PopWord();


            if ((cmd == "tr" || cmd == "tsx" || cmd == "tsy" || cmd == "tsz") && args.Length > 0)
            {
                double val = 0;
                if (double.TryParse(args[0], NumberStyles.Any, GlobalConstants.DefaultCultureInfo, out val))
                {
                    if (val > 50 && workspace.serverOverloadProtection)
                    {
                        Bad("Operation rejected. Server overload protection is on. Might kill the server or client to use such a large brush (max is 50).");

                        SendPlayerWorkSpace(fromPlayer.PlayerUID);

                        return;
                    }
                }
            }

            switch (cmd)
            {
            case "impr":
                int angle = 90;

                if (args.Length > 0)
                {
                    if (!int.TryParse(args[0], NumberStyles.Any, GlobalConstants.DefaultCultureInfo, out angle))
                    {
                        Bad("Invalid Angle (not a number)");
                        break;
                    }
                }
                if (angle < 0)
                {
                    angle += 360;
                }

                if (angle != 0 && angle != 90 && angle != 180 && angle != 270)
                {
                    Bad("Invalid Angle, allowed values are -270, -180, -90, 0, 90, 180 and 270");
                    break;
                }

                workspace.ImportAngle = angle;

                Good("Ok, set rotation to " + angle + " degrees");

                break;

            case "impflip":
                workspace.ImportFlipped = !workspace.ImportFlipped;

                Good("Ok, import data flip " + (workspace.ImportFlipped ? "on" : "off"));

                break;


            case "mcopy":
                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Please mark start and end position");
                    break;
                }

                workspace.clipboardBlockData = CopyArea(workspace.StartMarker, workspace.EndMarker);
                Good(Lang.Get("{0} blocks and {1} entities copied", workspace.clipboardBlockData.BlockIds.Count, workspace.clipboardBlockData.EntitiesUnpacked.Count));
                break;

            case "mposcopy":
                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Please mark start and end position");
                    break;
                }

                BlockPos s = workspace.StartMarker;
                BlockPos e = workspace.EndMarker;

                serverChannel.SendPacket(new CopyToClipboardPacket()
                {
                    Text = string.Format("/we mark {0} {1} {2} {3} {4} {5}", s.X, s.Y, s.Z, e.X, e.Y, e.Z)
                }, player);

                break;

            case "mpaste":
                if (workspace.clipboardBlockData == null)
                {
                    Bad("No copied block data to paste");
                    break;
                }

                PasteBlockData(workspace.clipboardBlockData, workspace.StartMarker, EnumOrigin.StartPos);
                Good(workspace.clipboardBlockData.BlockIds.Count + " blocks pasted");
                break;


            case "cpinfo":
                if (workspace.clipboardBlockData == null)
                {
                    Bad("No schematic in the clipboard");
                    break;
                }

                workspace.clipboardBlockData.Init(workspace.revertableBlockAccess);
                workspace.clipboardBlockData.LoadMetaInformationAndValidate(workspace.revertableBlockAccess, workspace.world, "(from clipboard)");

                string sides = "";
                for (int i = 0; i < workspace.clipboardBlockData.PathwayStarts.Length; i++)
                {
                    if (sides.Length > 0)
                    {
                        sides += ",";
                    }
                    sides += workspace.clipboardBlockData.PathwaySides[i].Code + " (" + workspace.clipboardBlockData.PathwayOffsets[i].Length + " blocks)";
                }
                if (sides.Length > 0)
                {
                    sides = "Found " + workspace.clipboardBlockData.PathwayStarts.Length + " pathways: " + sides;
                }

                Good("{0} blocks in clipboard. {1}", workspace.clipboardBlockData.BlockIds.Count, sides);
                break;


            case "block":
                if (stack == null || stack.Class == EnumItemClass.Item)
                {
                    Bad("Please put the desired block in your active hotbar slot");
                    return;
                }

                sapi.World.BlockAccessor.SetBlock(stack.Id, centerPos.DownCopy());

                Good("Block placed");

                break;


            case "relight":
                workspace.DoRelight = (bool)args.PopBool(true);
                workspace.revertableBlockAccess.Relight = workspace.DoRelight;
                Good("Block relighting now " + ((workspace.DoRelight) ? "on" : "off"));
                break;

            case "sovp":

                if (args.Length > 0)
                {
                    if (!fromPlayer.HasPrivilege(Privilege.controlserver))
                    {
                        Bad("controlserver privilege required to change server overload protection flag");
                        break;
                    }
                    workspace.serverOverloadProtection = (bool)args.PopBool(true);
                }

                Good("Server overload protection " + (workspace.serverOverloadProtection ? "on" : "off"));
                break;

            case "undo":
                HandleHistoryChange(args, false);
                break;

            case "redo":
                HandleHistoryChange(args, true);
                break;


            case "on":
                Good("World edit tools now enabled");
                workspace.ToolsEnabled = true;
                workspace.ResendBlockHighlights(this);
                break;


            case "off":
                Good("World edit tools now disabled");
                workspace.ToolsEnabled = false;
                workspace.ResendBlockHighlights(this);
                break;


            case "rebuildrainmap":
                if (!player.HasPrivilege(Privilege.controlserver))
                {
                    Bad("You lack the controlserver privilege to rebuild the rain map.");
                    return;
                }

                Good("Ok, rebuilding rain map on all loaded chunks, this may take some time and lag the server");
                int rebuilt = RebuildRainMap();
                Good("Done, rebuilding {0} map chunks", rebuilt);
                break;


            case "t":
                string toolname         = null;
                string suppliedToolname = args.PopAll();

                if (suppliedToolname.Length > 0)
                {
                    int toolId;
                    if (int.TryParse(suppliedToolname, NumberStyles.Any, GlobalConstants.DefaultCultureInfo, out toolId))
                    {
                        if (toolId < 0)
                        {
                            Good("World edit tools now disabled");
                            workspace.ToolsEnabled = false;
                            workspace.ResendBlockHighlights(this);
                            return;
                        }

                        toolname = ToolRegistry.ToolTypes.GetKeyAtIndex(toolId);
                    }
                    else
                    {
                        foreach (string name in ToolRegistry.ToolTypes.Keys)
                        {
                            if (name.ToLowerInvariant().StartsWith(suppliedToolname.ToLowerInvariant()))
                            {
                                toolname = name;
                                break;
                            }
                        }
                    }
                }

                if (toolname == null)
                {
                    Bad("No such tool '" + suppliedToolname + "' registered");
                    break;
                }

                workspace.SetTool(toolname);

                Good(toolname + " tool selected");

                workspace.ToolsEnabled = true;
                workspace.ResendBlockHighlights(this);
                SendPlayerWorkSpace(fromPlayer.PlayerUID);
                break;


            case "tom":
                EnumToolOffsetMode mode = EnumToolOffsetMode.Center;

                try
                {
                    int index = 0;
                    if (args.Length > 0)
                    {
                        index = args[0].ToInt(0);
                    }
                    mode = (EnumToolOffsetMode)index;
                }
                catch (Exception) { }

                workspace.ToolOffsetMode = mode;

                Good("Set tool offset mode " + mode);

                workspace.ResendBlockHighlights(this);
                break;


            case "range":
                float pickingrange = GlobalConstants.DefaultPickingRange;

                if (args.Length > 0)
                {
                    pickingrange = args[0].ToFloat(GlobalConstants.DefaultPickingRange);
                }

                fromPlayer.WorldData.PickingRange = pickingrange;
                fromPlayer.BroadcastPlayerData();

                Good("Picking range " + pickingrange + " set");
                break;


            case "mex":
            case "mexc":

                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Please mark start and end position");
                    break;
                }

                if (args.Length < 1)
                {
                    Bad("Please provide a filename");
                    break;
                }

                ExportArea(args[0], workspace.StartMarker, workspace.EndMarker, cmd == "mexc" ? fromPlayer : null);

                if (args.Length > 1 && args[1] == "c")
                {
                    BlockPos st = workspace.StartMarker;
                    BlockPos en = workspace.EndMarker;
                    serverChannel.SendPacket(new CopyToClipboardPacket()
                    {
                        Text = string.Format("/we mark {0} {1} {2} {3} {4} {5}\n/we mex {6}", st.X, st.Y, st.Z, en.X, en.Y, en.Z, args[0])
                    }, player);
                }
                break;


            case "mre":

                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Please mark start and end position");
                    break;
                }

                Good("Relighting marked area, this may lag the server for a while...");

                sapi.WorldManager.FullRelight(workspace.StartMarker, workspace.EndMarker);

                Good("Ok, relighting complete");
                break;


            case "mgencode":
                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Please mark start and end position");
                    break;
                }

                if (player.CurrentBlockSelection == null)
                {
                    Bad("Please look at a block as well");
                    break;
                }

                GenMarkedMultiblockCode(player);

                break;

            case "imp":

                if (workspace.StartMarker == null)
                {
                    Bad("Please mark a start position");
                    break;
                }

                if (args.Length < 1)
                {
                    Bad("Please provide a filename");
                    break;
                }

                EnumOrigin origin = EnumOrigin.StartPos;

                if (args.Length > 1)
                {
                    try
                    {
                        origin = (EnumOrigin)Enum.Parse(typeof(EnumOrigin), args[1]);
                    }
                    catch (Exception)
                    {
                    }
                }

                ImportArea(args[0], workspace.StartMarker, origin);
                break;


            case "impres":
                if (args.Length == 0)
                {
                    Good("Import item/block resolving currently " + (!sapi.ObjectCache.ContainsKey("donotResolveImports") || (bool)sapi.ObjectCache["donotResolveImports"] == false ? "on" : "off"));
                }
                else
                {
                    bool doreplace = (bool)args.PopBool(ReplaceMetaBlocks);
                    sapi.ObjectCache["donotResolveImports"] = !doreplace;
                    Good("Import item/block resolving now globally " + (doreplace ? "on" : "off"));
                }



                break;


            case "blu":
                BlockLineup(centerPos, args);
                Good("Block lineup created");
                break;


            // Mark start
            case "ms":
                SetStartPos(centerPos);
                break;


            // Mark end
            case "me":
                SetEndPos(centerPos);
                break;

            case "mark":
                workspace.StartMarker = args.PopVec3i(null)?.AsBlockPos;
                workspace.EndMarker   = args.PopVec3i(null)?.AsBlockPos;

                Good("Start and end position marked");
                EnsureInsideMap(workspace.EndMarker);
                workspace.HighlightSelectedArea();
                break;

            case "gn":
                ModifyMarker(BlockFacing.NORTH, args);
                break;

            case "ge":
                ModifyMarker(BlockFacing.EAST, args);
                break;

            case "gs":
                ModifyMarker(BlockFacing.SOUTH, args);
                break;

            case "gw":
                ModifyMarker(BlockFacing.WEST, args);
                break;

            case "gu":
                ModifyMarker(BlockFacing.UP, args);
                break;

            case "gd":
                ModifyMarker(BlockFacing.DOWN, args);
                break;


            case "mr":
                HandleRotateCommand(args.PopInt(), args.PopWord());
                break;


            case "mmirn":
                HandleMirrorCommand(BlockFacing.NORTH, args);
                break;

            case "mmire":
                HandleMirrorCommand(BlockFacing.EAST, args);
                break;

            case "mmirs":
                HandleMirrorCommand(BlockFacing.SOUTH, args);
                break;

            case "mmirw":
                HandleMirrorCommand(BlockFacing.WEST, args);
                break;

            case "mmiru":
                HandleMirrorCommand(BlockFacing.UP, args);
                break;

            case "mmird":
                HandleMirrorCommand(BlockFacing.DOWN, args);
                break;

            case "mrepn":
                HandleRepeatCommand(BlockFacing.NORTH, args);
                break;

            case "mrepe":
                HandleRepeatCommand(BlockFacing.EAST, args);
                break;

            case "mreps":
                HandleRepeatCommand(BlockFacing.SOUTH, args);
                break;

            case "mrepw":
                HandleRepeatCommand(BlockFacing.WEST, args);
                break;

            case "mrepu":
                HandleRepeatCommand(BlockFacing.UP, args);
                break;

            case "mrepd":
                HandleRepeatCommand(BlockFacing.DOWN, args);
                break;

            case "mmu":
                HandleMoveCommand(BlockFacing.UP, args);
                break;

            case "mmd":
                HandleMoveCommand(BlockFacing.DOWN, args);
                break;

            case "mmn":
                HandleMoveCommand(BlockFacing.NORTH, args);
                break;

            case "mme":
                HandleMoveCommand(BlockFacing.EAST, args);
                break;

            case "mms":
                HandleMoveCommand(BlockFacing.SOUTH, args);
                break;

            case "mmw":
                HandleMoveCommand(BlockFacing.WEST, args);
                break;

            case "mmby":
                HandleMoveCommand(null, args);
                break;



            case "smu":
                HandleShiftCommand(BlockFacing.UP, args);
                break;

            case "smd":
                HandleShiftCommand(BlockFacing.DOWN, args);
                break;

            case "smn":
                HandleShiftCommand(BlockFacing.NORTH, args);
                break;

            case "sme":
                HandleShiftCommand(BlockFacing.EAST, args);
                break;

            case "sms":
                HandleShiftCommand(BlockFacing.SOUTH, args);
                break;

            case "smw":
                HandleShiftCommand(BlockFacing.WEST, args);
                break;

            case "smby":
                HandleShiftCommand(null, args);
                break;



            // Marked clear
            case "mc":
            case "clear":
                workspace.StartMarker = null;
                workspace.EndMarker   = null;
                Good("Marked positions cleared");
                workspace.ResendBlockHighlights(this);
                break;

            // Marked info
            case "minfo":
                int sizeX = Math.Abs(workspace.StartMarker.X - workspace.EndMarker.X);
                int sizeY = Math.Abs(workspace.StartMarker.Y - workspace.EndMarker.Y);
                int sizeZ = Math.Abs(workspace.StartMarker.Z - workspace.EndMarker.Z);

                Good(string.Format("Marked area is a cuboid of size {0}x{1}x{2} or a total of {3:n0} blocks", sizeX, sizeY, sizeZ, ((long)sizeX * sizeY * sizeZ)));

                break;

            // Fill marked
            case "mfill":
                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Start marker or end marker not set");
                    return;
                }



                if (stack == null || stack.Class == EnumItemClass.Item)
                {
                    Bad("Please put the desired block in your active hotbar slot");
                    return;
                }

                int filled = FillArea(stack, workspace.StartMarker, workspace.EndMarker);

                Good(filled + " marked blocks placed");
                break;

            case "mclear":
            {
                Bad("No such function, did you mean mdelete?");
                return;
            }

            // Clear marked
            case "mdelete":
            {
                if (workspace.StartMarker == null || workspace.EndMarker == null)
                {
                    Bad("Start marker or end marker not set");
                    return;
                }

                int cleared = FillArea(null, workspace.StartMarker, workspace.EndMarker);
                Good(cleared + " marked blocks removed");
            }
            break;

            // Clear area
            case "delete":
            {
                if (args.Length < 1)
                {
                    Bad("Missing size param");
                    return;
                }

                int size = 0;
                if (!int.TryParse(args[0], NumberStyles.Any, GlobalConstants.DefaultCultureInfo, out size))
                {
                    Bad("Invalide size param");
                    return;
                }

                int height = 20;
                if (args.Length > 1)
                {
                    int.TryParse(args[1], NumberStyles.Any, GlobalConstants.DefaultCultureInfo, out height);
                }


                int cleared = FillArea(null, centerPos.AddCopy(-size, 0, -size), centerPos.AddCopy(size, height, size));

                Good(cleared + " Blocks removed");
            }

            break;

            default:
                args.PushSingle(cmd);
                if (workspace.ToolInstance == null || !workspace.ToolInstance.OnWorldEditCommand(this, args))
                {
                    Bad("No such function " + cmd + ". Maybe wrong tool selected?");
                }

                break;
            }
        }
Esempio n. 6
0
 /// <summary>
 /// Whether or not the player has the privilage to run the command.
 /// </summary>
 /// <param name="player"></param>
 /// <returns></returns>
 public bool HasPrivilege(IServerPlayer player)
 {
     return(player.HasPrivilege(RequiredPrivilege));
 }
Esempio n. 7
0
        bool TryAttackEntity(double impactSpeed)
        {
            if (World is IClientWorldAccessor || World.ElapsedMilliseconds <= msCollide + 250)
            {
                return(false);
            }
            if (impactSpeed <= 0.01)
            {
                return(false);
            }

            EntityPos pos = LocalPos;

            Cuboidd projectileBox = CollisionBox.ToDouble().Translate(ServerPos.X, ServerPos.Y, ServerPos.Z);

            // We give it a bit of extra leeway of 50% because physics ticks can run twice or 3 times in one game tick
            if (ServerPos.Motion.X < 0)
            {
                projectileBox.X1 += 1.5 * ServerPos.Motion.X;
            }
            else
            {
                projectileBox.X2 += 1.5 * ServerPos.Motion.X;
            }
            if (ServerPos.Motion.Y < 0)
            {
                projectileBox.Y1 += 1.5 * ServerPos.Motion.Y;
            }
            else
            {
                projectileBox.Y2 += 1.5 * ServerPos.Motion.Y;
            }
            if (ServerPos.Motion.Z < 0)
            {
                projectileBox.Z1 += 1.5 * ServerPos.Motion.Z;
            }
            else
            {
                projectileBox.Z2 += 1.5 * ServerPos.Motion.Z;
            }

            Entity entity = World.GetNearestEntity(ServerPos.XYZ, 5f, 5f, (e) => {
                if (e.EntityId == this.EntityId || !e.IsInteractable)
                {
                    return(false);
                }

                if (FiredBy != null && e.EntityId == FiredBy.EntityId && World.ElapsedMilliseconds - msLaunch < 500)
                {
                    return(false);
                }

                Cuboidd eBox = e.CollisionBox.ToDouble().Translate(e.ServerPos.X, e.ServerPos.Y, e.ServerPos.Z);

                return(eBox.IntersectsOrTouches(projectileBox));
            });

            if (entity != null)
            {
                IServerPlayer fromPlayer = null;
                if (FiredBy is EntityPlayer)
                {
                    fromPlayer = (FiredBy as EntityPlayer).Player as IServerPlayer;
                }

                bool targetIsPlayer   = entity is EntityPlayer;
                bool targetIsCreature = entity is EntityAgent;
                bool canDamage        = true;

                ICoreServerAPI sapi = World.Api as ICoreServerAPI;
                if (fromPlayer != null)
                {
                    if (targetIsPlayer && (!sapi.Server.Config.AllowPvP || !fromPlayer.HasPrivilege("attackplayers")))
                    {
                        canDamage = false;
                    }
                    if (targetIsCreature && !fromPlayer.HasPrivilege("attackcreatures"))
                    {
                        canDamage = false;
                    }
                }

                msCollide = World.ElapsedMilliseconds;
                World.PlaySoundAt(new AssetLocation("sounds/arrow-impact"), this, null, false, 24);

                if (canDamage)
                {
                    bool didDamage = entity.ReceiveDamage(new DamageSource()
                    {
                        Source = EnumDamageSource.Entity, SourceEntity = FiredBy == null ? this : FiredBy, Type = EnumDamageType.PiercingAttack
                    }, Damage);

                    float kbresist = entity.Properties.KnockbackResistance;
                    entity.LocalPos.Motion.Add(kbresist * pos.Motion.X * Weight, kbresist * pos.Motion.Y * Weight, kbresist * pos.Motion.Z * Weight);

                    int leftDurability = ProjectileStack == null ? 1 : ProjectileStack.Attributes.GetInt("durability", 1);

                    if (World.Rand.NextDouble() < DropOnImpactChance && leftDurability > 0)
                    {
                        pos.Motion.Set(0, 0, 0);
                    }
                    else
                    {
                        Die();
                    }

                    if (FiredBy is EntityPlayer && didDamage)
                    {
                        World.PlaySoundFor(new AssetLocation("sounds/player/projectilehit"), (FiredBy as EntityPlayer).Player, false, 24);
                    }
                }
                else
                {
                    pos.Motion.Set(0, 0, 0);
                }

                return(true);
            }


            return(false);
        }