Make mobs target mobs without using nms

Discussion in 'Plugin Development' started by goodstuff20, Apr 27, 2014.

Thread Status:
Not open for further replies.
  1. Hi,

    The .target didnt seem to work at all (probably only able to target players?) and i was wondering if there was a way to easily make a mob target mobs

    The reason i dont want to use nms is that lets say there is team one zombies and team 2 zombies - i wouldnt want the zombie to attack its team when i set the targeting for zombies

    Thanks guys
     
  2. Offline

    garbagemule

    Which Bukkit build are you compiling with? There were some changes (fixes) regarding monster targetting a while back, so if you're working with old builds, try updating first.

    Rant about nms (open)
    I'm not sure what you mean by a zombie attacking its own team - you would just set the target for a specific object, not the class, so I don't see how you would run into the issue you're suggesting. This shouldn't be the reason not to use nms, though. The reason not to use nms should be that it's plain wrong. You're creating tight coupling (and making your plugin extremely and unnecessarily brittle) by breaking one of the most sacred unwritten rules about object-oriented design: Program to an interface, not an implementation.


    Anyway, what have you tried? What's your test setup? You spawn two zombies and set their targets to each other? How are you doing it?
     
  3. oh no sorry didnt explain myself well enough i guess ^^ - nah with nms teams i ment in nms you set the target for a class and not an object - .target sets it to an object - that is what i need - but .target doesnt seem to work - nms can only (and yes you are right it should be avoided) sets target to lets say all villagers or all zombies - not one or a "team" (i meant team A is just a batch of zombies on the right fighting against team B)

    Thanks!
     
  4. Offline

    garbagemule

    If it was impossible to set a specific target for a specific object in nms, it would also be impossible via (Craft)Bukkit. Targetting in nms is not as simple as it is in Bukkit, but it is possible to set individual targets for individual mobs of the same class.

    You didn't mention what you have tried. Throw some code blocks in here of how you're testing it (minimal examples are easier to reproduce).
     
  5. garbagemule ok well i threw away the most code cause when something doesnt work and i try something new i delete the old of course - but for simplisity
    for the bukkit.jar thing i did
    Code:
    e.setTarget(e2);
    or so
    and for the nms I made a customEntityType class where I override the custom (nms) entities to spawn (works fine) and then the specific customEntity classes for ex. CustomZombie (a living zombie) where in the constructor
    Code:
    public CustomEntityZombie(World world) {
    super(world);
     
    try {
    Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
    bField.setAccessible(true);
    Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
    cField.setAccessible(true);
    bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    } catch (Exception exc) {
    exc.printStackTrace();
    // This means that the name of one of the fields changed names or declaration and will have to be re-examined.
    }
     
    this.goalSelector.a(0, new PathfinderGoalFloat(this));
    this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, 1.0D, false));
    this.goalSelector.a(4, new PathfinderGoalMeleeAttack(this, EntitySkeleton.class, 1.0D, true));
    this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D));
    this.goalSelector.a(6, new PathfinderGoalMoveThroughVillage(this, 1.0D, false));
    this.goalSelector.a(7, new PathfinderGoalRandomStroll(this, 1.0D));
    this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
    this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this));
    this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true));
    this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 0, true));
    this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntitySkeleton.class, 0, false));
    }
    
    for example making the attack goals human and skeleton - but that counts for every human and skeleton and only gets called once per entity spawn so it cant change per second

    thanks
     
  6. Offline

    garbagemule

    I tested with zombies, spiders, and wolves on a pre-1.7.9 build, and it was only spiders that seemed to work. However, this commit supposedly fixes targetting - you make no mention of the build number of the build you're using, but this commit is fairly recent, so chances are your build does not include that fix. Download the most recent development build of Craftbukkit and try again.
     
  7. Ah thanks man - that's the code I needed (does it also work in a 1.7.4 build (in general?) Or is it something old?)

    But do you know why the normal (craft)bukkit ".set target" doesn't work?

    Thanks!!!

    Wups sorry didn't read that its something new - ok I'll try (but bukkit doesn't have a 1.7.9 version out yet I thought so I can't use a 1.7.9 plugin or?

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

    garbagemule

    This is why you should never use Craftbukkit as your library. Craftbukkit is an implementation of Bukkit, so you should always depend on Bukkit. But don't worry, this is something (way too) many developers are guilty of. A horrible amount of developers think hacking around in nms is "cool" or in any way a good idea, but at the end of the day, all they're doing is wasting resources on something that could have existed in the API, oh well.

    Anyway, to fully understand why you should depend on Bukkit instead of Craftbukkit, you need to understand the principle of polymorphism and the whole idea behind interfaces, which I won't go into. I can tell you, however, that MobArena has depended on a 1.7.2-R0.2 build of Bukkit for almost half a year now, simply because there is no reason to update. The API has not changed to the point where it is necessary yet, mostly because of the effort the Bukkit team have put into backwards compatibility. Plugins built for older versions of Bukkit will work on newer versions of Craftbukkit, but the other way around may not always be true.
     
  9. garbagemule In that case I hope your plugin doesn't store data based on player usernames :p
     
  10. Offline

    garbagemule

    AdamQpzm
    It doesn't store data persistently based on player names, which is all that matters. You can store data based on player names all day long if it's only stored on a per-session basis. The only problem with UUIDs is persistent storage, something way too many developers seem to not understand.
     
    xTigerRebornx and AdamQpzm like this.
  11. umm garbagemule getHandle(); seems to give me an error - i thought "getHandle()" got removed for entites since 1.6.4?
     
  12. Offline

    garbagemule

    getHandle() is a method in CraftEntity, which is the implementation of the Entity interface in Bukkit, meaning you shouldn't use it. You should have no reason to get the implementation handle of anything. The setTarget() method on the Creature interface is all you need (meaning also that mobs that aren't instances of Creature cannot target anything - this used to be the case for slimes which would just pick a target right before bouncing, but I don't know if that's been fixed/changed).
     
    goodstuff20 likes this.
  13. garbagemule ok so I can also only use the stuff in the method but let's say I would like to use the whole method - how would I get the "get handle" to work?

    Thanks man!
     
  14. Offline

    garbagemule

    getHandle() doesn't exist in Bukkit. It's purely a Craftbukkit method that should only be used internally (in Craftbukkit), not by plugins. What is it that you think you need that method for?

    You spawn an Entity with the spawn() method in World and then set its target (if it is a Creature, which most [if not all] mobs are). Worst case scenario is that you will have to cast an Entity to a Creature, but the spawn() method uses generics, so the return value is an object of the class you feed it as a parameter, which means if you call the method with Zombie.class, you will get an object of type Zombie back, and Zombie extends Monster, which extends Creature (so by the closure of the supertype relation, a Zombie is also a Creature, so it has Creature's methods, including setTarget()).
     
  15. garbagemule oh right - so that method is .swtTarget - but In the beginning I tried for ex.
    Code:
    Zombie z; Zombie z1 = w.spawnCreature(loc, z);
    //z2
    z1.target(z2);
    
    Although now if I look at it its not too good - first of all "z" is null and so - would this work?/Is this what you meant?
    Code:
    Zombie z = w.spawn(loc, Zombie.class);
    Zombie z2 = w.spawn(loc, Zombie.class);
    z.target(z2);
    
     
  16. Offline

    Garris0n

    It's still better to use UUIDs even for temporary storage. It's more consistent, for one, and it will be faster in 1.8 because a UUID->Player map will apparently be kept by the server for quick lookups.
     
  17. Offline

    garbagemule

    goodstuff20
    Yes, that's what I mean. The spawn() method takes a class as its argument, because if you needed to already have an object of the class you're trying to instantiate, it would be difficult to spawn arbitrary entities. If you're feeling adventurous, you can have a look at the source code to figure out what actually goes on in the method.

    Your opinion cannot constitute a rule, so no, it's not "better even for temporary storage". Storing data based on player names insinuates the use of a mapping from player names to data. Getting a player name from a Player object will not be any slower than getting a UUID from a Player object, because both will be nothing more than one-line getters, which will both be inlined by the JVM. Furthermore, key-value mappings need unique keys, and player names of online players will always be unique, and I'll be damned if stuff like sorting by player name isn't easier with a list of names than it is with a list of UUIDs (which will be much slower due to a necessary lookup on every UUID). This "making mountains out of molehills" is what's causing the contagious fear-mongering in the community over a change that is literally no more than an abstraction that needs attention in very, very few places - there is no problem, so stop making it seem like there is. I will also argue that using UUIDs when necessary is a much better design philosophy than sticking them everywhere (Maslow's hammer), simply because it makes more sense than using them where they aren't necessary. Consistency is a matter of scope. Within persistent storage? Sure. Within the entire scope of a system? Get real. Should I also use BigIntegers everywhere in place of normals ints because it supports arbitrarily large integers compared to the 32 bits of a normal int?
     
    slipcor and AdamQpzm like this.
  18. garbagemule Hmm, the reference "Maslow's hammer" has avoided my attention until just now. I'd never heard it before. But I can see it fits quite nicely here. I guess you really can learn more than just bukkit (+ java I suppose) here. :p
     
  19. Offline

    garbagemule

    AdamQpzm
    Maslow's hammer is an important teaching material in every form of craft - especially, I find, in programming. People have a tendency of littering their projects with the product of using some random tool right after they learn it, and while they sometimes get it right, more often than not, they don't. UUIDs are the current "big thing" in the Bukkit community, so people think they need to use it everywhere, when in fact, they don't.

    Edit: However, this is getting highly off-topic. There is no reason to discuss UUIDs in a thread about monster targetting.
     
    MrAwellstein and AdamQpzm like this.
  20. umm garbagemule the .setTarget still doesnt work for me in the latest craftbukkit & bukkit
     
  21. Offline

    garbagemule

    The words "latest" and "most recent" have no meaning in a rapidly changing open source environment. Specific build numbers are necessary for reproduction. Furthermore, you didn't specify which creatures you're using, so your report is meaningless.

    Anyway, if you are 100% certain that the setTarget() method does not work as intended (zombies can't really target other zombies in vanilla, because they can't accidentally attack each other, so maybe it's a Minecraft limitation), you can make a leaky ticket and hope that someone will be able to fix it.
     
  22. Oh thanks yeah i used Zombies :/ - but lets say i would make a livingZombie in nms and set that to all Zombies that spawn - and the nms zombie targets other Zombies - then it would work or?
     
  23. Offline

    MrAwellstein

    Yes that could work if you figure out how to change the target code from looking at players to livingentities. You should go take a look at nms ZombieEntity and see if the targeting code is managed by the class. If it is then you're in luck. Otherwise you would probably have to make your own targeting system that handles the entities (I'm just guessing I haven't looked there before).
     
  24. Offline

    garbagemule

    You shouldn't mess around in nms, period. A possible reason that these kinds of bugs/limitations exist is that people just don't do anything about them and revert to hacking around in nms, instead of trying to get them implemented in (Craft)Bukkit. It slows the progress of the entire Bukkit project down when no one contributes and instead depends on the raw nms code, which is brittle and will break on every Minecraft update. I've seen stupid hacks that use reflection to avoid the breaking, but breaks still happen because the variable- and method-names in the obfuscated code changes.

    Anyway, to keep monsters from targetting the "wrong" players in MobArena (i.e. spectators), I use the EntityTargetEvent, which may be useful to you. If you are going to hack around in nms, only do it to the extent that it is absolutely necessary. It should be a very last resort, not a first, second, third, or n'th choice. And seriously, make a leaky ticket. Bring some attention to the problem so the Bukkit team and contributors see it. If the ticket is declined because of "works as intended", you can justify your hacking around.
     
  25. Ok thanks garbagemule - and MrAwellstein yes it works

    I hope that (even though its not possible in vanilla) bukkit adds that Zombies can target Zombies - until then - would it be too much lagg / just not healthy to make Zombie target Zombies in nms and if a zombie targets a zombie thaz shouldent be tsrgetet i.e. he is on his "Team" then cancel it?

    I'm asking because I am scared that when it gets canceled he just targets him again and this creates an infinite loop which makes the zomie unable to target the zombies he should target
     
  26. Offline

    garbagemule

    If you cancel the target event, the target switch will not happen. Note that you have to handle the "target died" reason, because if its target dies, it of course can't continue to attack it. You will want to cancel the appropriate target events, ignore irrelevant ones and modify certain others, just as with any kind of generic event listening.
     
  27. Ah thanks!
     
Thread Status:
Not open for further replies.

Share This Page