use of com.ixale.starparse.domain.Actor in project StarParse by Ixale.
the class Context method getActor.
public Actor getActor(final String name, final Type type, final Long guid, final Long instanceId, final String x, final String y, final String angle) {
if (instanceId == null) {
return getActor(name, type, guid);
}
if (guid == null) {
return getActor(name, type);
}
if (!actors.containsKey(instanceId)) {
final Raid raid = locationInfo == null || locationInfo.getInstanceGuid() == null ? null : Helpers.getRaidByInstanceGuid(locationInfo.getInstanceGuid());
if (raid != null && x != null && y != null && angle != null) {
final Raid.Npc npc = raid.getNpcs().get(guid);
try {
if (npc != null && npc.getNameResolver() != null) {
actors.put(instanceId, new Actor(npc.getNameResolver().getNpcName(npc.getName() == null ? name : npc.getName(), Float.valueOf(x), Float.valueOf(y), Float.valueOf(angle)), type, guid, instanceId));
return actors.get(instanceId);
}
} catch (Exception ignored) {
}
}
actors.put(instanceId, new Actor(name, type, guid, instanceId));
}
return actors.get(instanceId);
}
use of com.ixale.starparse.domain.Actor in project StarParse by Ixale.
the class Parser method getActor.
private Actor getActor(final String type, final long timestamp, final String effectGuid, final Matcher baseMatcher) {
if (baseMatcher.group(type + "CompanionName") != null) {
return context.getActor(baseMatcher.group(type + "CompanionName"), Actor.Type.COMPANION, Long.parseLong(baseMatcher.group(type + "CompanionGuid")));
}
if (baseMatcher.group(type + "PlayerName") != null) {
final String playerName = baseMatcher.group(type + "PlayerName");
return context.getActor(playerName, playerName.equals(combatLog.getCharacterName()) ? Actor.Type.SELF : Actor.Type.PLAYER);
}
if (baseMatcher.group(type + "NpcGuid") != null) {
// detect raid encounter
final long guid = Long.parseLong(baseMatcher.group(type + "NpcGuid"));
if (combat != null && combat.getBoss() == null) {
combat.setBoss(getRaidBoss(guid, instanceSize, instanceMode));
if (combat.getBoss() != null) {
Long eff = effectGuid == null || effectGuid.isEmpty() ? null : Long.valueOf(effectGuid);
if (eff != null && (eff.equals(EntityGuid.TargetSet.getGuid()) || eff.equals(EntityGuid.TargetCleared.getGuid()))) {
// ignore clicking on boss
combat.setBoss(null);
}
}
if (combat.getBoss() != null) {
if (logger.isDebugEnabled()) {
logger.debug("Boss detected as [" + combat.getBoss() + "] at " + Event.formatTs(timestamp));
if (Boolean.TRUE.equals(combat.isPvp())) {
logger.debug("Removed previously set PvP flag at " + Event.formatTs(timestamp));
}
}
// explicitly set to false (as it may be both, e.g. open world PvE grieving)
combat.setIsPvp(false);
// upgrades available?
combatBossUpgrade = isEffectiveLogged ? null : /* already set */
combat.getBoss().getPossibleUpgrade();
if (combatBossUpgrade != null && (instanceMode != null || instanceSize != null)) {
// try to use the already-confident mode and size for this instance
resolveCombatUpgrade(combatBossUpgrade.upgradeByModeAndSize(instanceMode, instanceSize), true);
}
if (combatBossUpgrade == null) {
instanceMode = combat.getBoss().getMode();
instanceSize = combat.getBoss().getSize();
}
}
}
if (combat != null && combatBossUpgrade != null) {
resolveCombatUpgrade(combatBossUpgrade.upgradeByNpc(guid), true);
}
final Actor actor = context.getActor(baseMatcher.group(type + "NpcName"), Actor.Type.NPC, guid, baseMatcher.group(type + "NpcInstance") != null ? Long.parseLong(baseMatcher.group(type + "NpcInstance")) : 0L, isEffectiveLogged ? baseMatcher.group(type + "X") : null, isEffectiveLogged ? baseMatcher.group(type + "Y") : null, isEffectiveLogged ? baseMatcher.group(type + "Angle") : null);
if (combat != null && combat.getBoss() != null && combat.getBoss().getRaid().getNpcs().containsKey(guid)) {
context.setCombatActorState(combat, actor, combat.getBoss().getRaid().getNpcs().get(guid), baseMatcher.group(type + "CurrentHp"), baseMatcher.group(type + "MaxHp"), timestamp - combat.getTimeFrom());
}
return actor;
}
throw new IllegalArgumentException("Invalid actor:" + " npcName[" + baseMatcher.group(type + "NpcName") + "]" + " npcGuid[" + baseMatcher.group(type + "NpcGuid") + "] at " + Event.formatTs(timestamp));
}
use of com.ixale.starparse.domain.Actor in project StarParse by Ixale.
the class Parser method parseLogLine.
public boolean parseLogLine(final String line) throws ParserException {
if (line == null) {
logger.warn("Empty line, ignoring");
return false;
}
if (combatLog == null) {
throw new RuntimeException("Enclosing combat log not set");
}
// match the combat log line
Matcher baseMatcher;
if (context.getVersion() == null) {
baseMatcher = v7ZonePattern.matcher(line);
if (baseMatcher.matches()) {
final long timestamp = getTimestamp(baseMatcher);
context.setVersion(baseMatcher.group("Version"));
context.setServerId(baseMatcher.group("ServerId"));
setCharacterName(getSourceActor(baseMatcher, timestamp, null), timestamp);
if (baseMatcher.group("InstanceName") != null && !baseMatcher.group("InstanceName").isEmpty()) {
parseInstanceType(baseMatcher.group("InstanceName"), baseMatcher.group("InstanceGuid"), baseMatcher.group("InstanceType"), baseMatcher.group("InstanceTypeGuid"), timestamp);
}
} else {
// cropped?
for (final Pattern v7pattern : Arrays.asList(v7BasePattern, v7ZonePattern, v7DisciplinePattern)) {
baseMatcher = v7pattern.matcher(line);
if (baseMatcher.matches()) {
// tentative, inconclusive
return false;
}
}
}
if (context.getVersion() == null) {
// give up
// legacy - default
context.setVersion("6.0.0");
}
if (context.getVersion().startsWith("7")) {
basePattern = v7BasePattern;
combatPattern = null;
zonePattern = v7ZonePattern;
disciplinePattern = v7DisciplinePattern;
ignorePattern = null;
isEffectiveLogged = true;
gsfPattern = v7GsfPattern;
} else {
basePattern = legacyBasePattern;
combatPattern = legacyCombatPattern;
zonePattern = null;
disciplinePattern = null;
ignorePattern = null;
isEffectiveLogged = false;
gsfPattern = legacyGsfPattern;
}
if (baseMatcher.matches()) {
logger.info("Version detected as " + context.getVersion());
return false;
}
}
baseMatcher = basePattern.matcher(line);
if (!baseMatcher.matches()) {
if (combatPattern != null) {
// fallback to combat enter/exit
baseMatcher = combatPattern.matcher(line);
}
if (!baseMatcher.matches()) {
if (disciplinePattern != null) {
baseMatcher = disciplinePattern.matcher(line);
if (baseMatcher.matches()) {
final long timestamp = getTimestamp(baseMatcher);
final Actor a = getSourceActor(baseMatcher, timestamp, null);
final CharacterDiscipline newDiscipline = CharacterDiscipline.fromGuid(baseMatcher.group("DisciplineGuid"));
if (newDiscipline != null) {
if (!Objects.equals(newDiscipline, a.getDiscipline())) {
if (logger.isDebugEnabled()) {
logger.debug(a + ": Discipline set as [" + newDiscipline + "] (was " + a.getDiscipline() + ") at " + Event.formatTs(getTimestamp(baseMatcher)));
}
a.setDiscipline(newDiscipline);
if (Actor.Type.SELF.equals(a.getType())) {
clearHotsTracking();
}
}
if (actorStates.containsKey(a)) {
actorStates.get(a).discipline = a.getDiscipline();
actorStates.get(a).role = a.getDiscipline().getRole();
}
}
return false;
}
}
if (zonePattern != null) {
baseMatcher = zonePattern.matcher(line);
if (baseMatcher.matches()) {
final long timestamp = getTimestamp(baseMatcher);
if (baseMatcher.group("InstanceName") != null && !baseMatcher.group("InstanceName").isEmpty()) {
parseInstanceType(baseMatcher.group("InstanceName"), baseMatcher.group("InstanceGuid"), baseMatcher.group("InstanceType"), baseMatcher.group("InstanceTypeGuid"), timestamp);
}
return false;
}
}
if (gsfPattern.matcher(line).matches()) {
// GSF combat line, ignore for now
return false;
}
if (ignorePattern != null && ignorePattern.matcher(line).matches()) {
// intentionally ignored
return false;
}
throw new ParserException("Invalid line");
}
}
// setup event
final Event e = new Event(++eventId, combatLogId, getTimestamp(baseMatcher));
if (e.getEventId() == 1) {
// adjust combat log start from the very first event
combatLog.setTimeFrom(e.getTimestamp());
}
// auto detect name if not already (pre v7)
if (combatLog.getCharacterName() == null && baseMatcher.group("SourcePlayerName") != null && !baseMatcher.group("SourcePlayerName").isEmpty() && baseMatcher.group("SourcePlayerName").equals(baseMatcher.group("TargetPlayerName"))) {
// found, set
setCharacterName(getSourceActor(baseMatcher, e.getTimestamp(), null), e.getTimestamp());
}
// source
if (baseMatcher.group("Source") != null && !baseMatcher.group("Source").isEmpty()) {
e.setSource(getSourceActor(baseMatcher, e.getTimestamp(), baseMatcher.group("EffectGuid")));
} else {
e.setSource(context.getActor("Unknown", Actor.Type.NPC));
}
// target
if (baseMatcher.group("Target") != null && !baseMatcher.group("Target").isEmpty()) {
if ("=".equals(baseMatcher.group("Target"))) {
e.setTarget(e.getSource());
} else {
e.setTarget(getTargetActor(baseMatcher, e.getTimestamp(), baseMatcher.group("EffectGuid")));
}
} else {
if (isEffectiveLogged) {
e.setTarget(e.getSource());
} else {
e.setTarget(context.getActor("Unknown", Actor.Type.NPC));
}
}
if (e.getSource() != null && (Actor.Type.PLAYER.equals(e.getSource().getType()) || Actor.Type.SELF.equals(e.getSource().getType()))) {
ActorState ac = actorStates.get(e.getSource());
if (ac == null) {
ac = new ActorState();
if (e.getSource().getDiscipline() != null) {
// v7+
ac.discipline = e.getSource().getDiscipline();
ac.role = e.getSource().getDiscipline().getRole();
}
if (combat != null && (isEffectiveLogged || Actor.Type.SELF.equals(e.getSource().getType()))) {
context.addCombatPlayer(combat, e.getSource(), ac.discipline);
}
actorStates.put(e.getSource(), ac);
if (Actor.Type.SELF.equals(e.getSource().getType())) {
//
} else {
if (logger.isDebugEnabled()) {
logger.debug("Added group player " + e.getSource() + " at " + e.getTs());
}
}
} else if (combat != null) {
if (isEffectiveLogged || Actor.Type.SELF.equals(e.getSource().getType())) {
context.addCombatPlayer(combat, e.getSource(), ac.discipline);
}
}
}
if (zonePattern == null && baseMatcher.group("Value") != null && "836045448945489".equals(baseMatcher.group("EffectGuid"))) {
// EnterCombat
// enter, any ops details? // pre v7
parseInstanceType(null, null, baseMatcher.group("Value"), null, e.getTimestamp());
}
// ability
if (baseMatcher.group("Ability") != null && !baseMatcher.group("Ability").isEmpty()) {
e.setAbility(getEntity(baseMatcher.group("AbilityName"), baseMatcher.group("AbilityGuid")));
}
// action
e.setAction(getEntity(baseMatcher.group("ActionName"), baseMatcher.group("ActionGuid")));
// effect
e.setEffect(getEntity(baseMatcher.group("EffectName"), baseMatcher.group("EffectGuid")));
// value (healing / damage)
if (baseMatcher.group("Value") != null && !EntityGuid.EnterCombat.toString().equals(baseMatcher.group("EffectGuid")) && !EntityGuid.ExitCombat.toString().equals(baseMatcher.group("EffectGuid"))) {
e.setValue(Integer.parseInt(baseMatcher.group("Value")));
// critical hit?
e.setCrit(baseMatcher.group("IsCrit") != null);
// damage
if (baseMatcher.group("DamageType") != null && !baseMatcher.group("DamageTypeGuid").equals(EntityGuid.Charges.toString())) {
e.setDamage(getEntity(baseMatcher.group("DamageType"), baseMatcher.group("DamageTypeGuid")));
}
// reflect
if (baseMatcher.group("ReflectType") != null) {
e.setReflect(getEntity(baseMatcher.group("ReflectType"), baseMatcher.group("ReflectTypeGuid")));
}
// mitigation
if (baseMatcher.group("IsMitigation") != null) {
if (baseMatcher.group("MitigationType") != null) {
e.setMitigation(getEntity(baseMatcher.group("MitigationType"), baseMatcher.group("MitigationTypeGuid")));
// attack type (incoming attacks to known actors only)
if (combat != null && actorStates.containsKey(e.getTarget())) {
processAttackType(e);
}
} else {
// unknown mitigation
e.setMitigation(getEntity("unknown", "-1"));
}
}
// absorption
if (baseMatcher.group("AbsorbValue") != null) {
e.setAbsorption(getEntity(baseMatcher.group("AbsorbType"), baseMatcher.group("AbsorbTypeGuid")));
e.setAbsorbed(Integer.parseInt(baseMatcher.group("AbsorbValue")));
if (e.getValue() != null && e.getAbsorbed() != null && e.getAbsorbed() > e.getValue()) {
e.setAbsorbed(e.getValue());
}
if (isEffectiveLogged) {
final String s;
if (e.getSource() == e.getTarget()) {
// no TargetMaxHp for [=]
s = baseMatcher.group("SourceMaxHp");
} else {
s = baseMatcher.group("TargetMaxHp");
}
final Integer maxHp = s == null ? null : Integer.valueOf(s);
if (maxHp != null && maxHp < e.getAbsorbed()) {
// looking at you, Ciphas & Doom
e.setAbsorbed(maxHp);
}
}
}
}
// threat
if (baseMatcher.group("Threat") != null) {
e.setThreat(Long.parseLong(baseMatcher.group("Threat")));
}
// guard
if (actorStates.containsKey(e.getSource()) || actorStates.containsKey(e.getTarget())) {
processEventGuard(e);
}
// combat
final boolean wasInCombat = combat != null;
processEventCombat(e);
// healing
if (isEffectHeal(e)) {
processEventHealing(e, isEffectiveLogged ? baseMatcher.group("Effective") : null);
}
// effect
if (actorStates.containsKey(e.getSource()) || actorStates.containsKey(e.getTarget())) {
processEventEffect(e);
}
// absorption
processEventAbsorption(e, isEffectiveLogged ? baseMatcher.group("Effective") : null);
// instance swap?
if (isEffectEqual(e, EntityGuid.SafeLoginImmunity.getGuid()) && isActionApply(e)) {
if (zonePattern == null) {
instanceMode = null;
instanceSize = null;
}
isUsingMimCrystal = false;
if (logger.isDebugEnabled()) {
logger.debug("Instance reset at " + e.getTs());
}
clearHotsTracking();
// } else if (isEffectEqual(e, EntityGuid.Bolster.getGuid())) {
// instanceMode = Raid.Mode.SM;
} else if (isEffectEqual(e, 3638571739119616L) && isActionApply(e)) {
// Nightmare Fury
instanceMode = Raid.Mode.NiM;
if (logger.isDebugEnabled()) {
logger.debug("NiM crystal detected at " + e.getTs());
}
if (!isUsingMimCrystal && combat != null) {
// activated mid fight?
context.addCombatEvent(combat.getCombatId(), e.getSource(), Event.Type.NIM_CRYSTAL, e.getTimestamp());
}
isUsingMimCrystal = true;
}
// hots tracking
if (isSourceThisPlayer(e) && isTargetAnyPlayer(e) && (combat == null || actorStates.get(e.getSource()).discipline == null || CharacterRole.HEALER.equals(actorStates.get(e.getSource()).discipline.getRole()))) {
processEventHots(e, baseMatcher);
}
events.add(e);
return wasInCombat && combat == null;
}
use of com.ixale.starparse.domain.Actor in project StarParse by Ixale.
the class Parser method processEventAbsorption.
public void processEventAbsorption(final Event e, final String effectiveValue) {
// is this an absorption event to be linked?
boolean isEventUnlinked = e.getAbsorbed() != null && isTargetAnyPlayer(e);
final Integer effective = effectiveValue == null || effectiveValue.isEmpty() ? null : Integer.parseInt(effectiveValue);
if (isEventUnlinked && isEffectiveLogged && (effective == null || Math.abs(effective - e.getValue()) <= 1 || ((effective + e.getAbsorbed() - e.getValue()) > 100))) {
if ((e.getTarget().getDiscipline() == null || (e.getTarget().getDiscipline() != null && e.getTarget().getDiscipline().getRole().equals(CharacterRole.TANK))) && e.getMitigation() != null && EntityGuid.Shield.getGuid() == e.getMitigation().getGuid()) {
// ignore this, tank shield broken logging
isEventUnlinked = false;
e.setAbsorbed(null);
}
}
final Actor a = e.getTarget();
if (absorptionEffectsClosing.containsKey(e.getTarget()) && !absorptionEffectsClosing.get(a).isEmpty()) {
final List<Effect> absClosing = absorptionEffectsClosing.get(a);
final Iterator<Effect> absClosingIt = absClosing.listIterator();
// resolve already closed effects (in the order of their end)
while (absClosingIt.hasNext()) {
final Effect effect = absClosingIt.next();
if (absorptionEventsInside.containsKey(a)) {
// link pending INSIDE events to this effects as it was the first one ending
linkAbsorptionEvents(absorptionEventsInside.get(a), effect);
absorptionEventsInside.remove(a);
}
if (effect.getTimeTo() < e.getTimestamp() - ((absorptionEffectsRunning.containsKey(a) && !absorptionEffectsRunning.get(a).isEmpty()) ? // resolve possible delay (long if this is the only effect, short if another is available as well)
ABSORPTION_INSIDE_DELAY_WINDOW : ABSORPTION_OUTSIDE_DELAY_WINDOW)) {
if (absorptionEventsOutside.containsKey(a) && absClosing.size() == 1) {
// link pending OUTSIDE events to this effect as it is the only choice (should be only 1 anyway)
linkAbsorptionEvents(absorptionEventsOutside.get(a), effect);
absorptionEventsOutside.remove(a);
}
// effect was closed and expired, remove it for good
absClosingIt.remove();
absorptionEffectsJustClosed.add(effect);
continue;
} else if (!isEventUnlinked) {
// not expired yet and this is not an absorption event, nothing else to do
continue;
}
// we are here = this event is an absorption & this closing effect is within a delay window
if (absorptionEventsOutside.containsKey(a)) {
// link queued OUTSIDE events to this effect (since this is another absorption, so there is nothing to wait for)
linkAbsorptionEvents(absorptionEventsOutside.get(a), effect);
absorptionEventsOutside.remove(a);
if (e.getAbsorbed() + 1 < e.getValue()) {
// ... and consume the effect as there are another active
// (unless the mitigation was full - high chance the remaining charge will be used in a bit)
absClosingIt.remove();
absorptionEffectsJustClosed.add(effect);
continue;
}
}
// try to link this absorption event
if (absClosing.size() > 1) {
// not clear to which effect to link to, queue as OUTSIDE and wait
absorptionEventsOutside.computeIfAbsent(a, (t) -> new ArrayList<>()).add(e.getEventId());
} else {
// link to the just closed effect
absorptions.add(new Absorption(e.getEventId(), effect.getEffectId()));
if (e.getAbsorbed() + 1 < e.getValue()) {
// ... and consume the effect as there are another active
// (unless the mitigation was full - high chance the remaining charge will be used in a bit)
absClosingIt.remove();
absorptionEffectsJustClosed.add(effect);
}
}
if (a == e.getTarget()) {
// flag event as linked
isEventUnlinked = false;
}
}
if (absClosing.isEmpty()) {
absorptionEffectsClosing.remove(a);
}
}
if (!isEventUnlinked) {
// event was already linked to a closed effect or its not an absorption at all
return;
}
final List<Effect> absRunning = absorptionEffectsRunning.get(e.getTarget());
if (absRunning == null || absRunning.isEmpty()) {
if (isEffectiveLogged) {
absorptionEffectsJustClosed.removeIf((eff) -> eff.getTimeTo() < e.getTimestamp() - ABSORPTION_OUTSIDE_DELAY_WINDOW);
final Optional<Effect> lagged = absorptionEffectsJustClosed.stream().filter((eff) -> eff.getTarget() == e.getTarget()).findFirst();
if (lagged.isPresent()) {
absorptions.add(new Absorption(e.getEventId(), lagged.get().getEffectId()));
return;
}
}
// no absorption effect currently active
if (logger.isDebugEnabled()) {
logger.error("Unknown absorption: " + e);
}
} else if (absRunning.size() == 1) {
// exactly one absorption effect active, link it
absorptions.add(new Absorption(e.getEventId(), absRunning.get(0).getEffectId()));
// try to be smart - if the mitigation was not full, then its probably consumed
// if (e.getAbsorbed() + 1 < e.getValue() && !chargedEffects.containsKey(absRunning.get(0))) {
// absorptionEffectsConsumed.computeIfAbsent(e.getTarget(), (t) -> new ArrayList<>()).add(absRunning.get(0));
// }
} else {
// try to be smart - if the mitigation was not full, then its probably consumed by the first one activated
// if (e.getAbsorbed() + 1 < e.getValue() && !chargedEffects.containsKey(absRunning.get(0))) {
// absorptions.add(new Absorption(e.getEventId(), absRunning.get(0).getEffectId()));
// absorptionEffectsConsumed.computeIfAbsent(e.getTarget(), (t) -> new ArrayList<>()).add(absRunning.get(0));
// } else {
// multiple absorption effects currently active, queue as INSIDE and wait whichever finishes first ...
absorptionEventsInside.computeIfAbsent(e.getTarget(), (t) -> new ArrayList<>()).add(e.getEventId());
// }
}
}
use of com.ixale.starparse.domain.Actor in project StarParse by Ixale.
the class CombatDaoImpl method getCombatActors.
@Override
public List<Actor> getCombatActors(final Combat combat, final Actor.Role role, final CombatSelection combatSel) throws Exception {
final String sql;
switch(role) {
case SOURCE:
sql = SQL_GET_SOURCE_NAMES;
break;
default:
sql = SQL_GET_TARGET_NAMES;
}
final Boundaries bounds = getBoundaries(combat, combatSel);
final Map<String, Object> args = new HashMap<>();
args.put("eventIdFrom", bounds.eventIdFrom);
args.put("eventIdTo", bounds.eventIdTo);
return getJdbcTemplate().query(sql, args, (rs, rowNum) -> {
Actor a = context.getActor(rs.getString(role == Actor.Role.SOURCE ? "source_name" : "target_name"), Actor.Type.valueOf(rs.getInt(role == Actor.Role.SOURCE ? "source_type" : "target_type")), getValueOrNull(rs, rs.getLong(role == Actor.Role.SOURCE ? "source_guid" : "target_guid")), getValueOrNull(rs, rs.getLong(role == Actor.Role.SOURCE ? "source_instance" : "target_instance")));
a.setTimeFrom(getTimestamp(rs, role == Actor.Role.SOURCE ? "source_time_from" : "target_time_from").getTime());
a.setTimeTo(getTimestamp(rs, role == Actor.Role.SOURCE ? "source_time_to" : "target_time_to").getTime());
return a;
});
}
Aggregations