Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPC name doesn't update correctly in different screnarios #1752

Open
Sago92 opened this issue Apr 25, 2019 · 11 comments

Comments

Projects
None yet
3 participants
@Sago92
Copy link

commented Apr 25, 2019

The output of command /version on my server is:
Screenshot3
The output of command /version citizens on my server is:
Screenshot4
Citizens configuration & latest server log file: click

Dear Development-Team,

I am using the engine/plugin/api of Citizens to control and create different NPC's on my in progress MMORPG Server.

I've created some own traits. For example to archive a friendly/aggressive or neutral behavior or for exmaple a wander trait where an NPC walks randomly in a defined area.

Now I have the issue, that my custom NPC names won't show up in the following scenarios.
Scenario 1: When the NPC is navigating directly after it was spawned
Scenario 2: When a NPC gets into a fight after spawned
Scenario 3: When you moving from far away into the area where NPCs are fighting each other

As you can see in the following screenshots the wolf and the sheep are in a fight and the custom name doesn't show up.

Screenshot1
Screenshot2

I am using different color codes in the name and figured out that setting the name of the NPC is slow because of the internal respawn (~1-3 seconds). I am using this piece of code to change the name of the NPC

// Updates the entity display name
private void updateEntityDisplayName() {
    // Gets the color based on the attitude
    ChatColor nameColor = ColorHelper.attitudeColor.get(definition.getAttitude());

    // Splits the entity name by spaces, because client side names need the color code before every part of the name
    String[] splittedName = definition.getName().split(" ");

    // Combines back the name with the needed color code
    String entityName = "";
    for (String namePart : splittedName)
        entityName += nameColor + namePart + " ";

    npc.setName(definition.getRolePrefix() + entityName);
}

When a entitys health reached zero (custom health management) the kill method will get invoked

// Kills the entity
@Override
public void kill() {
    if (npc.isSpawned() && !isDead) {
        isDead = true;
	LivingEntity livingEntity = (LivingEntity) npc.getEntity();
	livingEntity.setHealth(0);
	health = 0;
	npc.despawn(DespawnReason.DEATH);
	aggro.clear();

	// Cancels the old in fight reset task
	if (inFightResetTaskID != 0)
	    Bukkit.getScheduler().cancelTask(inFightResetTaskID);

	// Triggers the leave fight event
	isInFight = false;
	ConquestEntityLeaveFightEvent eventData = new ConquestEntityLeaveFightEvent(this);
	listeners.forEach(x -> x.conquestEntityLeaveFight(eventData));
    }
}

After a specified defined of time the respawn logic calls the spawn method

// Spawns the entity
@Override
public void spawn() {
    if (!npc.isSpawned() && isDead) {
        isDead = false;
	health = definition.getMaxHealth();
	npc.spawn(detail.getSpawnLocation());
	aggro.clear();
	spawnTime = System.currentTimeMillis();
    }
}

Finally my setup method after I created an NPC

