/*
* Aphelion
* Copyright (c) 2013 Joris van der Wel
*
* This file is part of Aphelion
*
* Aphelion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Aphelion 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 Affero General Public License
* along with Aphelion. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, the following supplemental terms apply, based on section 7 of
* the GNU Affero General Public License (version 3):
* a) Preservation of all legal notices and author attributions
* b) Prohibition of misrepresentation of the origin of this material, and
* modified versions are required to be marked in reasonable ways as
* different from the original version (for example by appending a copyright notice).
*
* Linking this library statically or dynamically with other modules is making a
* combined work based on this library. Thus, the terms and conditions of the
* GNU Affero General Public License cover the whole combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent modules,
* and to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent module,
* the terms and conditions of the license of that module. An independent
* module is a module which is not derived from or based on this library.
*/
package aphelion.shared.physics;
import aphelion.shared.gameconfig.ConfigSelection;
import aphelion.shared.gameconfig.GameConfig;
import aphelion.shared.physics.entities.ActorPublic;
import aphelion.shared.physics.valueobjects.PhysicsMovement;
import aphelion.shared.physics.valueobjects.PhysicsShipPosition;
import aphelion.shared.swissarmyknife.EvenSteinhausJohnsonTrotterIterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
/**
*
* @author Joris
*/
public class ConsistencyFuzz
{
private static interface Command
{
void execute();
}
List<Object> yamlDocuments;
private SimpleEnvironment env;
private ConfigSelection conf;
private final Command tick = new Command()
{
public void execute()
{
env.tick();
}
};
public ConsistencyFuzz()
{
try
{
yamlDocuments = GameConfig.loadYaml(
"- ship-radius: 14336\n"
+ " ship-bounce-friction: 600\n"
+ " ship-bounce-friction-other-axis: 900 \n"
+ " ship-rotation-speed: 3800000 \n"
+ " ship-rotation-points: 40\n"
+ " ship-speed: 2624\n"
+ " ship-thrust: 28\n"
+ " ship-boost-speed: 1000\n"
+ " ship-boost-thrust: 120\n"
+ " ship-boost-energy: 2500000\n"
+ " ship-energy: 10000\n"
+ " ship-recharge: 1\n"
+ " ship-spawn-x: 13\n"
+ " ship-spawn-y: 8\n"
+ " ship-respawn-delay: 3\n"
+ " weapon-fire-energy: 1000\n"
+ " weapon-fire-delay: 5\n"
+ " weapon-projectiles: 1\n"
+ " projectile-offset-y: 14336\n"
+ " projectile-bounce-friction: 1024\n"
+ " projectile-bounce-friction-other-axis: 1024 \n"
+ " projectile-speed: 20000\n"
+ " projectile-speed-relative: true\n"
+ " projectile-angle-relative: true\n"
+ " projectile-expiration-ticks: 1000\n"
+ " projectile-damage: 5000\n"
+ " projectile-emp-ticks: 5\n"
+ "");
}
catch (Exception ex)
{
throw new Error(ex);
}
}
private ConfigSelection applyTestSettings(PhysicsEnvironment env)
{
env.loadConfig(env.getTick() - env.getConfig().HIGHEST_DELAY, "test", yamlDocuments);
return env.newConfigSelection();
}
@Test
@Ignore
public void testWeapon()
{
// O(n!)
Command[] commands = new Command[]
{
// tick 0
new Command(){public void execute(){ env.actorNew(1, 1, 357436389, "warbird"); }},
new Command(){public void execute(){ env.actorWarp(2, 1, false, 200000, 150000, -1000, 0, EnvironmentConf.ROTATION_1_4TH); }},
new Command(){public void execute(){ env.actorMove(3, 1, PhysicsMovement.get(false, true, false, true, true)); }},
new Command(){public void execute(){ env.actorMove(4, 1, PhysicsMovement.get(true, false, false, false, false)); }},
new Command(){public void execute(){ env.actorMove(10, 1, PhysicsMovement.get(true, true, false, false, true)); }},
new Command(){public void execute(){ env.actorMove(16, 1, PhysicsMovement.get(false, true, false, true, true)); }},
new Command(){public void execute(){ env.actorMove(20, 1, PhysicsMovement.get(true, true, true, true, true)); }},
new Command(){public void execute(){ env.actorMove(3, 1, PhysicsMovement.get(false, true, true, true, true)); }},
};
EvenSteinhausJohnsonTrotterIterator it = new EvenSteinhausJohnsonTrotterIterator(commands.length);
int iterations = 1;
for (int i = 1; i <= commands.length; ++i)
{
iterations *= i;
}
Logger.getLogger("aphelion.shared.physics").setLevel(Level.OFF); // speed up execution
int iteration = 0;
long startNano = System.nanoTime();
while (it.hasNext())
{
++iteration;
env = new SimpleEnvironment(false, new MapEmpty());
conf = applyTestSettings(env);
testWeapon_doTest(commands, it.next());
if (iteration % 10000 == 0)
{
long now = System.nanoTime();
// (now - startNano) / iteration * (iterations - iteration)
System.out.printf("Progress: %d of %d. Seconds left: %f\n",
iteration,
iterations,
(now - startNano) / iteration * (iterations - iteration) / 1_000_000_000.0);
}
}
Logger.getGlobal().setLevel(Level.ALL);
}
private void testWeapon_doTest(Command[] commands, int[] order)
{
while (env.tick_now < 16)
{
env.tick();
}
for (int i = 0; i < order.length; ++i)
{
commands[order[i]].execute();
}
// this stuff needs to be adjusted if any of the constants in PhysicsEnvironment change
while (env.tick_now < 16 * 2)
{
env.tick();
}
assertPosition(0, 1, 170353,149891, -999, -6, 191383600);
assertEquals(240030, env.getActor(1, 0, false).getEnergy());
assertPosition(1, 1, 186337, 149987, -1091, -8, 191383600);
assertEquals(2740014, env.getActor(1, 1, false).getEnergy());
assert env.consistencyCheck();
}
private void assertPosition(int stateid, int pid, int x, int y, int x_vel, int y_vel, int rot)
{
ActorPublic actor = env.getActor(pid, stateid, false);
PhysicsShipPosition pos = new PhysicsShipPosition();
assertTrue(actor.getPosition(pos));
if (x != pos.x || y != pos.y)
{
throw new AssertionError("expected position:<" + x + "," + y + "> but was:<" + pos.x + "," + pos.y + ">");
}
if (x_vel != pos.x_vel || y_vel != pos.y_vel)
{
throw new AssertionError("expected velocity:<" + x_vel + "," + y_vel + "> but was:<" + pos.x_vel + "," + pos.y_vel + ">");
}
assertEquals(rot, pos.rot);
assertTrue(actor.getHistoricPosition(pos, env.getTick(stateid), false));
if (x != pos.x || y != pos.y)
{
throw new AssertionError("getHistoricPosition(0) is not equal to the current position!");
}
if (x_vel != pos.x_vel || y_vel != pos.y_vel)
{
throw new AssertionError("getHistoricPosition(0) is not equal to the current velocity!");
}
assertEquals(rot, pos.rot);
}
}