Solved Mobs

Discussion in 'Plugin Development' started by Scullyking, Apr 15, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    Scullyking

    I have reached a point in a large project I am working on where I haven't got a clue what I'm doing. If anybody could point me to some relevant, up-to-date and good tutorials on these subject matters, that would be great.

    I need to manipulate the behaviours and properties of mobs. I have found a decent looking tutorial by @TeeePeee on overriding mobs, but I need to have multiple types of mobs (such as a weak zombie, a strong zombie with iron armour, and a boss zombie with diamond armour that fires TNT).

    These mobs need to be spawned into the game into very selective areas. For example a single building that is infested with spiders. I would want the spiders to be numerous, but not just keep spawning forever. And the spiders would need to 'know' not to stray too far from the building.

    I understand that these are advanced topics, any help would be awesome.
    Thanks
     
  2. Offline

    mine-care

    Hmm i dont really know any to be honest but with a google search you might find some, Also about fiering tnt's i dont really know but i assume there is a way to disguise a wither to a zombi (as odd as it sounds ) Check out the resource section for more!
     
  3. Offline

    DoppelRR

    @Scullyking
    I can just say NMS NMS NMS. This is where Bukkit reaches its limits. I know the tutorial of TeeePeee to, I would suggest to develop a manual Spawning System, and spawn entities with World#addEntity(<yourentity>).
     
  4. Offline

    Scullyking

    @DoppelRR
    So I could cancel the EntitySpawnEvent and use my own spawning manager. Maybe a hashmap of regions with the type of entity to spawn inside it or something...

    Not too confident on how to create multiple overwrites of an entity though. TeeePeee's tutorial seems to offer one overwrite for all zombies.
     
  5. Offline

    Europia79

    This sounds exactly like a Villager that doesn't stray too far from the Village... Therefore, I would suggest looking at PathfinderGoalMoveThroughVillage... See how they do it... And tweak it to your needs: In this case, something along the lines of a PathfinderGoalMoveThroughArea so-to-speak... where you define the "Area" in question.

    Then add this pathfinder to your entity.

    Code:java
    1.  
    2. public class PathfinderGoalMoveThroughVillage
    3. extends PathfinderGoal
    4. {
    5. private EntityCreature a;
    6. private double b;
    7. private PathEntity c;
    8. private VillageDoor d;
    9. private boolean e;
    10. private List f = Lists.newArrayList();
    11. public PathfinderGoalMoveThroughVillage(EntityCreature paramEntityCreature, double paramDouble, boolean paramBoolean)
    12. {
    13. this.a = paramEntityCreature;
    14. this.b = paramDouble;
    15. this.e = paramBoolean;
    16. a(1);
    17. if (!(paramEntityCreature.getNavigation() instanceof Navigation)) {
    18. throw new IllegalArgumentException("Unsupported mob for MoveThroughVillageGoal");
    19. }
    20. }
    21. public boolean a()
    22. {
    23. f();
    24. if ((this.e) && (this.a.world.w())) {
    25. return false;
    26. }
    27. Village localVillage = this.a.world.ae().getClosestVillage(new BlockPosition(this.a), 0);
    28. if (localVillage == null) {
    29. return false;
    30. }
    31. this.d = a(localVillage);
    32. if (this.d == null) {
    33. return false;
    34. }
    35. Navigation localNavigation = (Navigation)this.a.getNavigation();
    36. boolean bool = localNavigation.g();
    37. localNavigation.b(false);
    38. this.c = localNavigation.a(this.d.d());
    39. localNavigation.b(bool);
    40. if (this.c != null) {
    41. return true;
    42. }
    43. Vec3D localVec3D = RandomPositionGenerator.a(this.a, 10, 7, new Vec3D(this.d.d().getX(), this.d.d().getY(), this.d.d().getZ()));
    44. if (localVec3D == null) {
    45. return false;
    46. }
    47. localNavigation.b(false);
    48. this.c = this.a.getNavigation().a(localVec3D.a, localVec3D.b, localVec3D.c);
    49. localNavigation.b(bool);
    50. return this.c != null;
    51. }
    52. public boolean b()
    53. {
    54. if (this.a.getNavigation().m()) {
    55. return false;
    56. }
    57. float f1 = this.a.width + 4.0F;
    58. return this.a.b(this.d.d()) > f1 * f1;
    59. }
    60. public void c()
    61. {
    62. this.a.getNavigation().a(this.c, this.b);
    63. }
    64. public void d()
    65. {
    66. if ((this.a.getNavigation().m()) || (this.a.b(this.d.d()) < 16.0D)) {
    67. this.f.add(this.d);
    68. }
    69. }
    70. private VillageDoor a(Village paramVillage)
    71. {
    72. Object localObject = null;
    73. int i = 2147483647;
    74. List localList = paramVillage.f();
    75. for (VillageDoor localVillageDoor : localList)
    76. {
    77. int j = localVillageDoor.b(MathHelper.floor(this.a.locX), MathHelper.floor(this.a.locY), MathHelper.floor(this.a.locZ));
    78. if (j < i) {
    79. if (!a(localVillageDoor))
    80. {
    81. localObject = localVillageDoor;
    82. i = j;
    83. }
    84. }
    85. }
    86. return localObject;
    87. }
    88. private boolean a(VillageDoor paramVillageDoor)
    89. {
    90. for (VillageDoor localVillageDoor : this.f) {
    91. if (paramVillageDoor.d().equals(localVillageDoor.d())) {
    92. return true;
    93. }
    94. }
    95. return false;
    96. }
    97. private void f()
    98. {
    99. if (this.f.size() > 15) {
    100. this.f.remove(0);
    101. }
    102. }
    103. }
    104.  
    105.  


    http://bukkit.org/threads/custom-nms-entity-problem.352387/#post-3073303

    This is the solution. Don't write to Map e.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 12, 2016
    Scullyking likes this.
  6. Offline

    Scullyking

    @Europia79
    Interesting. So if I did make my own pathfinder goal e.g PathfinderGoalMoveThroughDungeon, I could presumably use nice variable names and such since I'm not overriding anything.

    @Europia79
    What is Map e doing?
     
    Last edited by a moderator: Apr 15, 2015
  7. Offline

    Europia79

    @Scullyking

    net.minecraft.server.EntityTypes has five Maps:

    Code:java
    1.  
    2. Map c = Maps.newHashMap(); /** key = entityName , value = entityClass */
    3. Map d = Maps.newHashMap(); /** key = entityClass, value = entityName */
    4. Map e = Maps.newHashMap(); /** key = entityId, value = entityClass */
    5. Map f = Maps.newHashMap(); /** key = entityClass, value = entityId */
    6. Map g = Maps.newHashMap(); /** key = entityName, value = entityId */
    7.  


    The server is going to use the class or name to lookup the entityId. The entityId is going to determine what graphic is used to represent the mob: So evenif you extend CraftZombie... if you use entityId of 120, it will look like a Villager.

    Here are all the valid entityIds:
    https://github.com/SpigotMC/mc-dev/blob/master/net/minecraft/server/EntityTypes.java#L143-L199

    So it sounds like you will want:
    Code:java
    1. public class CustomZombie extends CraftZombie implements Zombie { }
    2. public class WeakZombie extends CustomZombie { }
    3. public class StrongZombie extends CustomZombie { }
    4. public class BossZombie extends CustomZombie { }


    So if you have any similarities at all (any shared code between them), then it will go in the CustomZombie class. If there are no similarities, then you can just extend CraftZombie directly.

    I'm thinking at the very least, you could clear all the pathfinders in CustomZombie... then turn around and add back only the ones you want for Weak, Strong, & Boss.

    The Zombie interface is your own. It is a way you can refer to your zombies in the rest of your code... But it's optional... you could refer directly to CustomZombie... but then, when Minecraft updates, you'll have to update ALL your classes. Instead, if you refer only to your Zombie interface, then you do not have to update any class that only uses this interface. Additionally, the Zombie interface can have multiple implementations... one for each version of Minecraft... so tomorrow, if you update to Minecraft 1.9... your plugin can still be backwards compatible with 1.8.3, 1.8, 1.7.10, 1.7.9, 1.7.2, etc...

    If you wish to do this, here's the info:
    http://bukkit.org/threads/support-multiple-minecraft-versions-with-abstraction-maven.115810/

    Here are some more examples supporting multiple minecraft versions:
    https://github.com/Europia79/Extraction
    https://github.com/Europia79/VirtualPlayers
     
    Scullyking likes this.
  8. Offline

    Scullyking

    @Europia79
    Wow, I don't think I've ever gotten such a helpful reply, so thank-you. This is very daunting since I've never done any reflection or NMS stuff with my plugins. When you talk about the Zombie interface. Isn't there already a class called Zombie in bukkit? So as well as needing to make CustomZombie, WeakZombie, StrongZombie and BossZombie, I need to make an interface called Zombie? Basically which is the Zombie interface?

    Thanks again.

    I just found this excellent tutorial about creating custom goals and entities, for anyone interested.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 12, 2016
  9. Offline

    nverdier

  10. Offline

    Scullyking

    nverdier likes this.
  11. Offline

    nverdier

    Well I just don't like it when I go to a thread and it's already solved, after I read through the entire thing ;3
     
  12. Offline

    Scullyking

    @nverdier
    Fair enough. Expect to see many NMS-related questions throughout the night as I try to get custom mobs working :D
     
  13. Offline

    Europia79

    Making your own Zombie interface is 100% optional.

    Code:java
    1. package me.scullyking.mobs.compat.v1_8_R1;
    2.  
    3. import net.minecraft.server.v1_8_R1.EntityZombie;
    4.  
    5. public class CustomZombie extends EntityZombie { }


    Notice how EntityZombie lives in the v1_8_R1 package... And CustomZombie mirrors this...

    And you can have other CustomZombies too:

    Code:java
    1. package me.scullyking.mobs.compat.v1_8_R2;
    2.  
    3. import net.minecraft.server.v1_8_R2.EntityZombie;
    4.  
    5. public class CustomZombie extends EntityZombie { }


    Now... you can no longer refer to CustomZombie in your code... because the question arises: Are you referring to me.scullyking.mobs.compat.v1_8_R1.CustomZombie ? Or me.scullyking.mobs.compat.v1_8_R2.CustomZombie ?

    Same class, different packages.

    But they could share a common interface... And you could refer to BOTH of them at the same time thru this shared interface.

    Here is an example of an abstract factory (where each version of Minecraft has it's own implementation):
    https://github.com/Europia79/Extrac...rc/mc/euro/extraction/nms/NPCFactory.java#L49

    Notice that the factory could return type CraftHostage... but returns the Hostage interface instead.

    Now, when I code, I always use type Hostage interface... And I don't care which implementation that the factory gives me.

    Take a look at my imports for my arena:
    https://github.com/Europia79/Extrac.../src/mc/euro/extraction/HostageArena.java#L23

    Notice that there are no NMS or Minecraft-version-dependent imports. So anytime Minecraft updates, I don't have to update the arena class. I only have to supply a new implementation for the Hostage interface (Zombie interface in your case). But like I said: The interface is purely optional.

    This is my spawn code if you were curious:
    https://github.com/Europia79/Extrac...c/euro/extraction/HostageArena.java#L106-L109
     
    Last edited: Apr 16, 2015
Thread Status:
Not open for further replies.

Share This Page