/* * 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.client.graphics; import aphelion.client.graphics.world.ActorShip; import aphelion.client.graphics.world.MapEntities; import aphelion.shared.event.TickEvent; import aphelion.shared.gameconfig.ConfigSelection; import aphelion.shared.gameconfig.GameConfig; import aphelion.shared.net.game.NetworkedActor; import aphelion.shared.physics.PhysicsEnvironment; import aphelion.shared.physics.WEAPON_SLOT; import aphelion.shared.physics.valueobjects.PhysicsMovement; import aphelion.shared.resource.ResourceDB; import java.io.InputStream; import java.util.Iterator; import java.util.List; import java.util.TreeSet; /** * * @author Joris */ public abstract class Scenario implements TickEvent { protected PhysicsEnvironment env; protected MapEntities mapEntities; private ResourceDB resourceDB; protected ConfigSelection config; private final TreeSet<Todo> todo = new TreeSet<>(); public static final int ACTOR_LOCAL = 1; public static final int ACTOR_2 = 2; public static final int ACTOR_3 = 3; public Scenario() { } protected abstract String getConfig(); protected abstract void setup(); public final void doSetup(PhysicsEnvironment env, MapEntities mapEntities, ResourceDB resourceDB) { this.env = env; this.mapEntities = mapEntities; this.resourceDB = resourceDB; List<Object> yamlDocuments; try { // default config InputStream in = Scenario.class.getResourceAsStream("/client/graphics/scenario.game.yaml"); assert in != null; yamlDocuments = GameConfig.loadYaml(in); } catch (Exception ex) { throw new Error(ex); } env.loadConfig(env.getTick() - env.getConfig().HIGHEST_DELAY, "scenario.game.yaml", yamlDocuments); String implConfig = this.getConfig(); if (implConfig != null) { try { yamlDocuments = GameConfig.loadYaml(implConfig); } catch (Exception ex) { throw new Error(ex); } env.loadConfig(env.getTick() - env.getConfig().HIGHEST_DELAY, "impl", yamlDocuments); } this.config = env.newConfigSelection(); setup(); } @Override public void tick(long unused) { Iterator<Todo> it = todo.iterator(); while (it.hasNext()) { Todo t = it.next(); if (t.arriveAt_tick > env.getTick()) { break; // done for now } it.remove(); t.run(); } } public final void actorNew(long tick, int pid, long seed, String ship) { env.actorNew(tick, pid, seed, ship); ActorShip actorShip = new ActorShip( resourceDB, new NetworkedActor(pid, pid == ACTOR_LOCAL, "Player " + pid), env.getActor(pid, true), mapEntities); mapEntities.addShip(actorShip); } public final void actorWarp(long executeAt_tick, final long tick, final int pid, final boolean hint, final int x, final int y, final int x_vel, final int y_vel, final int rotation) { if (executeAt_tick <= env.getTick()) { env.actorWarp(tick, pid, hint, x, y, x_vel, y_vel, rotation); return; } todo.add(new Todo(executeAt_tick) { @Override void run() { env.actorWarp(tick, pid, hint, x, y, x_vel, y_vel, rotation); } }); } public final void actorMove(long executeAt_tick, final long tick, final int pid, final PhysicsMovement move) { if (executeAt_tick <= env.getTick()) { env.actorMove(tick, pid, move); RenderDelay renderDelayHandler = mapEntities.getRenderDelay(); if (renderDelayHandler != null) { renderDelayHandler.receivedMove(pid, tick); } return; } todo.add(new Todo(executeAt_tick) { @Override void run() { env.actorMove(tick, pid, move); RenderDelay renderDelayHandler = mapEntities.getRenderDelay(); if (renderDelayHandler != null) { renderDelayHandler.receivedMove(pid, tick); } } }); } public final void actorWeapon( long executeAt_tick, final long tick, final int pid, final WEAPON_SLOT weapon_slot) { if (executeAt_tick <= env.getTick()) { env.actorWeapon(tick, pid, weapon_slot, false, 0, 0, 0, 0, 0); return; } todo.add(new Todo(executeAt_tick) { @Override void run() { env.actorWeapon(tick, pid, weapon_slot, false, 0, 0, 0, 0, 0); } }); } public final void actorWeapon( long executeAt_tick, final long tick, final int pid, final WEAPON_SLOT weapon_slot, final boolean hint_set, final int hint_x, final int hint_y, final int hint_x_vel, final int hint_y_vel, final int hint_snapped_rotation) { if (executeAt_tick <= env.getTick()) { env.actorWeapon(tick, pid, weapon_slot, hint_set, hint_x, hint_y, hint_x_vel, hint_y_vel, hint_snapped_rotation); return; } todo.add(new Todo(executeAt_tick) { @Override void run() { env.actorWeapon(tick, pid, weapon_slot, hint_set, hint_x, hint_y, hint_x_vel, hint_y_vel, hint_snapped_rotation); } }); } private static abstract class Todo implements Comparable<Todo> { private static long next_seq; final long arriveAt_tick; private final long seq; Todo(long arriveAt_tick) { this.arriveAt_tick = arriveAt_tick; seq = ++next_seq; } abstract void run(); @Override public int compareTo(Todo o) { int c = Long.compare(arriveAt_tick, o.arriveAt_tick); if (c == 0) { return Long.compare(seq, o.seq); } return c; } } }