Boss projectile not firing in multiplayer

MaloLeNono

Terrarian
I'm trying to make sure the randomness in my boss is synced with other players. One of the things I'm synchronising is that whenever the boss gets hit, it has a 1 in 5 chance to fire off a homing projectile at the player. Here's how I'm trying to sync it by calculating it on the server:
C#:
public override void OnHitByProjectile(Projectile projectile, NPC.HitInfo hit, int damageDone)
{
    for (int i = 0; i < 4; i++)
    {
        Dust.NewDust(new Vector2(NPC.position.X, NPC.position.Y), NPC.width, NPC.height, DustID.ShimmerSpark, Scale: 4);
    }

    if (Main.netMode != NetmodeID.MultiplayerClient)
    {
        if (Main.rand.NextBool(projectileChance))
        {
            Player player = Main.player[NPC.target];
            Vector2 direction = player.Center - NPC.Center;
            direction.Normalize();
            Vector2 velocity = direction;
            IEntitySource source = NPC.GetSource_FromAI();
            if (Main.netMode != NetmodeID.Server)
                SoundEngine.PlaySound(ModDeTchass.LudoEi); // Placeholder
            Projectile.NewProjectile(source, NPC.Center, velocity, ModContent.ProjectileType<TchassProjectile>(), 300, 5);
        }
    }
}
C#:
public override void OnHitByProjectile(Projectile projectile, NPC.HitInfo hit, int damageDone)
{
    for (int i = 0; i < 4; i++)
    {
        Dust.NewDust(new Vector2(NPC.position.X, NPC.position.Y), NPC.width, NPC.height, DustID.ShimmerSpark, Scale: 4);
    }

    if (Main.netMode != NetmodeID.MultiplayerClient)
    {
        if (Main.rand.NextBool(projectileChance))
        {
            Player player = Main.player[NPC.target];
            Vector2 direction = player.Center - NPC.Center;
            direction.Normalize();
            Vector2 velocity = direction;
            IEntitySource source = NPC.GetSource_FromAI();
            if (Main.netMode != NetmodeID.Server)
                SoundEngine.PlaySound(ModDeTchass.LudoEi); // Placeholder
            Projectile.NewProjectile(source, NPC.Center, velocity, ModContent.ProjectileType<TchassProjectile>(), 300, 5);
        }
    }
}
This works fine in singleplayer, but the projectiles do not fire in multiplayer.

Here's the entire boss script and projectile, if needed.
C#:
using Microsoft.Xna.Framework;
using ModDeTchass.Common.Systems;
using ModDeTchass.Content.Items.Guns;
using ModDeTchass.Content.Items.Materials;
using ModDeTchass.Content.Projectiles;
using Terraria;
using Terraria.Audio;
using Terraria.DataStructures;
using Terraria.GameContent.ItemDropRules;
using Terraria.ID;
using Terraria.ModLoader;

namespace ModDeTchass.Content.NPCs.Bosses
{
    [AutoloadBossHead]
    class BFDTCHS : ModNPC
    {
        bool phase2 = false;
        int projectileChance = 5;

        public override void SetStaticDefaults()
        {
            NPCID.Sets.MPAllowedEnemies[Type] = true;
            NPCID.Sets.BossBestiaryPriority.Add(Type);
        }

        public override void SetDefaults()
        {
            NPC.netAlways = true;
            NPC.width = 450;
            NPC.height = 377;
            NPC.damage = 9999;
            NPC.defense = 0;
            NPC.lifeMax = 500000;
            NPC.HitSound = ModDeTchass.PiedsOursin;
            NPC.DeathSound = ModDeTchass.LudoEi;
            NPC.knockBackResist = 0;
            NPC.aiStyle = -1;
            NPC.boss = true;
            NPC.noGravity = true;
            NPC.noTileCollide = true;
            NPC.SpawnWithHigherTime(10);
            NPC.npcSlots = 10f;
            if (!Main.dedServ)
            {
                Music = MusicLoader.GetMusicSlot(Mod, "Content/Sounds/Music/bfdtchsSong");
            }
        }

        public override Color? GetAlpha(Color drawColor)
        {
            return Color.White;
        }