// Setups the default NPC data
private void setup() {
    // Updates the display name of the entity
    updateEntityDisplayName();

    // Adds the friendly behavior trait to the NPC if its attitude type is friendly and not already attachedd
    if (definition.getAttitude() == EntityAttitudeType.Friendly && !npc.hasTrait(FriendlyBehaviorTrait.class)) {
        FriendlyBehaviorTrait friendlyBehaviorTrait = new FriendlyBehaviorTrait(this);
	npc.addTrait(friendlyBehaviorTrait);
    } else if (npc.hasTrait(FriendlyBehaviorTrait.class))
        // Removes the friendly behavior trait because the attitude type of the entity changed to another
	npc.removeTrait(FriendlyBehaviorTrait.class);

    // Adds the neutral behavior trait to the NPC if its attitude type is neutral and not already attachedd
    if (definition.getAttitude() == EntityAttitudeType.Neutral && !npc.hasTrait(NeutralBehaviorTrait.class)) {
        NeutralBehaviorTrait neutralBehaviorTrait = new NeutralBehaviorTrait(this);
	npc.addTrait(neutralBehaviorTrait);
    } else if (npc.hasTrait(NeutralBehaviorTrait.class))
        // Removes the neutral behavior trait because the attitude type of the entity changed to another
	npc.removeTrait(NeutralBehaviorTrait.class);

    // Adds the aggressive behavior trait to the NPC if its attitude type is aggressive and not already attachedd
    if (definition.getAttitude() == EntityAttitudeType.Aggressive && !npc.hasTrait(AggressiveBehaviorTrait.class)) {
        AggressiveBehaviorTrait aggressiveBehaviorTrait = new AggressiveBehaviorTrait(this);
	npc.addTrait(aggressiveBehaviorTrait);
    } else if (npc.hasTrait(AggressiveBehaviorTrait.class))
        // Removes the aggressive behavior trait because the attitude type of the entity changed to another
	npc.removeTrait(AggressiveBehaviorTrait.class);

    // Sets the equipment of the entity
    Equipment equipment = npc.getTrait(Equipment.class);
    ItemStack weaponItem = ItemManager.getItem(definition.getWeaponItem(), RarityType.Common);
    if (weaponItem != null)
        equipment.set(EquipmentSlot.HAND, weaponItem);
    ItemStack helmetItem = ItemManager.getItem(definition.getHelmetItem(), RarityType.Common);
    if (helmetItem != null)
        equipment.set(EquipmentSlot.HELMET, helmetItem);
    ItemStack chestplatItem = ItemManager.getItem(definition.getChestplateItem(), RarityType.Common);
    if (chestplatItem != null)
        equipment.set(EquipmentSlot.CHESTPLATE, chestplatItem);
    ItemStack leggingsItem = ItemManager.getItem(definition.getLeggingsItem(), RarityType.Common);
    if (leggingsItem != null)
        equipment.set(EquipmentSlot.LEGGINGS, leggingsItem);
     ItemStack bootsItem = ItemManager.getItem(definition.getBootsItem(), RarityType.Common);
    if (bootsItem != null)
        equipment.set(EquipmentSlot.BOOTS, bootsItem);

    // Adds the watching move trait and look close trait to the NPC if its move type is watching and not already attachedd
     if (definition.getMoveType() == EntityMoveType.Watching && !npc.hasTrait(WatchingTrait.class)) {
        WatchingTrait watchingTrait = new WatchingTrait(this);
	 npc.addTrait(watchingTrait);
	 LookClose lookClose = npc.getTrait(LookClose.class);
	 lookClose.lookClose(true);
	 lookClose.setRange(5);
    } else if (npc.hasTrait(WatchingTrait.class)) {
        // Removes the watching and look close trait because the move type of the entity changed to another
	npc.removeTrait(WatchingTrait.class);
	npc.removeTrait(LookClose.class);
    }

    // Adds the walking move trait to the NPC if its move type is walking and not already attached
    if (definition.getMoveType() == EntityMoveType.Walking && !npc.hasTrait(WalkingTrait.class)) 
    {
        WalkingTrait walkingTrait = new WalkingTrait(this);
	npc.addTrait(walkingTrait);
    } else if (npc.hasTrait(WalkingTrait.class)) {
        // Removes the walking trait and removes the latest goals because the move type of the entity changed to another
	npc.removeTrait(WalkingTrait.class);
	npc.getDefaultGoalController().cancelCurrentExecution();
	npc.getDefaultGoalController().addGoal(new MoveToGoal(npc, detail.getSpawnLocation()), 1);
    }

    // Adds the patrol move trait to the NPC if its move type is patrol and not already attached
    if (definition.getMoveType() == EntityMoveType.Patrol && !npc.hasTrait(PatrolTrait.class)) {
        PatrolTrait patrolTrait = new PatrolTrait(this);
	npc.addTrait(patrolTrait);
    } else if (npc.hasTrait(PatrolTrait.class)) {
        // Removes the patrol trait and removes the latest goals because the move type of the entity changed to another
	npc.removeTrait(PatrolTrait.class);
	npc.getDefaultGoalController().cancelCurrentExecution();
	npc.getDefaultGoalController().addGoal(new MoveToGoal(npc, detail.getSpawnLocation()), 1);
    }

    // Teleports the entity back to its start position
    if (npc.isSpawned())
        npc.getEntity().teleport(detail.getSpawnLocation());

	// Sets the protected property to true so the entity can take damage and dies
	npc.setProtected(false);
}

