From cb9f859e5826beb09137f90185d0dc0bd9c33ede Mon Sep 17 00:00:00 2001 From: Adam Kneller Date: Thu, 23 Apr 2020 20:07:58 +1000 Subject: [PATCH 1/4] Improve FindNearbyPlayersSystem performance, also add AttackInProximityComponent --- .../actions/CheckAttackStopAction.java | 20 ++++-- .../AttackInProximityComponent.java | 31 +++++++++ .../system/FindNearbyPlayersSystem.java | 68 ++++++++++--------- 3 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java diff --git a/src/main/java/org/terasology/behaviors/actions/CheckAttackStopAction.java b/src/main/java/org/terasology/behaviors/actions/CheckAttackStopAction.java index ff01d42c..12496d1e 100644 --- a/src/main/java/org/terasology/behaviors/actions/CheckAttackStopAction.java +++ b/src/main/java/org/terasology/behaviors/actions/CheckAttackStopAction.java @@ -15,6 +15,7 @@ */ package org.terasology.behaviors.actions; +import org.terasology.behaviors.components.AttackInProximityComponent; import org.terasology.behaviors.components.AttackOnHitComponent; import org.terasology.logic.behavior.BehaviorAction; import org.terasology.logic.behavior.core.Actor; @@ -40,9 +41,15 @@ public class CheckAttackStopAction extends BaseAction { public BehaviorState modify(Actor actor, BehaviorState state) { BehaviorState status = getBehaviorStateWithoutReturn(actor); if (status == BehaviorState.FAILURE) { - AttackOnHitComponent attackOnHitComponent = actor.getComponent(AttackOnHitComponent.class); - attackOnHitComponent.instigator = null; - actor.getEntity().saveComponent(attackOnHitComponent); + if (actor.hasComponent(AttackOnHitComponent.class)) { + AttackOnHitComponent attackOnHitComponent = actor.getComponent(AttackOnHitComponent.class); + attackOnHitComponent.instigator = null; + actor.getEntity().saveComponent(attackOnHitComponent); + } else if (actor.hasComponent(AttackInProximityComponent.class)) { + AttackInProximityComponent attackInProximityComponent = actor.getComponent(AttackInProximityComponent.class); + attackInProximityComponent.instigator = null; + actor.getEntity().saveComponent(attackInProximityComponent); + } actor.getEntity().removeComponent(FollowComponent.class); } return status; @@ -54,7 +61,12 @@ private BehaviorState getBehaviorStateWithoutReturn(Actor actor) { return BehaviorState.FAILURE; } Vector3f actorPosition = actorLocationComponent.getWorldPosition(); - float maxDistance = actor.hasComponent(AttackOnHitComponent.class) ? actor.getComponent(AttackOnHitComponent.class).maxDistance : this.maxDistance; + float maxDistance = this.maxDistance; + if (actor.hasComponent(AttackOnHitComponent.class)) { + maxDistance = actor.getComponent(AttackOnHitComponent.class).maxDistance; + } else if (actor.hasComponent(AttackInProximityComponent.class)) { + maxDistance = actor.getComponent(AttackInProximityComponent.class).maxDistance; + } float maxDistanceSquared = maxDistance * maxDistance; FollowComponent followWish = actor.getComponent(FollowComponent.class); diff --git a/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java new file mode 100644 index 00000000..8a56b499 --- /dev/null +++ b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 MovingBlocks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.terasology.behaviors.components; + +import org.terasology.entitySystem.Component; +import org.terasology.entitySystem.entity.EntityRef; + +/** + * Represents an NPC that will attack players when they enter {@code maxDistance} range. + */ +public class AttackInProximityComponent implements Component { + // Maximum distance from instigator after which the animal will stop chasing to attack + public float maxDistance = 10f; + // Speed factor by which attack speed increases + public float speedMultiplier = 1.2f; + public EntityRef instigator; + public long timeWhenHit; +} \ No newline at end of file diff --git a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java index bbf584f0..9c1027fb 100644 --- a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java +++ b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java @@ -15,7 +15,6 @@ */ package org.terasology.behaviors.system; -import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.entitySystem.entity.EntityManager; @@ -31,9 +30,15 @@ import org.terasology.registry.In; import org.terasology.behaviors.components.FindNearbyPlayersComponent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; @RegisterSystem(RegisterMode.AUTHORITY) public class FindNearbyPlayersSystem extends BaseComponentSystem implements UpdateSubscriberSystem { @@ -46,47 +51,48 @@ public class FindNearbyPlayersSystem extends BaseComponentSystem implements Upda @Override public void update(float delta) { + Iterable clients = entityManager.getEntitiesWith(ClientComponent.class); + Map clientLocationMap = new HashMap<>(); + + for (EntityRef client : clients) { + ClientComponent clientComponent = client.getComponent(ClientComponent.class); + EntityRef character = clientComponent.character; + AliveCharacterComponent aliveCharacterComponent = character.getComponent(AliveCharacterComponent.class); + if (aliveCharacterComponent == null) { + continue; + } + LocationComponent locationComponent = character.getComponent(LocationComponent.class); + if (locationComponent == null) { + continue; + } + clientLocationMap.put(locationComponent.getWorldPosition(), character); + } + Set locationSet = clientLocationMap.keySet(); + for (EntityRef entity : entityManager.getEntitiesWith(FindNearbyPlayersComponent.class)) { Vector3f actorPosition = entity.getComponent(LocationComponent.class).getWorldPosition(); FindNearbyPlayersComponent findNearbyPlayersComponent = entity.getComponent(FindNearbyPlayersComponent.class); float maxDistance = findNearbyPlayersComponent.searchRadius; float maxDistanceSquared = maxDistance * maxDistance; - Iterable clients = entityManager.getEntitiesWith(ClientComponent.class); - List charactersWithinRange = Lists.newArrayList(); - - EntityRef closestCharacter = EntityRef.NULL; - float minDistanceFromCharacter = 0.0f; - for (EntityRef client : clients) { - ClientComponent clientComponent = client.getComponent(ClientComponent.class); - EntityRef character = clientComponent.character; - AliveCharacterComponent aliveCharacterComponent = character.getComponent(AliveCharacterComponent.class); - if (aliveCharacterComponent == null) { - continue; - } - LocationComponent locationComponent = character.getComponent(LocationComponent.class); - if (locationComponent == null) { - continue; - } - if (locationComponent.getWorldPosition().distanceSquared(actorPosition) <= maxDistanceSquared) { - if (charactersWithinRange.size() == 0) { - closestCharacter = character; - minDistanceFromCharacter = locationComponent.getWorldPosition().distanceSquared(actorPosition); - } else { - if (locationComponent.getWorldPosition().distanceSquared(actorPosition) < minDistanceFromCharacter) { - closestCharacter = character; - minDistanceFromCharacter = locationComponent.getWorldPosition().distanceSquared(actorPosition); - } - } - charactersWithinRange.add(character); - } + List inRange = locationSet.stream() + .filter(loc -> loc.distanceSquared(actorPosition) <= maxDistanceSquared) + .collect(Collectors.toList()); + if (inRange.isEmpty()) { + findNearbyPlayersComponent.charactersWithinRange = Collections.emptyList(); + findNearbyPlayersComponent.closestCharacter = EntityRef.NULL; + entity.saveComponent(findNearbyPlayersComponent); + continue; } + inRange.sort(Comparator.comparingDouble(v3f -> v3f.distanceSquared(actorPosition))); + List charactersWithinRange = new ArrayList<>(inRange.size()); + inRange.forEach(v3f -> charactersWithinRange.add(clientLocationMap.get(v3f))); + if (!isEqual(charactersWithinRange, findNearbyPlayersComponent.charactersWithinRange)) { findNearbyPlayersComponent.charactersWithinRange = charactersWithinRange; - findNearbyPlayersComponent.closestCharacter = closestCharacter; + findNearbyPlayersComponent.closestCharacter = charactersWithinRange.get(0); entity.saveComponent(findNearbyPlayersComponent); - } } } From 4a467651f0888d46428874392a5b5a9e24c013a9 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 24 Apr 2020 17:38:03 +1000 Subject: [PATCH 2/4] Apply suggestions from code review Co-Authored-By: Tobias Nett --- .../behaviors/components/AttackInProximityComponent.java | 2 +- .../terasology/behaviors/system/FindNearbyPlayersSystem.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java index 8a56b499..79a68c75 100644 --- a/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java +++ b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java @@ -28,4 +28,4 @@ public class AttackInProximityComponent implements Component { public float speedMultiplier = 1.2f; public EntityRef instigator; public long timeWhenHit; -} \ No newline at end of file +} diff --git a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java index 9c1027fb..5367d180 100644 --- a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java +++ b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java @@ -86,8 +86,8 @@ public void update(float delta) { } inRange.sort(Comparator.comparingDouble(v3f -> v3f.distanceSquared(actorPosition))); - List charactersWithinRange = new ArrayList<>(inRange.size()); - inRange.forEach(v3f -> charactersWithinRange.add(clientLocationMap.get(v3f))); + List charactersWithinRange = + inRange.stream().map(clientLocationMap::get).collect(Collectors.toList());; if (!isEqual(charactersWithinRange, findNearbyPlayersComponent.charactersWithinRange)) { findNearbyPlayersComponent.charactersWithinRange = charactersWithinRange; From 535c89ce5eee20b799d22f7c0a367c0a09c35e6a Mon Sep 17 00:00:00 2001 From: Adam Kneller Date: Fri, 24 Apr 2020 17:43:47 +1000 Subject: [PATCH 3/4] Implement other review suggestions --- .../behaviors/components/AttackInProximityComponent.java | 2 +- .../terasology/behaviors/system/FindNearbyPlayersSystem.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java index 79a68c75..ab9d83d5 100644 --- a/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java +++ b/src/main/java/org/terasology/behaviors/components/AttackInProximityComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 MovingBlocks + * Copyright 2020 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java index 5367d180..61059171 100644 --- a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java +++ b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java @@ -77,6 +77,7 @@ public void update(float delta) { List inRange = locationSet.stream() .filter(loc -> loc.distanceSquared(actorPosition) <= maxDistanceSquared) + .sorted(Comparator.comparingDouble(v3f -> v3f.distanceSquared(actorPosition))) .collect(Collectors.toList()); if (inRange.isEmpty()) { findNearbyPlayersComponent.charactersWithinRange = Collections.emptyList(); @@ -85,7 +86,6 @@ public void update(float delta) { continue; } - inRange.sort(Comparator.comparingDouble(v3f -> v3f.distanceSquared(actorPosition))); List charactersWithinRange = inRange.stream().map(clientLocationMap::get).collect(Collectors.toList());; From 037c1f48b2feb1a5f0bb5c33043cec41243f0a4f Mon Sep 17 00:00:00 2001 From: Tobias Nett Date: Fri, 24 Apr 2020 09:59:53 +0200 Subject: [PATCH 4/4] Update src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java --- .../terasology/behaviors/system/FindNearbyPlayersSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java index 61059171..eaaf86ae 100644 --- a/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java +++ b/src/main/java/org/terasology/behaviors/system/FindNearbyPlayersSystem.java @@ -87,7 +87,7 @@ public void update(float delta) { } List charactersWithinRange = - inRange.stream().map(clientLocationMap::get).collect(Collectors.toList());; + inRange.stream().map(clientLocationMap::get).collect(Collectors.toList()); if (!isEqual(charactersWithinRange, findNearbyPlayersComponent.charactersWithinRange)) { findNearbyPlayersComponent.charactersWithinRange = charactersWithinRange;