diff --git a/src/main/java/org/terasology/dynamicCities/region/RegionEntityManager.java b/src/main/java/org/terasology/dynamicCities/region/RegionEntityManager.java index 5ad1c8d..376fece 100644 --- a/src/main/java/org/terasology/dynamicCities/region/RegionEntityManager.java +++ b/src/main/java/org/terasology/dynamicCities/region/RegionEntityManager.java @@ -21,6 +21,7 @@ import org.terasology.dynamicCities.sites.SiteComponent; import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; +import org.terasology.engine.entitySystem.entity.internal.EntityScope; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnActivatedComponent; import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; @@ -30,7 +31,6 @@ import org.terasology.engine.logic.console.commandSystem.annotations.Sender; import org.terasology.engine.logic.location.LocationComponent; import org.terasology.engine.logic.nameTags.NameTagComponent; -import org.terasology.engine.logic.permission.PermissionManager; import org.terasology.engine.registry.In; import org.terasology.engine.registry.Share; import org.terasology.engine.world.block.BlockArea; @@ -40,13 +40,13 @@ import org.terasology.nui.Color; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; @Share(value = RegionEntityManager.class) @RegisterSystem(RegisterMode.AUTHORITY) public class RegionEntityManager extends BaseComponentSystem { + private static final Logger logger = LoggerFactory.getLogger(RegionEntityManager.class); @In private EntityManager entityManager; @@ -59,14 +59,11 @@ public class RegionEntityManager extends BaseComponentSystem { private final int gridSize = 96; - private Logger logger = LoggerFactory.getLogger(RegionEntityManager.class); private boolean toggledNameTags = false; @Override public void postBegin() { - Iterator regionEntitiesIterator = entityManager.getEntitiesWith(RegionEntitiesComponent.class).iterator(); - while (regionEntitiesIterator.hasNext()) { - EntityRef regionStore = regionEntitiesIterator.next(); + for (EntityRef regionStore : entityManager.getEntitiesWith(RegionEntitiesComponent.class)) { if (regionStore.hasComponent(RegionMainStoreComponent.class)) { regionStoreEntity = regionStore; regionEntitiesComponent = regionStore.getComponent(RegionEntitiesComponent.class); @@ -75,18 +72,18 @@ public void postBegin() { } regionEntitiesComponent = new RegionEntitiesComponent(gridSize); regionStoreEntity = entityManager.create(regionEntitiesComponent, new RegionMainStoreComponent()); - regionStoreEntity.setAlwaysRelevant(true); + regionStoreEntity.setScope(EntityScope.GLOBAL); } - @ReceiveEvent(components = {UnregisteredRegionComponent.class, LocationComponent.class, RoughnessFacetComponent.class, ResourceFacetComponent.class}) + @ReceiveEvent(components = {UnregisteredRegionComponent.class, LocationComponent.class, RoughnessFacetComponent.class, + ResourceFacetComponent.class}) public void registerRegion(OnActivatedComponent event, EntityRef region) { add(region); region.removeComponent(UnregisteredRegionComponent.class); region.addComponent(new UnassignedRegionComponent()); - } - @ReceiveEvent(components = {UnassignedRegionComponent.class}) + @ReceiveEvent(components = UnassignedRegionComponent.class) public void assignRegion(AssignRegionEvent event, EntityRef region) { region.addComponent(new ActiveRegionComponent()); region.removeComponent(UnassignedRegionComponent.class); @@ -148,8 +145,8 @@ private Vector2i toCellPos(Vector2ic pos) { public boolean cellIsLoaded(Vector2ic position) { Map cellGrid = regionEntitiesComponent.cellGrid; - int cellSize = regionEntitiesComponent.cellSize; - return cellGrid.containsKey(toCellPos(position)) && (cellGrid.get(toCellPos(position)) == cellSize); + Vector2i cellPos = toCellPos(position); + return cellGrid.containsKey(cellPos) && (cellGrid.get(cellPos) == regionEntitiesComponent.cellSize); } public List getRegionsInCell(Vector2ic position) { @@ -157,7 +154,7 @@ public List getRegionsInCell(Vector2ic position) { List regions = new ArrayList<>(); Vector2i cellCenter = toCellPos(position); - int edgeLength = Math.round((float)Math.sqrt(cellSize)); + int edgeLength = Math.round((float) Math.sqrt(cellSize)); BlockArea cellRegion = new BlockArea(-edgeLength, -edgeLength, edgeLength, edgeLength); Vector2i regionWorldPos = new Vector2i(); for (Vector2ic pos : cellRegion) { @@ -178,12 +175,12 @@ public List getRegionsInCell(EntityRef region) { LocationComponent regionLocation = region.getComponent(LocationComponent.class); Vector3fc loc = regionLocation.getLocalPosition(); Vector2i pos = new Vector2i(loc.x(), loc.z(), RoundingMode.FLOOR); - return getRegionsInCell(pos); + return getRegionsInCell(pos); } public boolean checkSidesLoadedLong(Vector2ic pos) { Vector2i temp = new Vector2i(); - return (cellIsLoaded(pos.add(3 * gridSize, 0, temp)) && cellIsLoaded(pos.add(-3 * gridSize, 0,temp)) + return (cellIsLoaded(pos.add(3 * gridSize, 0, temp)) && cellIsLoaded(pos.add(-3 * gridSize, 0, temp)) && cellIsLoaded(pos.add(0, 3 * gridSize, temp)) && cellIsLoaded(pos.add(0, -3 * gridSize, temp))); } @@ -202,7 +199,9 @@ public boolean checkSidesLoadedNear(Vector2ic pos) { // not finding any suitable location at all (in MetalRenegades) // return (cellIsLoaded(pos.add(gridSize,0, temp)) && cellIsLoaded(pos.add(-gridSize, 0, temp)) // && cellIsLoaded(pos.add(0, gridSize, temp)) && cellIsLoaded(pos.add(0, -gridSize, temp))); // horribly hacky logic but ok? - return cellIsLoaded(pos) && cellIsLoaded(pos.add(gridSize,0, temp)) && cellIsLoaded(pos.add(0, gridSize, temp)); + return cellIsLoaded(pos) + && cellIsLoaded(pos.add(gridSize, 0, temp)) + && cellIsLoaded(pos.add(0, gridSize, temp)); } public boolean checkSidesLoadedNear(EntityRef region) { @@ -215,7 +214,7 @@ public boolean checkSidesLoadedNear(EntityRef region) { public boolean checkFullLoaded(Vector2ic pos) { BlockArea cube = new BlockArea(-1, -1, 1, 1); Vector2i cellPos = new Vector2i(); - for(Vector2ic cubePos : cube) { + for (Vector2ic cubePos : cube) { cellPos.set(pos.x() + cubePos.x() * gridSize, pos.y() + cubePos.y() * gridSize); if (!cellIsLoaded(cellPos)) { return false; @@ -255,7 +254,7 @@ public void setNameTagForRegion(EntityRef region) { SiteComponent siteComponent = region.getComponent(SiteComponent.class); nT.text = "Roughness: " + roughnessFacetComponent.meanDeviation + " Grass: " + resourceFacetComponent.getResourceSum("Grass") - + locationComponent.getWorldPosition(new Vector3f()).toString(); + + locationComponent.getWorldPosition(new Vector3f()); nT.yOffset = 10; nT.scale = 10; @@ -273,10 +272,8 @@ public void setNameTagForRegion(EntityRef region) { region.addComponent(nT); } - @Command(shortDescription = "Toggles the view of nametags for region entities", runOnServer = true, - requiredPermission = PermissionManager.DEBUG_PERMISSION) - public String toggleRegionTags( - @Sender EntityRef client) { + @Command(shortDescription = "Toggles the view of name tags for region entities", runOnServer = true) + public String toggleRegionTags(@Sender EntityRef client) { if (toggledNameTags) { for (EntityRef region : regionEntitiesComponent.regionEntities.values()) { region.removeComponent(NameTagComponent.class); diff --git a/src/test/java/org/terasology/dynamicCities/region/RegionEntitiesTest.java b/src/test/java/org/terasology/dynamicCities/region/RegionEntitiesTest.java new file mode 100644 index 0000000..8a84076 --- /dev/null +++ b/src/test/java/org/terasology/dynamicCities/region/RegionEntitiesTest.java @@ -0,0 +1,114 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.dynamicCities.region; + +import org.joml.RoundingMode; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3fc; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.terasology.engine.entitySystem.entity.EntityRef; +import org.terasology.engine.logic.location.LocationComponent; +import org.terasology.engine.registry.In; +import org.terasology.engine.world.chunks.Chunks; +import org.terasology.moduletestingenvironment.MTEExtension; +import org.terasology.moduletestingenvironment.extension.Dependencies; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Tag("MteTest") +@ExtendWith({MockitoExtension.class, MTEExtension.class}) +@Dependencies("DynamicCities") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class RegionEntitiesTest { + private static final int HALF_X = Chunks.SIZE_X / 2; + private static final int HALF_Z = Chunks.SIZE_Z / 2; + + @In + public RegionEntityManager regionEntityManager; + + private final Vector3fc[] pos = new Vector3f[] { + // These first four are used by the test for #getNearest, which resolves to + // the center of chunks. Something around the time of the JOML migration shifted + // that value down by one. + new Vector3f(HALF_X - 1, 0, HALF_Z - 1), + new Vector3f(HALF_X - 1, 0, -HALF_Z - 1), + new Vector3f(-HALF_X - 1, 0, HALF_Z - 1), + new Vector3f(-HALF_X - 1, 0, -HALF_Z - 1), + + // …then why does this also have these locations that are at the corners of chunks + // instead of their centers? + new Vector3f(0, 0, 0), + new Vector3f(32, 0, 32), + new Vector3f(32, 0, -32), + new Vector3f(-32, 0, 32), + new Vector3f(-32, 0, -32), + new Vector3f(97, 0, -97) + }; + private final EntityRef[] test = new EntityRef[pos.length]; + + @BeforeAll + public void setupEntityRefs() { + for (int i = 0; i < test.length; i++) { + test[i] = Mockito.mock(EntityRef.class, "mock EntityRef#" + i); + Mockito.when(test[i].getComponent(LocationComponent.class)) + .thenReturn(new LocationComponent(pos[i])); + regionEntityManager.add(test[i]); + } + } + + @Test + public void testSimpleGet() { + for (int i = 0; i < test.length; i++) { + Vector2i position = new Vector2i(pos[i].x(), pos[i].z(), RoundingMode.FLOOR); + assertEquals(test[i], regionEntityManager.get(position)); + } + } + + @ParameterizedTest(name = "{1}, {2} is nearest pos[{0}]") + @CsvSource({ + "0, 21, 13", + "1, 14, -13", + "2, -22, 19", + "3, -13, -19" + }) + public void testNearestGet(int index, int x, int y) { + assertEquals(test[index], regionEntityManager.getNearest(new Vector2i(x, y))); + } + + @ParameterizedTest(name = "cell loaded at {0}, {1}") + @CsvSource({"0, 0", "16, 0", "0, -25"}) + public void testCellsInRegionAreLoaded(int x, int y) { + assertTrue(regionEntityManager.cellIsLoaded(new Vector2i(x, y))); + } + + @ParameterizedTest(name = "cell not loaded at {0}, {1}") + @CsvSource({"98, -124", "351, 234", "153, -134"}) + public void testCellsOutsideRegionAreNotLoaded(int x, int y) { + assertFalse(regionEntityManager.cellIsLoaded(new Vector2i(x, y))); + } + + @Disabled + @Test + public void testGetRegionsInCell() { + List testList = Arrays.asList(test).subList(0, 5); + // FIXME: The method under test seems to be returning the correct values, but the list is + // out-of-order and contains duplicates. + assertEquals(testList, regionEntityManager.getRegionsInCell(new Vector2i(0, 0))); + } +} diff --git a/src/test/java/regions/RegionEntitiesTest.java b/src/test/java/regions/RegionEntitiesTest.java deleted file mode 100644 index 0c50989..0000000 --- a/src/test/java/regions/RegionEntitiesTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2016 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 regions; - -import com.google.common.collect.Sets; -import org.joml.RoundingMode; -import org.joml.Vector2i; -import org.joml.Vector3f; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.terasology.dynamicCities.region.RegionEntityManager; -import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.logic.location.LocationComponent; -import org.terasology.moduletestingenvironment.ModuleTestingEnvironment; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Tag("MteTest") -public class RegionEntitiesTest extends ModuleTestingEnvironment { - private RegionEntityManager regionEntityManager; - - private EntityRef[] test; - private Vector3f[] pos = new Vector3f[10]; - - @Override - public Set getDependencies() { - return Sets.newHashSet("engine", "DynamicCities", "ModuleTestingEnvironment"); - } - - @BeforeEach - public void setupEntityRefs() { - pos[0] = new Vector3f(16, 0, 16); - pos[1] = new Vector3f(16, 0, -16); - pos[2] = new Vector3f(-16, 0, 16); - pos[3] = new Vector3f(-16, 0, -16); - pos[4] = new Vector3f(0, 0, 0); - pos[5] = new Vector3f(32, 0, 32); - pos[6] = new Vector3f(32, 0, -32); - pos[7] = new Vector3f(-32, 0, 32); - pos[8] = new Vector3f(-32, 0, -32); - pos[9] = new Vector3f(97, 0, -97); - - regionEntityManager = getHostContext().get(RegionEntityManager.class); - - test = new EntityRef[10]; - LocationComponent[] loc = new LocationComponent[test.length]; - for (int i = 0; i < test.length; i++) { - test[i] = Mockito.mock(EntityRef.class); - loc[i] = new LocationComponent(pos[i]); - Mockito.when(test[i].getComponent(LocationComponent.class)).thenReturn(loc[i]); - regionEntityManager.add(test[i]); - } - } - - @Disabled("failing with resolution error with gestalt v5 - re-enable after gestalt v7 migration") - @Test - public void testSimpleGet() { - for (int i = 0; i < test.length; i++) { - assertEquals(test[i], regionEntityManager.get(new Vector2i(pos[i].x(), pos[i].z(), RoundingMode.FLOOR))); - } - } - - @Disabled - @Test - public void testNearestGet() { - assertEquals(test[0], regionEntityManager.getNearest(new Vector2i(21, 13))); - assertEquals(test[1], regionEntityManager.getNearest(new Vector2i(14, -13))); - assertEquals(test[2], regionEntityManager.getNearest(new Vector2i(-22, 19))); - assertEquals(test[3], regionEntityManager.getNearest(new Vector2i(-13, -19))); - } - - @Disabled("failing with resolution error with gestalt v5 - re-enable after gestalt v7 migration") - @Test - public void testIsLoaded() { - assertTrue(regionEntityManager.cellIsLoaded(new Vector2i(0, 0))); - assertTrue(regionEntityManager.cellIsLoaded(new Vector2i(16, 0))); - assertTrue(regionEntityManager.cellIsLoaded(new Vector2i(0, -25))); - assertFalse(regionEntityManager.cellIsLoaded(new Vector2i(98, -124))); - assertFalse(regionEntityManager.cellIsLoaded(new Vector2i(351, 234))); - assertFalse(regionEntityManager.cellIsLoaded(new Vector2i(153, -134))); - } - - @Disabled - @Test - public void testGetRegionsInCell() { - List testList = new ArrayList<>(); - testList.addAll(Arrays.asList(test).subList(0, 5)); - assertEquals(testList, regionEntityManager.getRegionsInCell(new Vector2i(0, 0))); - } -}