        public override void AI()
        {
            if (NPC.target < 0 || NPC.target == 255 || Main.player[NPC.target].dead || !Main.player[NPC.target].active)
            {
                NPC.TargetClosest();
            }

            Player player = Main.player[NPC.target];

            if (player.dead)
            {
                NPC.noTileCollide = true;
                NPC.velocity.Y -= 50;
                NPC.EncourageDespawn(10);
                return;
            }

            Vector2 direction = player.Center - NPC.Center;
            direction.Normalize();
            float speed = 7f;

            if (NPC.life < NPC.lifeMax / 2 && !phase2 && Main.netMode != NetmodeID.MultiplayerClient)
            {
                NPC.netUpdate = true;
                speed *= 1.5f;
                projectileChance = 2;
                SoundEngine.PlaySound(SoundID.Roar, NPC.position);
                phase2 = true;
            }

            NPC.velocity = direction * speed;

            if (Main.netMode == NetmodeID.Server)
            {
                NetMessage.SendData(MessageID.SyncNPC, number: NPC.whoAmI);
            }
        }

        public override void OnHitByProjectile(Projectile projectile, NPC.HitInfo hit, int damageDone)
        {
            for (int i = 0; i < 4; i++)
            {
                Dust.NewDust(new Vector2(NPC.position.X, NPC.position.Y), NPC.width, NPC.height, DustID.ShimmerSpark, Scale: 4);
            }

            if (Main.netMode != NetmodeID.MultiplayerClient)
            {
                if (Main.rand.NextBool(projectileChance))
                {
                    Player player = Main.player[NPC.target];
                    Vector2 direction = player.Center - NPC.Center;
                    direction.Normalize();
                    Vector2 velocity = direction;
                    IEntitySource source = NPC.GetSource_FromAI();
                    if (Main.netMode != NetmodeID.Server)
                        SoundEngine.PlaySound(ModDeTchass.LudoEi); // Placeholder
                    Projectile.NewProjectile(source, NPC.Center, velocity, ModContent.ProjectileType<TchassProjectile>(), 300, 5);
                }
            }
        }

        public override void OnHitByItem(Player player, Item item, NPC.HitInfo hit, int damageDone)
        {
            for (int i = 0; i < 4; i++)
            {
                Dust.NewDust(new Vector2(NPC.position.X, NPC.position.Y), NPC.width, NPC.height, DustID.ShimmerSpark, Scale: 4);
            }

            if (Main.netMode != NetmodeID.MultiplayerClient)
            {
                if (Main.rand.NextBool(projectileChance))
                {
                    Vector2 direction = player.Center - NPC.Center;
                    direction.Normalize();
                    Vector2 velocity = direction;
                    IEntitySource source = NPC.GetSource_FromAI();
                    if (Main.netMode != NetmodeID.Server)
                        SoundEngine.PlaySound(ModDeTchass.LudoEi); // Placeholder
                    Projectile.NewProjectile(source, NPC.Center, velocity, ModContent.ProjectileType<TchassProjectile>(), 300, 5);
                }
            }
        }

        public override void OnKill()
        {
            NPC.SetEventFlagCleared(ref DownedBossSystem.downedBossDeTchass, -1);
        }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<SuperTchass>(), 1, 20, 30));
            npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<M61Vulcan>(), 1, 1, 1));
            npcLoot.Add(ItemDropRule.Common(ItemID.PlatinumCoin, 1, 5, 10));
        }
    }
}
C#:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.Audio;
using Terraria.GameContent;
using Terraria.ID;
using Terraria.ModLoader;

namespace ModDeTchass.Content.Projectiles
{
    class TchassProjectile : ModProjectile
    {
        public override void SetStaticDefaults()
        {
            ProjectileID.Sets.TrailCacheLength[Projectile.type] = 20;
            ProjectileID.Sets.TrailingMode[Projectile.type] = 0;
        }

        public override void SetDefaults()
        {
            Projectile.width = 60;
            Projectile.height = 30;
            Projectile.aiStyle = -1;
            Projectile.friendly = false;
            Projectile.hostile = true;
            Projectile.DamageType = DamageClass.Magic;
            Projectile.penetrate = 1;
            Projectile.timeLeft = Main.rand.Next(90, 120);
            Projectile.alpha = 0;
            Projectile.light = 1f;
            Projectile.ignoreWater = true;
            Projectile.tileCollide = false;
            Projectile.extraUpdates = 1;
            AIType = ProjectileID.Bullet;
        }

