/* * Copyright (c) 2015 NOVA, All rights reserved. * This library is free software, licensed under GNU Lesser General Public License version 3 * * This file is part of NOVA. * * NOVA is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NOVA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NOVA. If not, see <http://www.gnu.org/licenses/>. */ package nova.core.util; import nova.core.block.Block; import nova.core.block.BlockFactory; import nova.core.block.BlockManager; import nova.core.component.misc.Collider; import nova.core.entity.Entity; import nova.core.entity.EntityFactory; import nova.core.entity.EntityManager; import nova.core.event.bus.GlobalEvents; import nova.core.loader.Mod; import nova.core.util.math.RotationUtil; import nova.internal.core.launch.NovaLauncher; import nova.testutils.FakeWorld; import nova.wrappertests.NovaLauncherTestFactory; import org.apache.commons.math3.geometry.euclidean.threed.Rotation; import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.List; import java.util.stream.Collectors; import static nova.testutils.NovaAssertions.assertThat; /** * @author Calclavia */ public class RayTraceTest { static NovaLauncher launcher; FakeWorld fakeWorld; @BeforeClass public static void init() { launcher = NovaLauncherTestFactory.createDummyLauncher(RayTraceMod.class); } @Before public void setup() { fakeWorld = new FakeWorld(); } @Test public void testRayTraceBlock() { fakeWorld.setBlock(new Vector3D(5, 5, 5), RayTraceMod.solid); List<RayTracer.RayTraceBlockResult> rayTraceBlockResults1 = new RayTracer(new Ray(new Vector3D(5.5, 0, 5.5), new Vector3D(0, 1, 0))) .setDistance(6) .rayTraceBlocks(fakeWorld) .collect(Collectors.toList()); assertThat(rayTraceBlockResults1).hasSize(1); assertThat(rayTraceBlockResults1.get(0).block.position()).isEqualTo(new Vector3D(5, 5, 5)); fakeWorld.setBlock(new Vector3D(6, 5, 5), RayTraceMod.solid); List<RayTracer.RayTraceBlockResult> rayTraceBlockResults2 = new RayTracer(new Ray(new Vector3D(0, 5.5, 5.5), new Vector3D(1, 0, 0))) .setDistance(7) .rayTraceBlocks(fakeWorld) .collect(Collectors.toList()); assertThat(rayTraceBlockResults2).hasSize(2); assertThat(rayTraceBlockResults2.get(0).block.position()).isEqualTo(new Vector3D(5, 5, 5)); } @Test public void testRayTraceTunnel() { Vector3D start = new Vector3D(2, 7, 3); //Create a tunnel for (int i = 0; i < 5; i++) for (int d = 0; d < 4; d++) fakeWorld.setBlock(start.add(Direction.fromOrdinal(d).toVector()), RayTraceMod.solid); fakeWorld.setBlock(new Vector3D(5, 7, 3), RayTraceMod.solid); List<RayTracer.RayTraceBlockResult> rayTraceBlockResults1 = new RayTracer(new Ray(new Vector3D(0, 7.5, 3.5), new Vector3D(1, 0, 0))) .setDistance(10) .rayTraceBlocks(fakeWorld) .collect(Collectors.toList()); assertThat(rayTraceBlockResults1).hasSize(1); RayTracer.RayTraceBlockResult rayTraceBlockResult = rayTraceBlockResults1.get(0); assertThat(rayTraceBlockResult.block.position()).isEqualTo(new Vector3D(5, 7, 3)); assertThat(rayTraceBlockResult.hit).isEqualTo(new Vector3D(5, 7.5, 3.5)); } @Test public void testRayTraceEntity() { fakeWorld.setBlock(new Vector3D(5, 5, 5), RayTraceMod.solid); Entity entity = fakeWorld.addEntity(RayTraceMod.testEntity); entity.setPosition(new Vector3D(5.1, 0, 5.1)); entity.setRotation(new Rotation(RotationUtil.DEFAULT_ORDER, 0, Math.PI / 2, 0)); RayTracer rayTracer = new RayTracer(entity).setDistance(10); List<RayTracer.RayTraceBlockResult> rayTraceBlockResults = rayTracer.rayTraceBlocks(fakeWorld).collect(Collectors.toList()); assertThat(rayTraceBlockResults.size()).isEqualTo(1); } @Test public void testEdge() { fakeWorld.setBlock(new Vector3D(0, 0, 2), RayTraceMod.solid); List<RayTracer.RayTraceBlockResult> rayTraceBlockResults1 = new RayTracer(Ray.fromInterval(Vector3D.ZERO, Direction.SOUTH.toVector().add(new Vector3D(0.1, 0.1, 0)))) .setDistance(10) .rayTraceBlocks(fakeWorld) .collect(Collectors.toList()); assertThat(rayTraceBlockResults1).hasSize(1); RayTracer.RayTraceBlockResult res = rayTraceBlockResults1.get(0); assertThat(res.side).isEqualTo(Direction.NORTH); } //TODO: Make ray trace entity unit test @Mod(id = "rayTrace", name = "ray", version = "1.0", novaVersion = "0.0.1") public static class RayTraceMod { public static BlockFactory solid; public static EntityFactory testEntity; public RayTraceMod(GlobalEvents events, BlockManager blockManager, EntityManager entityManager) { events.on(BlockManager.Init.class).bind(evt -> this.registerBlocks(evt.manager)); events.on(EntityManager.Init.class).bind(evt -> this.registerEntities(evt.manager)); } public void registerBlocks(BlockManager blockManager) { solid = blockManager.register( "solid", () -> { Block solid = new Block(); solid.components.add(new Collider(solid)); return solid; } ); } private void registerEntities(EntityManager entityManager) { testEntity = entityManager.register("test", Entity::new); } } }