/*
* 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.events;
import aphelion.shared.physics.SimpleEnvironment;
import aphelion.shared.physics.State;
import aphelion.shared.physics.entities.Actor;
import aphelion.shared.physics.entities.ActorKey;
import aphelion.shared.physics.events.pub.ActorDiedPublic;
import aphelion.shared.physics.events.pub.EventPublic;
import aphelion.shared.swissarmyknife.SwissArmyKnife;
import java.util.Objects;
import java.util.logging.Logger;
/**
* @author Joris
*/
public class ActorDied extends Event implements ActorDiedPublic
{
private static final Logger log = Logger.getLogger("aphelion.shared.physics");
private final History[] history;
public ActorDied(SimpleEnvironment env, Key key)
{
super(env, key);
history = new History[env.econfig.TRAILING_STATES];
for (int a = 0; a < env.econfig.TRAILING_STATES; ++a)
{
history[a] = new History();
}
}
@Override
public Event cloneWithoutHistory(SimpleEnvironment env)
{
return new ActorDied(env, (Key) this.key);
}
public void execute(long tick, State state, Actor died, Event cause, Actor killer)
{
super.execute(tick, state);
assert died != null;
assert state == died.state;
assert died.dead.get(tick) == 1 : "The actor should have been marked as dead before calling this event";
if (SwissArmyKnife.assertEnabled)
{
for (int s = 0; s < history.length; ++s)
{
if (history[s].cause != null)
{
// Events are 1:1 on PhysicsEnvironment, not states
// This event should also be spawned by the same cause in every state
assert history[s].cause == cause;
}
}
}
History hist = history[state.id];
hist.set = true;
hist.tick = tick;
hist.died = died;
hist.cause = cause;
hist.killer = killer;
// nothing interesting to do yet, at the moment this event is only used for external notification
}
@Override
public boolean isConsistent(State older, State newer)
{
// This event is called by the result of other events.
// Those events already check consistency.
return true;
}
@Override
public void resetExecutionHistory(State state, State resetTo, Event resetToEvent)
{
History histFrom = ((ActorDied) resetToEvent).history[resetTo.id];
History histTo = history[state.id];
histTo.set(histFrom, state);
}
@Override
public void resetToEmpty(State state)
{
History histTo = history[state.id];
histTo.set(new History(), state);
}
@Override
public long getOccurredAt(int stateid)
{
History hist = history[stateid];
if (!hist.set)
{
return 0; // use hasOccurred first
}
return hist.tick;
}
@Override
public boolean hasOccurred(int stateid)
{
History hist = history[stateid];
return hist.set;
}
@Override
public EventPublic getCause(int stateid)
{
History hist = history[stateid];
return hist.cause;
}
@Override
public int getDied(int stateid)
{
History hist = history[stateid];
return hist.died == null ? 0 : hist.died.pid;
}
@Override
public int getKiller(int stateid)
{
History hist = history[stateid];
return hist.killer == null ? 0 : hist.killer.pid;
}
private static class History
{
boolean set = false;
long tick;
Actor died;
Event cause;
Actor killer;
public void set(History other, State myState)
{
set = other.set;
tick = other.tick;
cause = other.cause == null ? null : other.cause.findInOtherEnv(myState.env);
died = other.died == null ? null : other.died.findInOtherState(myState);
killer = other.killer == null ? null : other.killer.findInOtherState(myState);
}
}
public static final class Key implements EventKey
{
private final ProjectileExplosion.Key causedBy;
private final ActorKey died;
public Key(ProjectileExplosion.Key causedBy, ActorKey died)
{
if (causedBy == null || died == null)
{
throw new IllegalArgumentException();
}
this.causedBy = causedBy;
this.died = died;
}
@Override
public int hashCode()
{
int hash = 7;
hash = 67 * hash + Objects.hashCode(this.causedBy);
hash = 67 * hash + Objects.hashCode(this.died);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (!(obj instanceof Key))
{
return false;
}
final Key other = (Key) obj;
if (!Objects.equals(this.causedBy, other.causedBy))
{
return false;
}
if (!Objects.equals(this.died, other.died))
{
return false;
}
return true;
}
}
}