        public override void AI()
        {
            Player player = Main.player[Player.FindClosest(Projectile.Center, Projectile.width, Projectile.height)];

            float speed = 9f;
            Vector2 direction = player.Center - Projectile.Center;
            direction.Normalize();
            Projectile.velocity = direction * speed;
            Projectile.rotation = Projectile.velocity.ToRotation() - 90;
        }

        public override bool PreDraw(ref Color lightColor)
        {
            Texture2D texture = TextureAssets.Projectile[Type].Value;

            Vector2 drawOrigin = new Vector2(texture.Width * 0.5f, Projectile.height * 0.5f);
            for (int k = Projectile.oldPos.Length - 1; k > 0; k--)
            {
                Vector2 drawPos = (Projectile.oldPos[k] - Main.screenPosition) + drawOrigin + new Vector2(0f, Projectile.gfxOffY);
                Color color = Projectile.GetAlpha(lightColor) * ((Projectile.oldPos.Length - k) / (float)Projectile.oldPos.Length);
                Main.EntitySpriteDraw(texture, drawPos, null, color, Projectile.rotation, drawOrigin, Projectile.scale, SpriteEffects.None, 0);
            }

            return true;
        }

        public override void OnKill(int timeLeft)
        {
            SoundEngine.PlaySound(SoundID.Item10, Projectile.position);
            for (int i = 0; i < 5; i++)
            {
                Dust.NewDust(Projectile.position, Projectile.width, Projectile.height, DustID.ShimmerSpark, Scale: 2);
            }
        }
    }
}

Any help?
 
ModNPC.OnHitByItem() is only called for the player that was using the item, never the server. Though this isn't specified for ModNPC.OnHitByProjectile(), I imagine it's the same. This causes a contradiction in multiplayer, causing a projectile to never be spawned for anyone. Since what you have for these 2 functions are about the same, try using ModNPC.HitEffect() in place of both of them. If this is not an option, you may have to use ModPacket to indicate who damaged the NPC.
 
ModNPC.OnHitByItem() is only called for the player that was using the item, never the server. Though this isn't specified for ModNPC.OnHitByProjectile(), I imagine it's the same. This causes a contradiction in multiplayer, causing a projectile to never be spawned for anyone. Since what you have for these 2 functions are about the same, try using ModNPC.HitEffect() in place of both of them. If this is not an option, you may have to use ModPacket to indicate who damaged the NPC.
Thanks!
 
ModNPC.OnHitByItem() is only called for the player that was using the item, never the server. Though this isn't specified for ModNPC.OnHitByProjectile(), I imagine it's the same. This causes a contradiction in multiplayer, causing a projectile to never be spawned for anyone. Since what you have for these 2 functions are about the same, try using ModNPC.HitEffect() in place of both of them. If this is not an option, you may have to use ModPacket to indicate who damaged the NPC.
Hey, I'm having another issue now that the sound that is supposed to play isn't playing when a projectile is fired in multiplayer. Here's my new HitEffect() code:

C#:
public override void HitEffect(NPC.HitInfo hit)
{
    for (int i = 0; i < 4; i++)
    {
        Dust.NewDust(new Vector2(NPC.position.X, NPC.position.Y), NPC.width, NPC.height, DustID.ShimmerSpark, Scale: 4);
    }

    if (Main.netMode != NetmodeID.MultiplayerClient)
    {
        if (Main.rand.NextBool(projectileChance))
        {
            Player player = Main.player[NPC.target];
            Vector2 direction = player.Center - NPC.Center;
            direction.Normalize();
            Vector2 velocity = direction;
            IEntitySource source = NPC.GetSource_FromAI();
            if (Main.netMode != NetmodeID.Server)
                SoundEngine.PlaySound(ModDeTchass.LudoEi, NPC.position); // Placeholder
            Projectile.NewProjectile(source, NPC.Center, velocity, ModContent.ProjectileType<TchassProjectile>(), 300, 5);
        }
    }
}
 
Back
Top Bottom