Solved Making zombies spawn during the day

Discussion in 'Spigot Plugin Development' started by dadus33, May 30, 2016.

Thread Status:
Not open for further replies.
  1. The title says it all. I want to make zombies spawn during the day, with an altered mechanics (that is, they will spawn less often than during the night). Also, I don't want to make it by "forcing" the spawn. That is, using a scheduler or something to check whether it's day or not and spawn the zombies at random positions in loaded chunks. I want it to work exactly like the way minecraft spawn entities by default, but I honestly don't know where that is handled inside NMS (or if there's an implementation of it in the spigot API, which I really doubt). Thanks!
     
  2. Simply cancelling the ECE would prevent zombies from lighting on fire in the day, while checking if the time is 0 or more but less than 12300 (the time of night) would determine whether or not it is day.

    In my opinion, the cleanest way to allow zombies to spawn during the day is by using NMS. What I would do in this situation is make an implementation of a Minecraft_Zombie, and override the canSpawn method to prevent checking the light level.
     
    #2 inksquid_, May 30, 2016
    Last edited: May 30, 2016
    • Agree Agree x 1
  3. Well thanks for the reply and maybe I didn't make that clear, but I am already using a custom zombie. I already managed to override it's behavior and make it immune to daylight, but didn't quiet make them spawnable at daytime yet. Also, the canSpawn method found in EntityInsentient seems to only be checking whether the space is suitable for the entity to spawn, not necessarily if it's in daylight or not.
    Code (Text):
        public boolean canSpawn() {
            return this.world.a(this.getBoundingBox(), this) && this.world.getCubes(this, this.getBoundingBox()).isEmpty() && !this.world.containsLiquid(this.getBoundingBox());
        }
    Above code extracted right from EntityInsentient class.
     
  4. Sorry to bump this so quick, but I'm kinda desperate in getting an answer....
     
  5. They would burn.
     
    • Funny Funny x 2
  6. That's why I told him to cancel the EntityCombustEvent if the entity is a zombie
     
  7. Oh god, why don't you understand they don't? I made a custom zombie and overwritten that method (which, just FYI is m()). They DON'T burn. I already checked that. But they don't spawn... That's the issue (only with spawn eggs or during the night).
     
  8. Finally, I managed to solve it!
    For anyone interested, here's what I did:
    I looked inside the SpawnerCreature NMS class (which I discovered handles mob spawning in the world) and saw what checks it did before spawning an entity.
    This is a fairly simple piece of code (that's in 1.8.8):
    Code (Text):
    if(entityinsentient.bR() && entityinsentient.canSpawn())
    There, if we take a look at EntityInsentient#canSpawn(), we see all it does is it checks if the POSITION of the designated spawn loacation is suitable for the mob (if it spawns in water/lava, if it spawns in a place too short for the mob or in a wall, etc.) so we shouldn't touch that. However, the obfuscated bR() method is overriden by almost all clases that extend EntityLiving. If we take a look, for instance, at EntityMonster, which is the superclass of EntityZombie, we see it does the following:
    Code (Text):
        public boolean bR() {
            return this.world.getDifficulty() != EnumDifficulty.PEACEFUL && this.n_() && super.bR();
        }
    So it will return true as long as the difficulty is not peacefull and n_() returns true (the super.bR() is meant to also do the less particular checks, but we don't actually care about it as we know we want to spawn it no mater the opther factors). And, finally, the n_() method checks the light level of the zombie like this:
    Code (Text):
        protected boolean n_() {
            BlockPosition blockposition = new BlockPosition(this.locX, this.getBoundingBox().b, this.locZ);
            if(this.world.b(EnumSkyBlock.SKY, blockposition) > this.random.nextInt(32)) {
                return false;
            } else {
                int i = this.world.getLightLevel(blockposition);
                if(this.world.R()) {
                    int j = this.world.ab();
                    this.world.c(10);
                    i = this.world.getLightLevel(blockposition);
                    this.world.c(j);
                }

                return i <= this.random.nextInt(8);
            }
        }
    Therefore, changing the method n_() so it always returns true should solve the issue, but I took things one step further by making the whole bR() method return true. This apparently solves some issues making zombies spawn more abundantly, although simply making n_() return true will also work.
    PS: Some of the methods used in the EntityZombie class use the super keyword to refer to some other methods in their superclasses. Therefore, if you extend EndityZombie in your custom class, the super keyword will refer to the EntityZombie class, making it so if the method you want to call is also found in EntityZombie, it would be run instead of the one in the EntityZombie's super class. Example: The mnethod m() in your class calls super.m() (which, called from the actual EntityZombie object, would call the method on the EntityInsentient object), but in your case it will just run the original m() method from EntityZombie, making it impossible for you to override it's behavior. Therefore, ion such cases, all you can possibly do is copy the whole code from EntityZombie and create a class that contains that code and extends EntityMonster. It's a bit harder, but it will allow you to override any single method you want in the class.

    Hope this helped others looking for ways to do this. Thanks for the help anyways @inksquid_ and @KingLinux01
     
    • Useful Useful x 5
Thread Status:
Not open for further replies.