Do you have any ideas/suggestions or code improvements to solve the above scenarios?

Regards
Sascha

@Sago92 Sago92 changed the title NPC name doesn't refresh in different screnarios NPC name doesn't update correctly in different screnarios Apr 25, 2019

@mcmonkey4eva

This comment has been minimized.

Copy link
Member

commented Apr 26, 2019

Generally you want to spawn the NPC with the correct name from the start, not spawn it and rename it after.

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

Now I changed my logic so that the name will only be set when I create a whole new NPC and I never update or set the name in the rest of my code (spawn, despawn or setup logic).

// Gets the color based on the attitude
ChatColor nameColor = ColorHelper.attitudeColor.get(definition.getAttitude());

// Splits the entity name by spaces, because client side names need the color code before every part of the name
String[] splittedName = definition.getName().split(" ");

// Combines back the name with the needed color code
String entityName = "";
for (String namePart : splittedName)
	entityName += nameColor + namePart + " ";

// Creates the new entity/npc instance
NPC npc = CitizensAPI.getNPCRegistry().createNPC(definition.getType(), definition.getRolePrefix() + entityName);
npc.spawn(spawnLocation);

Nevertheless the NPCs name wont show up after the NPC gets killed, respawns and directly starts a fight or is directly walking after the respawn.

Video1

And the last described scenario when you come from far away and the NPCs are already in a fight the names won't update, too.

Video2

When the NPC stands still for around 1~2 seconds the name will correctly be updated after respawn.

Video3

Do you need any additional information or soruce code snippets?

Regards
Sascha

@mcmonkey4eva

This comment has been minimized.

Copy link
Member

commented Apr 26, 2019

Can you test with a fully up-to-date Spigot 1.13.2 build (make a new one via buildtools), and the latest stable 1.13.2 build - which is this one: https://ci.citizensnpcs.co/job/Citizens2/1636/

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

Issue is still there with the latest version of Spigot and Citizens

Screenshot1
Screenshot2

Sample: Directly walking after spawn:

Video1

@fullwall

This comment has been minimized.

Copy link
Member

commented Apr 26, 2019

Try latest build.

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

With the latest build all 3 described behaviors are still there. It look like the update of the name won't trigger/work if the NPC is moving (see directly walking after spawn or fight while player ist comming from far away)

Screenshot

@fullwall

This comment has been minimized.

Copy link
Member

commented Apr 26, 2019

And what's your packet update delay? The point of 1657 was to change that if you look at the commit.

@fullwall

This comment has been minimized.

Copy link
Member

commented Apr 26, 2019

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

My packet update delay is 30. I tried to change it to 5, but it doesn't change anything.

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

I did some additional testing.
1.) The scencario when I come from far away to the NPCs that are fighting, the names are updated correctly now. - Had this issue again
2.) Adding a "spawn protection" from 2 seconds where the NPC don't walk or gets into a fight including the reducing of the packet update delay to 5 seconds updates the name correctly, too

Nevertheless without the delay the name doesn't update when an NPC is directly walking or starting a fight

@Sago92

This comment has been minimized.

Copy link
Author

commented Apr 26, 2019

I figured something new out. If the entity type of the spawned entity is a Player the name is directly correct. Only if the entity type is something different like a sheep or a wolf the update appears a bit later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.