From b565f2b4e6f30a1d1d6aedfdcc62e1f41e6ce9cd Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Tue, 14 Jun 2022 15:39:10 -0700 Subject: [PATCH 1/3] WIP! test: save and load --- .../system/WildAnimalsSpawnSystem.java | 6 +- .../system/WildAnimalsSpawnSystemTest.java | 187 ++++++++++++++++++ src/test/resources/logback-test.xml | 42 ++++ 3 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java create mode 100644 src/test/resources/logback-test.xml diff --git a/src/main/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystem.java b/src/main/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystem.java index 61fcdd1..04bc43e 100644 --- a/src/main/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystem.java +++ b/src/main/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystem.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Terasology Foundation +// Copyright 2022 The Terasology Foundation // SPDX-License-Identifier: Apache-2.0 package org.terasology.wildAnimals.system; @@ -30,7 +30,7 @@ import java.util.Random; import java.util.function.Function; -@Share(value = WildAnimalsSpawnSystem.class) +@Share(WildAnimalsSpawnSystem.class) @RegisterSystem(RegisterMode.AUTHORITY) public class WildAnimalsSpawnSystem extends BaseComponentSystem { private AnimalSpawnConfig config; @@ -123,7 +123,7 @@ public void onChunkGenerated(OnChunkGenerated event, EntityRef worldEntity) { * * @param chunkPos The chunk which the game will try to spawn deers on */ - private void tryFlockAnimalSpawn(Prefab animalPrefab, Vector3ic chunkPos) { + void tryFlockAnimalSpawn(Prefab animalPrefab, Vector3ic chunkPos) { List foundPositions = findFlockAnimalSpawnPositions(chunkPos); if (foundPositions.size() < config.minFlockSize * config.minGroundPerFlockAnimal) { diff --git a/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java new file mode 100644 index 0000000..225fb62 --- /dev/null +++ b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java @@ -0,0 +1,187 @@ +// Copyright 2022 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.wildAnimals.system; + +import com.google.common.collect.Lists; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector3ic; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.engine.config.Config; +import org.terasology.engine.config.SystemConfig; +import org.terasology.engine.context.Context; +import org.terasology.engine.core.GameEngine; +import org.terasology.engine.core.PathManager; +import org.terasology.engine.core.Time; +import org.terasology.engine.core.bootstrap.EntitySystemSetupUtil; +import org.terasology.engine.core.module.ModuleManager; +import org.terasology.engine.core.subsystem.EngineSubsystem; +import org.terasology.engine.entitySystem.entity.EntityManager; +import org.terasology.engine.entitySystem.entity.EntityRef; +import org.terasology.engine.entitySystem.entity.internal.EngineEntityManager; +import org.terasology.engine.entitySystem.prefab.PrefabManager; +import org.terasology.engine.integrationenvironment.MainLoop; +import org.terasology.engine.integrationenvironment.jupiter.Dependencies; +import org.terasology.engine.integrationenvironment.jupiter.IntegrationEnvironment; +import org.terasology.engine.integrationenvironment.jupiter.MTEExtension; +import org.terasology.engine.logic.location.LocationComponent; +import org.terasology.engine.logic.players.LocalPlayer; +import org.terasology.engine.persistence.StorageManager; +import org.terasology.engine.persistence.internal.ReadWriteStorageManager; +import org.terasology.engine.rendering.logic.SkeletalMeshComponent; +import org.terasology.engine.world.WorldProvider; +import org.terasology.engine.world.block.BlockManager; +import org.terasology.engine.world.block.BlockRegion; +import org.terasology.engine.world.chunks.Chunks; +import org.terasology.engine.world.chunks.blockdata.ExtraBlockDataManager; +import org.terasology.wildAnimals.AnimalSpawnConfig; +import reactor.core.publisher.Flux; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@Tag("MteTest") +@ExtendWith(MTEExtension.class) +@Dependencies("WildAnimals") +@IntegrationEnvironment(subsystem = WildAnimalsSpawnSystemTest.WriteSaveGames.class) +@Timeout(3600) +class WildAnimalsSpawnSystemTest { + + private static final Logger logger = LoggerFactory.getLogger(WildAnimalsSpawnSystemTest.class); + + Set inhabitedChunks = new HashSet<>(); + + @BeforeAll + void configSpawn(WildAnimalsSpawnSystem spawnSystem, WorldProvider worldProvider) { + var config = new AnimalSpawnConfig(); + config.spawnChanceInPercent = 100; + config.minFlockSize = 1; + config.minGroundPerFlockAnimal = 1; + spawnSystem.setConfig(config); + + // Spawn on any solid ground. + spawnSystem.setSpawnCondition(pos -> { + Vector3i below = new Vector3i(pos.x, pos.y - 1, pos.z); + return worldProvider.getBlock(pos).isPenetrable() + && !worldProvider.getBlock(below).isPenetrable(); + }); + } + + @Test + @Order(1) + void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer player, MainLoop main, + WildAnimalsSpawnSystem spawnSystem, PrefabManager prefabs) { + var character = player.getCharacterEntity(); + var loc = character.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); + main.runUntil(main.makeBlocksRelevant(new BlockRegion((int) loc.x, (int) loc.y, (int) loc.z) + .expand(100, 0, 100))); + +// var sheepPrefab = prefabs.getPrefab("WildAnimals:sheep"); +// spawnSystem.tryFlockAnimalSpawn(sheepPrefab, Chunks.toChunkPos(loc, new Vector3i())); +// +// main.runUntil(new Ticks(1)); + + assertThat(entities.getEntitiesWith(SkeletalMeshComponent.class)).isNotEmpty(); + + var animalPosition = Flux.fromIterable(entities.getEntitiesWith(SkeletalMeshComponent.class, LocationComponent.class)) + .map(e -> e.getComponent(LocationComponent.class).getWorldPosition(new Vector3f())) + .map(v -> (Vector3ic) Chunks.toChunkPos(v, new Vector3i())) + .collect(Collectors.toUnmodifiableSet()) + .block(); + inhabitedChunks.addAll(animalPosition); + + storage.waitForCompletionOfPreviousSaveAndStartSaving(); + storage.finishSavingAndShutdown(); + } + + @Test + @Order(2) + void testCanLoad(ModuleManager modules, + BlockManager blockManager, ExtraBlockDataManager extraDataManager, + Context context, Config config, MainLoop main, Time time) throws IOException { + // MTE does not include helpers for loading from a save file. + // This is kludged together from StorageManagerTest internals. + EntitySystemSetupUtil.addReflectionBasedLibraries(context); + EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); + EngineEntityManager newEntityManager = context.getValue(EngineEntityManager.class); + StorageManager newSM = new ReadWriteStorageManager(getSavePath(config), modules.getEnvironment(), newEntityManager, blockManager, + extraDataManager, null, null, null); + context.put(StorageManager.class, newSM); + + newSM.loadGlobalStore(); + + for (Vector3ic chunk : inhabitedChunks) { + var restored = newSM.loadChunkStore(chunk); + /* var dudes = */ restored.restoreEntities(); + /* logger.warn("restored dudes in {} '{}'", chunk, dudes); */ + } + +// var later = time.getGameTime() + 2; +// main.runUntil(() -> time.getGameTime() > later); + + var animals = Lists.newArrayList(newEntityManager.getEntitiesWith(SkeletalMeshComponent.class)); + assertThat(animals).isNotNull(); + assertThat(animals).isNotEmpty(); + for (EntityRef animal : animals) { + var skeleton = animal.getComponent(SkeletalMeshComponent.class); + assertThat(skeleton.boneEntities).isNotNull(); + assertThat(skeleton.boneEntities).isNotEmpty(); + skeleton.boneEntities.forEach((name, boneEnt) -> + assertWithMessage("Bone \"%s\"", name).that(boneEnt).isNotEqualTo(EntityRef.NULL)); + } + } + + // copied in from StorageManagerTest + Path getSavePath(Config config) { + // TODO: add a more direct way of inspecting StorageManager's path. + // This way of getting the game title (and thus the path) is a bit brittle, + // because world title and game title are not _required_ to be identical. + String gameTitle = config.getWorldGeneration().getWorldTitle(); + return PathManager.getInstance().getSavePath(gameTitle); + } + + static class WriteSaveGames implements EngineSubsystem { + @Override + public String getName() { + return getClass().getCanonicalName(); + } + + @Override + public void initialise(GameEngine engine, Context rootContext) { + rootContext.getValue(SystemConfig.class).writeSaveGamesEnabled.set(true); + } + } + + static class Ticks implements Supplier { + private final AtomicInteger count; + Ticks(int initial) { + count = new AtomicInteger(initial); + } + + @Override + public Boolean get() { + return count.getAndDecrement() > 0; + } + } +} diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 0000000..9fe5ff0 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,42 @@ + + + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + From 158a008ec595daacf61fe8696bae66031859743a Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Thu, 16 Jun 2022 14:18:45 -0700 Subject: [PATCH 2/3] test: switch how we load the saved game --- .../system/WildAnimalsSpawnSystemTest.java | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java index 225fb62..9fb0e56 100644 --- a/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java +++ b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java @@ -7,7 +7,7 @@ import org.joml.Vector3f; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Tag; @@ -18,18 +18,14 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.engine.config.Config; import org.terasology.engine.config.SystemConfig; import org.terasology.engine.context.Context; import org.terasology.engine.core.GameEngine; import org.terasology.engine.core.PathManager; import org.terasology.engine.core.Time; -import org.terasology.engine.core.bootstrap.EntitySystemSetupUtil; -import org.terasology.engine.core.module.ModuleManager; import org.terasology.engine.core.subsystem.EngineSubsystem; import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.entity.internal.EngineEntityManager; import org.terasology.engine.entitySystem.prefab.PrefabManager; import org.terasology.engine.integrationenvironment.MainLoop; import org.terasology.engine.integrationenvironment.jupiter.Dependencies; @@ -38,17 +34,17 @@ import org.terasology.engine.logic.location.LocationComponent; import org.terasology.engine.logic.players.LocalPlayer; import org.terasology.engine.persistence.StorageManager; -import org.terasology.engine.persistence.internal.ReadWriteStorageManager; import org.terasology.engine.rendering.logic.SkeletalMeshComponent; +import org.terasology.engine.rendering.nui.layers.mainMenu.savedGames.GameProvider; import org.terasology.engine.world.WorldProvider; -import org.terasology.engine.world.block.BlockManager; import org.terasology.engine.world.block.BlockRegion; +import org.terasology.engine.world.block.BlockRegionc; import org.terasology.engine.world.chunks.Chunks; -import org.terasology.engine.world.chunks.blockdata.ExtraBlockDataManager; import org.terasology.wildAnimals.AnimalSpawnConfig; import reactor.core.publisher.Flux; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.HashSet; import java.util.Set; @@ -59,7 +55,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestInstance(TestInstance.Lifecycle.PER_METHOD) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @Tag("MteTest") @ExtendWith(MTEExtension.class) @@ -70,9 +66,11 @@ class WildAnimalsSpawnSystemTest { private static final Logger logger = LoggerFactory.getLogger(WildAnimalsSpawnSystemTest.class); - Set inhabitedChunks = new HashSet<>(); + @SuppressWarnings("checkstyle:ConstantName") + private static final Set inhabitedChunks = new HashSet<>(); + private static BlockRegionc relevantRegion; - @BeforeAll + @BeforeEach void configSpawn(WildAnimalsSpawnSystem spawnSystem, WorldProvider worldProvider) { var config = new AnimalSpawnConfig(); config.spawnChanceInPercent = 100; @@ -92,10 +90,13 @@ void configSpawn(WildAnimalsSpawnSystem spawnSystem, WorldProvider worldProvider @Order(1) void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer player, MainLoop main, WildAnimalsSpawnSystem spawnSystem, PrefabManager prefabs) { + assertThat(GameProvider.isSavesFolderEmpty()).isTrue(); + var character = player.getCharacterEntity(); var loc = character.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); - main.runUntil(main.makeBlocksRelevant(new BlockRegion((int) loc.x, (int) loc.y, (int) loc.z) - .expand(100, 0, 100))); + relevantRegion = new BlockRegion((int) loc.x, (int) loc.y, (int) loc.z) + .expand(100, 0, 100); + main.runUntil(main.makeBlocksRelevant(relevantRegion)); // var sheepPrefab = prefabs.getPrefab("WildAnimals:sheep"); // spawnSystem.tryFlockAnimalSpawn(sheepPrefab, Chunks.toChunkPos(loc, new Vector3i())); @@ -109,6 +110,7 @@ void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer pla .map(v -> (Vector3ic) Chunks.toChunkPos(v, new Vector3i())) .collect(Collectors.toUnmodifiableSet()) .block(); + inhabitedChunks.clear(); inhabitedChunks.addAll(animalPosition); storage.waitForCompletionOfPreviousSaveAndStartSaving(); @@ -117,30 +119,21 @@ void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer pla @Test @Order(2) - void testCanLoad(ModuleManager modules, - BlockManager blockManager, ExtraBlockDataManager extraDataManager, - Context context, Config config, MainLoop main, Time time) throws IOException { - // MTE does not include helpers for loading from a save file. - // This is kludged together from StorageManagerTest internals. - EntitySystemSetupUtil.addReflectionBasedLibraries(context); - EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); - EngineEntityManager newEntityManager = context.getValue(EngineEntityManager.class); - StorageManager newSM = new ReadWriteStorageManager(getSavePath(config), modules.getEnvironment(), newEntityManager, blockManager, - extraDataManager, null, null, null); - context.put(StorageManager.class, newSM); - - newSM.loadGlobalStore(); + void testCanLoad(StorageManager storage, EntityManager entities, MainLoop main, Time time) { + assertThat(GameProvider.getSavedGames()).hasSize(1); + main.runUntil(main.makeBlocksRelevant(relevantRegion)); for (Vector3ic chunk : inhabitedChunks) { - var restored = newSM.loadChunkStore(chunk); - /* var dudes = */ restored.restoreEntities(); - /* logger.warn("restored dudes in {} '{}'", chunk, dudes); */ + var restored = storage.loadChunkStore(chunk); + restored.restoreEntities(); + // var dudes = restored.restoreEntities(); + // logger.warn("restored dudes in {} '{}'", chunk, dudes); } -// var later = time.getGameTime() + 2; -// main.runUntil(() -> time.getGameTime() > later); + var later = time.getGameTime() + 2; + main.runUntil(() -> time.getGameTime() > later); - var animals = Lists.newArrayList(newEntityManager.getEntitiesWith(SkeletalMeshComponent.class)); + var animals = Lists.newArrayList(entities.getEntitiesWith(SkeletalMeshComponent.class)); assertThat(animals).isNotNull(); assertThat(animals).isNotEmpty(); for (EntityRef animal : animals) { @@ -152,23 +145,33 @@ void testCanLoad(ModuleManager modules, } } - // copied in from StorageManagerTest - Path getSavePath(Config config) { - // TODO: add a more direct way of inspecting StorageManager's path. - // This way of getting the game title (and thus the path) is a bit brittle, - // because world title and game title are not _required_ to be identical. - String gameTitle = config.getWorldGeneration().getWorldTitle(); - return PathManager.getInstance().getSavePath(gameTitle); - } - static class WriteSaveGames implements EngineSubsystem { + + private static Path homePath; + @Override public String getName() { return getClass().getCanonicalName(); } + @Override + public void preInitialise(Context rootContext) { + if (homePath != null) { + try { + logger.debug("Resetting home path to previously seen {}", homePath); + PathManager.getInstance().useOverrideHomePath(homePath); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + @Override public void initialise(GameEngine engine, Context rootContext) { + if (homePath == null) { + homePath = PathManager.getInstance().getHomePath(); + logger.debug("Home path first set to {}", homePath); + } rootContext.getValue(SystemConfig.class).writeSaveGamesEnabled.set(true); } } From de788279a43965e28610fc4ec03cf980bed4a8f7 Mon Sep 17 00:00:00 2001 From: Kevin Turner <83819+keturn@users.noreply.github.com> Date: Fri, 17 Jun 2022 08:30:29 -0700 Subject: [PATCH 3/3] test: clean some things up --- .../system/WildAnimalsSpawnSystemTest.java | 84 +++++-------------- 1 file changed, 23 insertions(+), 61 deletions(-) diff --git a/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java index 9fb0e56..de0026f 100644 --- a/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java +++ b/src/test/java/org/terasology/wildAnimals/system/WildAnimalsSpawnSystemTest.java @@ -6,7 +6,6 @@ import com.google.common.collect.Lists; import org.joml.Vector3f; import org.joml.Vector3i; -import org.joml.Vector3ic; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; @@ -14,7 +13,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,11 +20,9 @@ import org.terasology.engine.context.Context; import org.terasology.engine.core.GameEngine; import org.terasology.engine.core.PathManager; -import org.terasology.engine.core.Time; import org.terasology.engine.core.subsystem.EngineSubsystem; import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.prefab.PrefabManager; import org.terasology.engine.integrationenvironment.MainLoop; import org.terasology.engine.integrationenvironment.jupiter.Dependencies; import org.terasology.engine.integrationenvironment.jupiter.IntegrationEnvironment; @@ -38,19 +34,12 @@ import org.terasology.engine.rendering.nui.layers.mainMenu.savedGames.GameProvider; import org.terasology.engine.world.WorldProvider; import org.terasology.engine.world.block.BlockRegion; -import org.terasology.engine.world.block.BlockRegionc; -import org.terasology.engine.world.chunks.Chunks; import org.terasology.wildAnimals.AnimalSpawnConfig; -import reactor.core.publisher.Flux; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Path; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import java.util.stream.Collectors; +import java.util.List; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -61,15 +50,10 @@ @ExtendWith(MTEExtension.class) @Dependencies("WildAnimals") @IntegrationEnvironment(subsystem = WildAnimalsSpawnSystemTest.WriteSaveGames.class) -@Timeout(3600) class WildAnimalsSpawnSystemTest { private static final Logger logger = LoggerFactory.getLogger(WildAnimalsSpawnSystemTest.class); - @SuppressWarnings("checkstyle:ConstantName") - private static final Set inhabitedChunks = new HashSet<>(); - private static BlockRegionc relevantRegion; - @BeforeEach void configSpawn(WildAnimalsSpawnSystem spawnSystem, WorldProvider worldProvider) { var config = new AnimalSpawnConfig(); @@ -88,30 +72,15 @@ void configSpawn(WildAnimalsSpawnSystem spawnSystem, WorldProvider worldProvider @Test @Order(1) - void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer player, MainLoop main, - WildAnimalsSpawnSystem spawnSystem, PrefabManager prefabs) { + void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer player, MainLoop main) { assertThat(GameProvider.isSavesFolderEmpty()).isTrue(); - var character = player.getCharacterEntity(); - var loc = character.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); - relevantRegion = new BlockRegion((int) loc.x, (int) loc.y, (int) loc.z) - .expand(100, 0, 100); - main.runUntil(main.makeBlocksRelevant(relevantRegion)); - -// var sheepPrefab = prefabs.getPrefab("WildAnimals:sheep"); -// spawnSystem.tryFlockAnimalSpawn(sheepPrefab, Chunks.toChunkPos(loc, new Vector3i())); -// -// main.runUntil(new Ticks(1)); + loadRegionAroundPlayer(player, main); assertThat(entities.getEntitiesWith(SkeletalMeshComponent.class)).isNotEmpty(); - var animalPosition = Flux.fromIterable(entities.getEntitiesWith(SkeletalMeshComponent.class, LocationComponent.class)) - .map(e -> e.getComponent(LocationComponent.class).getWorldPosition(new Vector3f())) - .map(v -> (Vector3ic) Chunks.toChunkPos(v, new Vector3i())) - .collect(Collectors.toUnmodifiableSet()) - .block(); - inhabitedChunks.clear(); - inhabitedChunks.addAll(animalPosition); + var animals = Lists.newArrayList(entities.getEntitiesWith(SkeletalMeshComponent.class)); + assertEveryoneHasBones(animals); storage.waitForCompletionOfPreviousSaveAndStartSaving(); storage.finishSavingAndShutdown(); @@ -119,32 +88,37 @@ void testCanSave(EntityManager entities, StorageManager storage, LocalPlayer pla @Test @Order(2) - void testCanLoad(StorageManager storage, EntityManager entities, MainLoop main, Time time) { + void testCanLoad(EntityManager entities, LocalPlayer player, MainLoop main) { assertThat(GameProvider.getSavedGames()).hasSize(1); - main.runUntil(main.makeBlocksRelevant(relevantRegion)); - - for (Vector3ic chunk : inhabitedChunks) { - var restored = storage.loadChunkStore(chunk); - restored.restoreEntities(); - // var dudes = restored.restoreEntities(); - // logger.warn("restored dudes in {} '{}'", chunk, dudes); - } - var later = time.getGameTime() + 2; - main.runUntil(() -> time.getGameTime() > later); + loadRegionAroundPlayer(player, main); var animals = Lists.newArrayList(entities.getEntitiesWith(SkeletalMeshComponent.class)); + assertEveryoneHasBones(animals); + } + + private void loadRegionAroundPlayer(LocalPlayer player, MainLoop main) { + var character = player.getCharacterEntity(); + var loc = character.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); + var relevantRegion = new BlockRegion((int) loc.x, (int) loc.y, (int) loc.z) + .expand(100, 0, 100); + main.runUntil(main.makeBlocksRelevant(relevantRegion)); + } + + private void assertEveryoneHasBones(List animals) { assertThat(animals).isNotNull(); assertThat(animals).isNotEmpty(); for (EntityRef animal : animals) { var skeleton = animal.getComponent(SkeletalMeshComponent.class); - assertThat(skeleton.boneEntities).isNotNull(); - assertThat(skeleton.boneEntities).isNotEmpty(); + var a = assertWithMessage("Entity %s animal %s", animal, skeleton); + a.that(skeleton.boneEntities).isNotNull(); + a.that(skeleton.boneEntities).isNotEmpty(); skeleton.boneEntities.forEach((name, boneEnt) -> assertWithMessage("Bone \"%s\"", name).that(boneEnt).isNotEqualTo(EntityRef.NULL)); } } + /** @see Terasology#5050 */ static class WriteSaveGames implements EngineSubsystem { private static Path homePath; @@ -175,16 +149,4 @@ public void initialise(GameEngine engine, Context rootContext) { rootContext.getValue(SystemConfig.class).writeSaveGamesEnabled.set(true); } } - - static class Ticks implements Supplier { - private final AtomicInteger count; - Ticks(int initial) { - count = new AtomicInteger(initial); - } - - @Override - public Boolean get() { - return count.getAndDecrement() > 0; - } - } }