From 7e49bb53adc4632e87895bf85dae9980a70d4035 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Wed, 14 Sep 2016 14:17:06 -0400 Subject: [PATCH 01/12] Add a warding processor this processor may be used to track down warding events, such as Counterwarding, Placement or Expiry. It uses the combat log events correlated with entity life state tracking. --- pom.xml | 82 +++++--- src/main/java/yasp/Main.java | 64 ++++-- src/main/java/yasp/Parse.java | 110 +++++----- .../processors/warding/OnWardCountered.java | 19 ++ .../processors/warding/OnWardExpired.java | 19 ++ .../yasp/processors/warding/OnWardPlaced.java | 19 ++ .../java/yasp/processors/warding/Wards.java | 188 ++++++++++++++++++ 7 files changed, 403 insertions(+), 98 deletions(-) create mode 100644 src/main/java/yasp/processors/warding/OnWardCountered.java create mode 100644 src/main/java/yasp/processors/warding/OnWardExpired.java create mode 100644 src/main/java/yasp/processors/warding/OnWardPlaced.java create mode 100644 src/main/java/yasp/processors/warding/Wards.java diff --git a/pom.xml b/pom.xml index 7463118b0..74827b7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -40,27 +40,27 @@ - - - + + + com.skadistats clarity 2.1 - + com.google.code.gson gson @@ -71,24 +71,52 @@ org.apache.maven.plugins - maven-shade-plugin - 2.2 + maven-jar-plugin + 3.0.2 + + + + true + yasp.Main + + + + + + + com.jolira + onejar-maven-plugin + 1.4.4 - package - shade + one-jar - - - - yasp.Main - - - + diff --git a/src/main/java/yasp/Main.java b/src/main/java/yasp/Main.java index 531188a70..aeb86a563 100644 --- a/src/main/java/yasp/Main.java +++ b/src/main/java/yasp/Main.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.FileInputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; @@ -9,28 +10,53 @@ import com.sun.net.httpserver.HttpServer; public class Main { + + public static void main(String[] args) { + try { + + if (args.length > 0 && args[0].equals("--file")) { System.exit(parse(args[1])); } + else if (args.length >0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } + else { startServer(args); } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static void startServer(String[] args) throws Exception { + HttpServer server = HttpServer.create(new InetSocketAddress(Integer.valueOf(args.length > 0 ? args[0] : "5600")), 0); + server.createContext("/", new MyHandler()); + server.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(4)); + server.start(); + } - public static void main(String[] args) throws Exception { - HttpServer server = HttpServer.create(new InetSocketAddress(Integer.valueOf(args.length > 0 ? args[0] : "5600")), 0); - server.createContext("/", new MyHandler()); - server.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(4)); - server.start(); + static int parseStream(InputStream is, OutputStream os) throws IOException { + try { + new Parse(is, os); + } + catch (Exception e) + { + e.printStackTrace(); + return -1; + } + finally { + is.close(); + os.close(); + } + + return 0; } + static int parse(String replay_file) throws Exception { + System.out.print(String.format("Parsing file %s", replay_file)); + return parseStream(new FileInputStream(replay_file), System.out); + } + static class MyHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - t.sendResponseHeaders(200, 0); - InputStream is = t.getRequestBody(); - OutputStream os = t.getResponseBody(); - try { - new Parse(is, os); - } - catch (Exception e) - { - e.printStackTrace(); - } - os.close(); - } + @Override + public void handle(HttpExchange t) throws IOException { + t.sendResponseHeaders(200, 0); + parseStream(t.getRequestBody(), t.getResponseBody()); + } } } diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index faaa121f6..8a19164cb 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -33,9 +33,13 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Iterator; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import yasp.processors.warding.OnWardCountered; +import yasp.processors.warding.OnWardExpired; +import yasp.processors.warding.OnWardPlaced; public class Parse { private class Entry { @@ -96,6 +100,7 @@ public Entry(Integer time) { this.time = time; } } + float INTERVAL = 1; float nextInterval = 0; Integer time = 0; @@ -106,7 +111,7 @@ public Entry(Integer time) { private Gson g = new Gson(); HashMap name_to_slot = new HashMap(); HashMap slot_to_playerslot = new HashMap(); - HashMap cosmeticsMap = new HashMap(); + HashMap cosmeticsMap = new HashMap(); InputStream is = null; OutputStream os = null; @@ -120,7 +125,6 @@ public Parse(InputStream input, OutputStream output) throws IOException System.err.format("total time taken: %s\n", (tMatch) / 1000.0); } - public void output(Entry e) { try { this.os.write((g.toJson(e) + "\n").getBytes()); @@ -291,15 +295,11 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry cle) { } @OnEntityEntered - public void onEntityEntered(Context ctx, Entity e) { - processEntity(ctx, e, false); - } - @OnEntityLeft - public void onEntityLeft(Context ctx, Entity e) { - processEntity(ctx, e, true); + public void onEntityExistenceChanged(Context ctx, Entity e) { + processEntity(ctx, e); } - + @UsesEntities @OnTickStart public void onTickStart(Context ctx, boolean synthetic) { @@ -459,6 +459,19 @@ public void onTickStart(Context ctx, boolean synthetic) { } } } + + @OnWardCountered + public void onWardCountered(Context ctx, Entity e, String killer_hero_name) { + Entry wardEntry = buildWardEntry(ctx, e); + wardEntry.attackername = killer_hero_name; + output(wardEntry); + } + + @OnWardExpired + @OnWardPlaced + public void onWardExistenceChanged(Context ctx, Entity e) { + output(buildWardEntry(ctx, e)); + } public T getEntityProperty(Entity e, String property, Integer idx) { try { @@ -476,51 +489,44 @@ public T getEntityProperty(Entity e, String property, Integer idx) { } } - public void processEntity(Context ctx, Entity e, boolean entityLeft) + public void processEntity(Context ctx, Entity e) { - //CDOTA_NPC_Observer_Ward - //CDOTA_NPC_Observer_Ward_TrueSight - //s1 "DT_DOTA_NPC_Observer_Ward" - //s1 "DT_DOTA_NPC_Observer_Ward_TrueSight" - boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); - boolean isSentry = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward_TrueSight"); - if (isObserver || isSentry) { - //System.err.println(e); - Entry entry = new Entry(time); - Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); - Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); - Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); - Integer[] pos = {x, y}; - entry.x = x; - entry.y = y; - entry.z = z; - if (entityLeft) + if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { + Integer accountId = getEntityProperty(e, "m_iAccountID", null); + Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); + //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); + if (accountId > 0) { - entry.type = isObserver ? "obs_left" : "sen_left"; + cosmeticsMap.put(itemDefinitionIndex, accountId); } - else - { - entry.type = isObserver ? "obs" : "sen"; - } - entry.key = Arrays.toString(pos); - entry.entityleft = entityLeft; - entry.ehandle = e.getHandle(); - //System.err.println(entry.key); - Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); - Entity ownerEntity = ctx.getProcessor(Entities.class).getByHandle(owner); - entry.slot = ownerEntity != null ? (Integer) getEntityProperty(ownerEntity, "m_iPlayerID", null) : null; - //2/3 radiant/dire - //entry.team = e.getProperty("m_iTeamNum"); - output(entry); - } - else if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { - Integer accountId = getEntityProperty(e, "m_iAccountID", null); - Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); - //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); - if (accountId > 0) - { - cosmeticsMap.put(itemDefinitionIndex, accountId); - } - } + } + } + + Entry buildWardEntry(Context ctx, Entity e) { + Entry entry = new Entry(time); + boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); + Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); + Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); + Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); + Integer life_state = getEntityProperty(e, "m_lifeState", null); + Integer[] pos = {x, y}; + entry.x = x; + entry.y = y; + entry.z = z; + entry.type = isObserver ? "obs" : "sen"; + entry.entityleft = life_state == 1; + entry.key = Arrays.toString(pos); + entry.ehandle = e.getHandle(); + + if (entry.entityleft) + entry.type += "_left"; + + //System.err.println(entry.key); + Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); + Entity ownerEntity = ctx.getProcessor(Entities.class).getByHandle(owner); + entry.slot = ownerEntity != null ? (Integer) getEntityProperty(ownerEntity, "m_iPlayerID", null) : null; + //2/3 radiant/dire + //entry.team = e.getProperty("m_iTeamNum"); + return entry; } } diff --git a/src/main/java/yasp/processors/warding/OnWardCountered.java b/src/main/java/yasp/processors/warding/OnWardCountered.java new file mode 100644 index 000000000..2fe0719da --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardCountered.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class, String.class }) +public @interface OnWardCountered { +} + diff --git a/src/main/java/yasp/processors/warding/OnWardExpired.java b/src/main/java/yasp/processors/warding/OnWardExpired.java new file mode 100644 index 000000000..affb3e08d --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardExpired.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class }) +public @interface OnWardExpired { +} + diff --git a/src/main/java/yasp/processors/warding/OnWardPlaced.java b/src/main/java/yasp/processors/warding/OnWardPlaced.java new file mode 100644 index 000000000..0312c8add --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardPlaced.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class }) +public @interface OnWardPlaced { +} + diff --git a/src/main/java/yasp/processors/warding/Wards.java b/src/main/java/yasp/processors/warding/Wards.java new file mode 100644 index 000000000..34866f9a2 --- /dev/null +++ b/src/main/java/yasp/processors/warding/Wards.java @@ -0,0 +1,188 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package yasp.processors.warding; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +import skadistats.clarity.event.Event; +import skadistats.clarity.event.EventListener; +import skadistats.clarity.event.Initializer; +import skadistats.clarity.event.Provides; +import skadistats.clarity.model.Entity; +import skadistats.clarity.model.FieldPath; +import skadistats.clarity.model.CombatLogEntry; +import skadistats.clarity.processor.entities.OnEntityCreated; +import skadistats.clarity.processor.entities.OnEntityDeleted; +import skadistats.clarity.processor.entities.OnEntityUpdated; +import skadistats.clarity.processor.entities.UsesEntities; +import skadistats.clarity.processor.gameevents.OnCombatLogEntry; +import skadistats.clarity.processor.reader.OnTickEnd; +import skadistats.clarity.processor.runner.Context; +import skadistats.clarity.wire.common.proto.DotaUserMessages; + +/** + * @author micaelbergeron + */ +@UsesEntities +@Provides({ OnWardCountered.class, OnWardExpired.class, OnWardPlaced.class }) +public class Wards { + + private static final Set WARDS_DT_CLASSES = new HashSet(Arrays.asList( + new String[] { + "CDOTA_NPC_Observer_Ward", + "CDOTA_NPC_Observer_Ward_TrueSight" + } + )); + + private static final Set WARDS_TARGET_NAMES = new HashSet(Arrays.asList( + new String[] { + "npc_dota_observer_wards", + "npc_dota_sentry_wards" + } + )); + + private final Map lifeStatePaths = new HashMap<>(); + private final Map currentLifeState = new HashMap<>(); + + private final Queue wardKillers = new ArrayDeque<>(); + private Queue toProcess = new ArrayDeque<>(); + + private Event evCountered; + private Event evExpired; + private Event evPlaced; + + private class ProcessEntityCommand { + + private Entity entity; + private FieldPath fieldPath; + + public ProcessEntityCommand(Entity e, FieldPath p) { + entity = e; + fieldPath = p; + } + } + + @Initializer(OnWardCountered.class) + public void initOnWardCountered(final Context ctx, final EventListener listener) { + evCountered = ctx.createEvent(OnWardCountered.class, Entity.class, String.class); + } + + @Initializer(OnWardExpired.class) + public void initOnWardExpired(final Context ctx, final EventListener listener) { + evExpired = ctx.createEvent(OnWardExpired.class, Entity.class); + } + + @Initializer(OnWardPlaced.class) + public void initOnWardPlaced(final Context ctx, final EventListener listener) { + evPlaced = ctx.createEvent(OnWardPlaced.class, Entity.class); + } + + @OnEntityCreated + public void onCreated(Context ctx, Entity e) { + if (!isWard(e)) return; + + FieldPath lifeStatePath; + + clearCachedState(e); + ensureFieldPathForEntityInitialized(e); + if ((lifeStatePath = getFieldPathForEntity(e)) != null) + processLifeStateChange(e, lifeStatePath); + } + + @OnEntityUpdated + public void onUpdated(Context ctx, Entity e, FieldPath[] fieldPaths, int num) { + FieldPath p; + if ((p = getFieldPathForEntity(e)) != null) { + for (int i = 0; i < num; i++) { + if (fieldPaths[i].equals(p)) { + toProcess.add(new ProcessEntityCommand(e, p)); + break; + } + } + } + } + + @OnEntityDeleted + public void onDeleted(Context ctx, Entity e) { + clearCachedState(e); + } + + @OnCombatLogEntry + public void onCombatLogEntry(Context ctx, CombatLogEntry entry) { + if (!isWardDeath(entry)) return; + + String killer; + if ((killer = entry.getAttackerName()) != null) + wardKillers.add(killer); + } + + @OnTickEnd + public void onTickEnd(Context ctx, boolean synthetic) { + if (!synthetic) return; + + ProcessEntityCommand cmd; + while ((cmd = toProcess.poll()) != null) { + processLifeStateChange(cmd.entity, cmd.fieldPath); + } + } + + private FieldPath getFieldPathForEntity(Entity e) { + return lifeStatePaths.get(e.getDtClass().getClassId()); + } + + private void clearCachedState(Entity e) { + currentLifeState.remove(e.getIndex()); + } + + private void ensureFieldPathForEntityInitialized(Entity e) { + Integer cid = e.getDtClass().getClassId(); + if (!lifeStatePaths.containsKey(cid)) { + lifeStatePaths.put(cid, e.getDtClass().getFieldPathForName("m_lifeState")); + } + } + + private boolean isWard(Entity e) { + return WARDS_DT_CLASSES.contains(e.getDtClass().getDtName()); + } + + private boolean isWardDeath(CombatLogEntry e) { + return e.getType().equals(DotaUserMessages.DOTA_COMBATLOG_TYPES.DOTA_COMBATLOG_DEATH) + && WARDS_TARGET_NAMES.contains(e.getTargetName()); + } + + public void processLifeStateChange(Entity e, FieldPath p) { + int oldState = currentLifeState.containsKey(e.getIndex()) ? currentLifeState.get(e.getIndex()) : 2; + int newState = e.getPropertyForFieldPath(p); + if (oldState != newState) { + switch(newState) { + case 0: + if (evPlaced != null) + evPlaced.raise(e); + break; + case 1: + String killer; + if ((killer = wardKillers.poll()) != null) { + if (evCountered != null) + evCountered.raise(e, killer); + } else { + if (evExpired != null) + evExpired.raise(e); + } + break; + } + } + + currentLifeState.put(e.getIndex(), newState); + } + +} + From 2dab48f0f0e6656bc61de0c88d9666693ec01ae7 Mon Sep 17 00:00:00 2001 From: Howard Chung Date: Wed, 14 Sep 2016 19:48:51 -0700 Subject: [PATCH 02/12] Update postbuild.sh --- scripts/postbuild.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/postbuild.sh b/scripts/postbuild.sh index 1e5dd1dbf..e5ca6fa30 100755 --- a/scripts/postbuild.sh +++ b/scripts/postbuild.sh @@ -2,7 +2,7 @@ if [ -n "$DOCKER_USERNAME" ]; then docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" - docker tag yasp/parser:latest yasp/parser:${TRAVIS_COMMIT} - docker push yasp/parser:${TRAVIS_COMMIT} - docker push yasp/parser:latest -fi \ No newline at end of file + docker tag odota/parser:latest odota/parser:${TRAVIS_COMMIT} + docker push odota/parser:${TRAVIS_COMMIT} + docker push odota/parser:latest +fi From c7be138a71be26316110710c7a40fc7bea9e38c6 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Wed, 14 Sep 2016 23:07:00 -0400 Subject: [PATCH 03/12] reword annotions and fix code style --- src/main/java/yasp/Main.java | 22 +++++-------- src/main/java/yasp/Parse.java | 18 +++++----- ...OnWardCountered.java => OnWardKilled.java} | 2 +- .../java/yasp/processors/warding/Wards.java | 33 +++++++++++-------- 4 files changed, 38 insertions(+), 37 deletions(-) rename src/main/java/yasp/processors/warding/{OnWardCountered.java => OnWardKilled.java} (93%) diff --git a/src/main/java/yasp/Main.java b/src/main/java/yasp/Main.java index aeb86a563..4f6f9a56c 100644 --- a/src/main/java/yasp/Main.java +++ b/src/main/java/yasp/Main.java @@ -11,16 +11,10 @@ public class Main { - public static void main(String[] args) { - try { - - if (args.length > 0 && args[0].equals("--file")) { System.exit(parse(args[1])); } - else if (args.length >0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } - else { startServer(args); } - } - catch (Exception e) { - e.printStackTrace(); - } + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("--file")) { System.exit(parseFile(args[1])); } + else if (args.length > 0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } + else { startServer(args); } } public static void startServer(String[] args) throws Exception { @@ -30,7 +24,7 @@ public static void startServer(String[] args) throws Exception { server.start(); } - static int parseStream(InputStream is, OutputStream os) throws IOException { + private static int parseStream(InputStream is, OutputStream os) throws IOException { try { new Parse(is, os); } @@ -47,9 +41,9 @@ static int parseStream(InputStream is, OutputStream os) throws IOException { return 0; } - static int parse(String replay_file) throws Exception { - System.out.print(String.format("Parsing file %s", replay_file)); - return parseStream(new FileInputStream(replay_file), System.out); + private static int parseFile(String replayFile) throws Exception { + System.out.print(String.format("Parsing file %s", replayFile)); + return parseStream(new FileInputStream(replayFile), System.out); } static class MyHandler implements HttpHandler { diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index 8a19164cb..beda7ded3 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -37,9 +37,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import yasp.processors.warding.OnWardCountered; import yasp.processors.warding.OnWardExpired; import yasp.processors.warding.OnWardPlaced; +import yasp.processors.warding.OnWardKilled; public class Parse { private class Entry { @@ -295,8 +295,7 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry cle) { } @OnEntityEntered - @OnEntityLeft - public void onEntityExistenceChanged(Context ctx, Entity e) { + public void onEntityEntered(Context ctx, Entity e) { processEntity(ctx, e); } @@ -460,10 +459,10 @@ public void onTickStart(Context ctx, boolean synthetic) { } } - @OnWardCountered - public void onWardCountered(Context ctx, Entity e, String killer_hero_name) { + @OnWardKilled + public void onWardKilled(Context ctx, Entity e, String killerHeroName) { Entry wardEntry = buildWardEntry(ctx, e); - wardEntry.attackername = killer_hero_name; + wardEntry.attackername = killerHeroName; output(wardEntry); } @@ -502,9 +501,9 @@ public void processEntity(Context ctx, Entity e) } } - Entry buildWardEntry(Context ctx, Entity e) { + private Entry buildWardEntry(Context ctx, Entity e) { Entry entry = new Entry(time); - boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); + boolean isObserver = !e.getDtClass().getDtName().contains("TrueSight"); Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); @@ -518,8 +517,9 @@ Entry buildWardEntry(Context ctx, Entity e) { entry.key = Arrays.toString(pos); entry.ehandle = e.getHandle(); - if (entry.entityleft) + if (entry.entityleft) { entry.type += "_left"; + } //System.err.println(entry.key); Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); diff --git a/src/main/java/yasp/processors/warding/OnWardCountered.java b/src/main/java/yasp/processors/warding/OnWardKilled.java similarity index 93% rename from src/main/java/yasp/processors/warding/OnWardCountered.java rename to src/main/java/yasp/processors/warding/OnWardKilled.java index 2fe0719da..bc615ad6e 100644 --- a/src/main/java/yasp/processors/warding/OnWardCountered.java +++ b/src/main/java/yasp/processors/warding/OnWardKilled.java @@ -14,6 +14,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(value = ElementType.METHOD) @UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class, String.class }) -public @interface OnWardCountered { +public @interface OnWardKilled { } diff --git a/src/main/java/yasp/processors/warding/Wards.java b/src/main/java/yasp/processors/warding/Wards.java index 34866f9a2..b51178a9e 100644 --- a/src/main/java/yasp/processors/warding/Wards.java +++ b/src/main/java/yasp/processors/warding/Wards.java @@ -33,11 +33,13 @@ * @author micaelbergeron */ @UsesEntities -@Provides({ OnWardCountered.class, OnWardExpired.class, OnWardPlaced.class }) +@Provides({ OnWardKilled.class, OnWardExpired.class, OnWardPlaced.class }) public class Wards { private static final Set WARDS_DT_CLASSES = new HashSet(Arrays.asList( new String[] { + "DT_DOTA_NPC_Observer_Ward", + "DT_DOTA_NPC_Observer_Ward_TrueSight", "CDOTA_NPC_Observer_Ward", "CDOTA_NPC_Observer_Ward_TrueSight" } @@ -56,7 +58,7 @@ public class Wards { private final Queue wardKillers = new ArrayDeque<>(); private Queue toProcess = new ArrayDeque<>(); - private Event evCountered; + private Event evKilled; private Event evExpired; private Event evPlaced; @@ -71,9 +73,9 @@ public ProcessEntityCommand(Entity e, FieldPath p) { } } - @Initializer(OnWardCountered.class) - public void initOnWardCountered(final Context ctx, final EventListener listener) { - evCountered = ctx.createEvent(OnWardCountered.class, Entity.class, String.class); + @Initializer(OnWardKilled.class) + public void initOnWardKilled(final Context ctx, final EventListener listener) { + evKilled = ctx.createEvent(OnWardKilled.class, Entity.class, String.class); } @Initializer(OnWardExpired.class) @@ -94,8 +96,9 @@ public void onCreated(Context ctx, Entity e) { clearCachedState(e); ensureFieldPathForEntityInitialized(e); - if ((lifeStatePath = getFieldPathForEntity(e)) != null) - processLifeStateChange(e, lifeStatePath); + if ((lifeStatePath = getFieldPathForEntity(e)) != null) { + processLifeStateChange(e, lifeStatePath); + } } @OnEntityUpdated @@ -121,8 +124,9 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry entry) { if (!isWardDeath(entry)) return; String killer; - if ((killer = entry.getAttackerName()) != null) - wardKillers.add(killer); + if ((killer = entry.getAttackerName()) != null) { + wardKillers.add(killer); + } } @OnTickEnd @@ -165,17 +169,20 @@ public void processLifeStateChange(Entity e, FieldPath p) { if (oldState != newState) { switch(newState) { case 0: - if (evPlaced != null) + if (evPlaced != null) { evPlaced.raise(e); + } break; case 1: String killer; if ((killer = wardKillers.poll()) != null) { - if (evCountered != null) - evCountered.raise(e, killer); + if (evKilled != null) { + evKilled.raise(e, killer); + } } else { - if (evExpired != null) + if (evExpired != null) { evExpired.raise(e); + } } break; } From 74474b11cc77c9b3694ce511c081c0f56e2f4e7f Mon Sep 17 00:00:00 2001 From: Howard Chung Date: Wed, 14 Sep 2016 20:27:00 -0700 Subject: [PATCH 04/12] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bbaf67357..5f2d294d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ notifications: - howardc93@gmail.com - aqc2109@columbia.edu script: -- docker build -t yasp/parser . +- docker build -t odota/parser . deploy: provider: script skip_cleanup: true From a72fcaac0e1b22709e38655ef093bd26f40e4792 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sun, 18 Sep 2016 21:43:56 +0000 Subject: [PATCH 05/12] extract player_slot for cosmetics --- scripts/rebuild.sh | 2 +- scripts/{test_java_parser.sh => test.sh} | 0 src/main/java/yasp/Parse.java | 5 ++++- 3 files changed, 5 insertions(+), 2 deletions(-) rename scripts/{test_java_parser.sh => test.sh} (100%) diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh index 23995e015..9871ae873 100644 --- a/scripts/rebuild.sh +++ b/scripts/rebuild.sh @@ -1,5 +1,5 @@ #!/bin/bash -sudo docker rm -fv parser sudo docker build -t yasp/parser . +sudo docker rm -fv parser sudo docker run -d --name parser --net=host yasp/parser \ No newline at end of file diff --git a/scripts/test_java_parser.sh b/scripts/test.sh similarity index 100% rename from scripts/test_java_parser.sh rename to scripts/test.sh diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index faaa121f6..edd97b0c5 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -106,6 +106,7 @@ public Entry(Integer time) { private Gson g = new Gson(); HashMap name_to_slot = new HashMap(); HashMap slot_to_playerslot = new HashMap(); + HashMap steamid_to_playerslot = new HashMap(); HashMap cosmeticsMap = new HashMap(); InputStream is = null; OutputStream os = null; @@ -365,6 +366,7 @@ public void onTickStart(Context ctx, boolean synthetic) { validIndices[added] = i; added += 1; slot_to_playerslot.put(added, entry.value); + steamid_to_playerslot.put(steamid, entry.value); } } catch(Exception e) @@ -519,7 +521,8 @@ else if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); if (accountId > 0) { - cosmeticsMap.put(itemDefinitionIndex, accountId); + Long accountId64 = 76561197960265728L + accountId; + cosmeticsMap.put(itemDefinitionIndex, steamid_to_playerslot.get(accountId64)); } } } From 510d6f2fb09abb822cd5fd0985951feb947518a9 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 19 Sep 2016 01:30:22 +0000 Subject: [PATCH 06/12] add some owner hero entity data --- src/main/java/yasp/Parse.java | 42 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index edd97b0c5..228d25988 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -36,7 +36,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; - +import java.util.Iterator; + public class Parse { private class Entry { public Integer time; @@ -294,6 +295,21 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry cle) { @OnEntityEntered public void onEntityEntered(Context ctx, Entity e) { processEntity(ctx, e, false); + if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { + Integer accountId = getEntityProperty(e, "m_iAccountID", null); + Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); + Integer ownerHandle = getEntityProperty(e, "m_hOwnerEntity", null); + Entity owner = ctx.getProcessor(Entities.class).getByHandle(ownerHandle); + //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); + if (accountId > 0) + { + // Get the owner (a hero entity) + Integer playerId = getEntityProperty(owner, "m_iPlayerID", null); + Long accountId64 = 76561197960265728L + accountId; + Integer playerSlot = steamid_to_playerslot.get(accountId64); + cosmeticsMap.put(itemDefinitionIndex, playerSlot); + } + } } @OnEntityLeft @@ -304,6 +320,20 @@ public void onEntityLeft(Context ctx, Entity e) { @UsesEntities @OnTickStart public void onTickStart(Context ctx, boolean synthetic) { + /* + Iterator cosmetics = ctx.getProcessor(Entities.class).getAllByDtName("CDOTAWearableItem"); + while ( cosmetics.hasNext() ) + { + Entity e = cosmetics.next(); + Integer accountId = getEntityProperty(e, "m_iAccountID", null); + Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); + if (itemDefinitionIndex == 7559) + { + System.err.format("%s,%s\n", accountId, itemDefinitionIndex); + } + } + */ + //TODO check engine to decide whether to use s1 or s2 entities //ctx.getEngineType() @@ -515,15 +545,5 @@ public void processEntity(Context ctx, Entity e, boolean entityLeft) //entry.team = e.getProperty("m_iTeamNum"); output(entry); } - else if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { - Integer accountId = getEntityProperty(e, "m_iAccountID", null); - Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); - //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); - if (accountId > 0) - { - Long accountId64 = 76561197960265728L + accountId; - cosmeticsMap.put(itemDefinitionIndex, steamid_to_playerslot.get(accountId64)); - } - } } } From 063e10cd109cde8207c0f3c303097bcbd5227145 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 20 Sep 2016 06:56:34 +0000 Subject: [PATCH 07/12] update rebuild script --- scripts/rebuild.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rebuild.sh b/scripts/rebuild.sh index 9871ae873..c88e2c829 100644 --- a/scripts/rebuild.sh +++ b/scripts/rebuild.sh @@ -1,5 +1,5 @@ #!/bin/bash -sudo docker build -t yasp/parser . +sudo docker build -t odota/parser . sudo docker rm -fv parser -sudo docker run -d --name parser --net=host yasp/parser \ No newline at end of file +sudo docker run -d --name parser --net=host odota/parser \ No newline at end of file From 39c1428c7c36d834aa8609e5306ecc88472f95a5 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Wed, 14 Sep 2016 14:17:06 -0400 Subject: [PATCH 08/12] Add a warding processor this processor may be used to track down warding events, such as Counterwarding, Placement or Expiry. It uses the combat log events correlated with entity life state tracking. --- pom.xml | 82 +++++--- src/main/java/yasp/Main.java | 64 ++++-- src/main/java/yasp/Parse.java | 117 +++++------ .../processors/warding/OnWardCountered.java | 19 ++ .../processors/warding/OnWardExpired.java | 19 ++ .../yasp/processors/warding/OnWardPlaced.java | 19 ++ .../java/yasp/processors/warding/Wards.java | 188 ++++++++++++++++++ 7 files changed, 404 insertions(+), 104 deletions(-) create mode 100644 src/main/java/yasp/processors/warding/OnWardCountered.java create mode 100644 src/main/java/yasp/processors/warding/OnWardExpired.java create mode 100644 src/main/java/yasp/processors/warding/OnWardPlaced.java create mode 100644 src/main/java/yasp/processors/warding/Wards.java diff --git a/pom.xml b/pom.xml index 7463118b0..74827b7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -40,27 +40,27 @@ - - - + + + com.skadistats clarity 2.1 - + com.google.code.gson gson @@ -71,24 +71,52 @@ org.apache.maven.plugins - maven-shade-plugin - 2.2 + maven-jar-plugin + 3.0.2 + + + + true + yasp.Main + + + + + + + com.jolira + onejar-maven-plugin + 1.4.4 - package - shade + one-jar - - - - yasp.Main - - - + diff --git a/src/main/java/yasp/Main.java b/src/main/java/yasp/Main.java index 531188a70..aeb86a563 100644 --- a/src/main/java/yasp/Main.java +++ b/src/main/java/yasp/Main.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.FileInputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; @@ -9,28 +10,53 @@ import com.sun.net.httpserver.HttpServer; public class Main { + + public static void main(String[] args) { + try { + + if (args.length > 0 && args[0].equals("--file")) { System.exit(parse(args[1])); } + else if (args.length >0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } + else { startServer(args); } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static void startServer(String[] args) throws Exception { + HttpServer server = HttpServer.create(new InetSocketAddress(Integer.valueOf(args.length > 0 ? args[0] : "5600")), 0); + server.createContext("/", new MyHandler()); + server.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(4)); + server.start(); + } - public static void main(String[] args) throws Exception { - HttpServer server = HttpServer.create(new InetSocketAddress(Integer.valueOf(args.length > 0 ? args[0] : "5600")), 0); - server.createContext("/", new MyHandler()); - server.setExecutor(java.util.concurrent.Executors.newFixedThreadPool(4)); - server.start(); + static int parseStream(InputStream is, OutputStream os) throws IOException { + try { + new Parse(is, os); + } + catch (Exception e) + { + e.printStackTrace(); + return -1; + } + finally { + is.close(); + os.close(); + } + + return 0; } + static int parse(String replay_file) throws Exception { + System.out.print(String.format("Parsing file %s", replay_file)); + return parseStream(new FileInputStream(replay_file), System.out); + } + static class MyHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - t.sendResponseHeaders(200, 0); - InputStream is = t.getRequestBody(); - OutputStream os = t.getResponseBody(); - try { - new Parse(is, os); - } - catch (Exception e) - { - e.printStackTrace(); - } - os.close(); - } + @Override + public void handle(HttpExchange t) throws IOException { + t.sendResponseHeaders(200, 0); + parseStream(t.getRequestBody(), t.getResponseBody()); + } } } diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index 228d25988..5dfcf6018 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -33,10 +33,15 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Iterator; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; +import yasp.processors.warding.OnWardCountered; +import yasp.processors.warding.OnWardExpired; +import yasp.processors.warding.OnWardPlaced; + public class Parse { private class Entry { @@ -97,6 +102,7 @@ public Entry(Integer time) { this.time = time; } } + float INTERVAL = 1; float nextInterval = 0; Integer time = 0; @@ -108,7 +114,7 @@ public Entry(Integer time) { HashMap name_to_slot = new HashMap(); HashMap slot_to_playerslot = new HashMap(); HashMap steamid_to_playerslot = new HashMap(); - HashMap cosmeticsMap = new HashMap(); + HashMap cosmeticsMap = new HashMap(); InputStream is = null; OutputStream os = null; @@ -122,7 +128,6 @@ public Parse(InputStream input, OutputStream output) throws IOException System.err.format("total time taken: %s\n", (tMatch) / 1000.0); } - public void output(Entry e) { try { this.os.write((g.toJson(e) + "\n").getBytes()); @@ -293,30 +298,11 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry cle) { } @OnEntityEntered - public void onEntityEntered(Context ctx, Entity e) { - processEntity(ctx, e, false); - if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { - Integer accountId = getEntityProperty(e, "m_iAccountID", null); - Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); - Integer ownerHandle = getEntityProperty(e, "m_hOwnerEntity", null); - Entity owner = ctx.getProcessor(Entities.class).getByHandle(ownerHandle); - //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); - if (accountId > 0) - { - // Get the owner (a hero entity) - Integer playerId = getEntityProperty(owner, "m_iPlayerID", null); - Long accountId64 = 76561197960265728L + accountId; - Integer playerSlot = steamid_to_playerslot.get(accountId64); - cosmeticsMap.put(itemDefinitionIndex, playerSlot); - } - } - } - @OnEntityLeft - public void onEntityLeft(Context ctx, Entity e) { - processEntity(ctx, e, true); + public void onEntityExistenceChanged(Context ctx, Entity e) { + processEntity(ctx, e); } - + @UsesEntities @OnTickStart public void onTickStart(Context ctx, boolean synthetic) { @@ -491,6 +477,19 @@ public void onTickStart(Context ctx, boolean synthetic) { } } } + + @OnWardCountered + public void onWardCountered(Context ctx, Entity e, String killer_hero_name) { + Entry wardEntry = buildWardEntry(ctx, e); + wardEntry.attackername = killer_hero_name; + output(wardEntry); + } + + @OnWardExpired + @OnWardPlaced + public void onWardExistenceChanged(Context ctx, Entity e) { + output(buildWardEntry(ctx, e)); + } public T getEntityProperty(Entity e, String property, Integer idx) { try { @@ -508,42 +507,44 @@ public T getEntityProperty(Entity e, String property, Integer idx) { } } - public void processEntity(Context ctx, Entity e, boolean entityLeft) + public void processEntity(Context ctx, Entity e) { - //CDOTA_NPC_Observer_Ward - //CDOTA_NPC_Observer_Ward_TrueSight - //s1 "DT_DOTA_NPC_Observer_Ward" - //s1 "DT_DOTA_NPC_Observer_Ward_TrueSight" - boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); - boolean isSentry = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward_TrueSight"); - if (isObserver || isSentry) { - //System.err.println(e); - Entry entry = new Entry(time); - Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); - Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); - Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); - Integer[] pos = {x, y}; - entry.x = x; - entry.y = y; - entry.z = z; - if (entityLeft) - { - entry.type = isObserver ? "obs_left" : "sen_left"; - } - else + if (e.getDtClass().getDtName().equals("CDOTAWearableItem")) { + Integer accountId = getEntityProperty(e, "m_iAccountID", null); + Integer itemDefinitionIndex = getEntityProperty(e, "m_iItemDefinitionIndex", null); + //System.err.format("%s,%s\n", accountId, itemDefinitionIndex); + if (accountId > 0) { - entry.type = isObserver ? "obs" : "sen"; + cosmeticsMap.put(itemDefinitionIndex, accountId); } - entry.key = Arrays.toString(pos); - entry.entityleft = entityLeft; - entry.ehandle = e.getHandle(); - //System.err.println(entry.key); - Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); - Entity ownerEntity = ctx.getProcessor(Entities.class).getByHandle(owner); - entry.slot = ownerEntity != null ? (Integer) getEntityProperty(ownerEntity, "m_iPlayerID", null) : null; - //2/3 radiant/dire - //entry.team = e.getProperty("m_iTeamNum"); - output(entry); - } + } + } + + Entry buildWardEntry(Context ctx, Entity e) { + Entry entry = new Entry(time); + boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); + Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); + Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); + Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); + Integer life_state = getEntityProperty(e, "m_lifeState", null); + Integer[] pos = {x, y}; + entry.x = x; + entry.y = y; + entry.z = z; + entry.type = isObserver ? "obs" : "sen"; + entry.entityleft = life_state == 1; + entry.key = Arrays.toString(pos); + entry.ehandle = e.getHandle(); + + if (entry.entityleft) + entry.type += "_left"; + + //System.err.println(entry.key); + Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); + Entity ownerEntity = ctx.getProcessor(Entities.class).getByHandle(owner); + entry.slot = ownerEntity != null ? (Integer) getEntityProperty(ownerEntity, "m_iPlayerID", null) : null; + //2/3 radiant/dire + //entry.team = e.getProperty("m_iTeamNum"); + return entry; } } diff --git a/src/main/java/yasp/processors/warding/OnWardCountered.java b/src/main/java/yasp/processors/warding/OnWardCountered.java new file mode 100644 index 000000000..2fe0719da --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardCountered.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class, String.class }) +public @interface OnWardCountered { +} + diff --git a/src/main/java/yasp/processors/warding/OnWardExpired.java b/src/main/java/yasp/processors/warding/OnWardExpired.java new file mode 100644 index 000000000..affb3e08d --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardExpired.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class }) +public @interface OnWardExpired { +} + diff --git a/src/main/java/yasp/processors/warding/OnWardPlaced.java b/src/main/java/yasp/processors/warding/OnWardPlaced.java new file mode 100644 index 000000000..0312c8add --- /dev/null +++ b/src/main/java/yasp/processors/warding/OnWardPlaced.java @@ -0,0 +1,19 @@ +package yasp.processors.warding; + +import java.lang.annotation.Annotation; + +import skadistats.clarity.event.UsagePointMarker; +import skadistats.clarity.event.UsagePointType; +import skadistats.clarity.model.Entity; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = ElementType.METHOD) +@UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class }) +public @interface OnWardPlaced { +} + diff --git a/src/main/java/yasp/processors/warding/Wards.java b/src/main/java/yasp/processors/warding/Wards.java new file mode 100644 index 000000000..34866f9a2 --- /dev/null +++ b/src/main/java/yasp/processors/warding/Wards.java @@ -0,0 +1,188 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package yasp.processors.warding; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +import skadistats.clarity.event.Event; +import skadistats.clarity.event.EventListener; +import skadistats.clarity.event.Initializer; +import skadistats.clarity.event.Provides; +import skadistats.clarity.model.Entity; +import skadistats.clarity.model.FieldPath; +import skadistats.clarity.model.CombatLogEntry; +import skadistats.clarity.processor.entities.OnEntityCreated; +import skadistats.clarity.processor.entities.OnEntityDeleted; +import skadistats.clarity.processor.entities.OnEntityUpdated; +import skadistats.clarity.processor.entities.UsesEntities; +import skadistats.clarity.processor.gameevents.OnCombatLogEntry; +import skadistats.clarity.processor.reader.OnTickEnd; +import skadistats.clarity.processor.runner.Context; +import skadistats.clarity.wire.common.proto.DotaUserMessages; + +/** + * @author micaelbergeron + */ +@UsesEntities +@Provides({ OnWardCountered.class, OnWardExpired.class, OnWardPlaced.class }) +public class Wards { + + private static final Set WARDS_DT_CLASSES = new HashSet(Arrays.asList( + new String[] { + "CDOTA_NPC_Observer_Ward", + "CDOTA_NPC_Observer_Ward_TrueSight" + } + )); + + private static final Set WARDS_TARGET_NAMES = new HashSet(Arrays.asList( + new String[] { + "npc_dota_observer_wards", + "npc_dota_sentry_wards" + } + )); + + private final Map lifeStatePaths = new HashMap<>(); + private final Map currentLifeState = new HashMap<>(); + + private final Queue wardKillers = new ArrayDeque<>(); + private Queue toProcess = new ArrayDeque<>(); + + private Event evCountered; + private Event evExpired; + private Event evPlaced; + + private class ProcessEntityCommand { + + private Entity entity; + private FieldPath fieldPath; + + public ProcessEntityCommand(Entity e, FieldPath p) { + entity = e; + fieldPath = p; + } + } + + @Initializer(OnWardCountered.class) + public void initOnWardCountered(final Context ctx, final EventListener listener) { + evCountered = ctx.createEvent(OnWardCountered.class, Entity.class, String.class); + } + + @Initializer(OnWardExpired.class) + public void initOnWardExpired(final Context ctx, final EventListener listener) { + evExpired = ctx.createEvent(OnWardExpired.class, Entity.class); + } + + @Initializer(OnWardPlaced.class) + public void initOnWardPlaced(final Context ctx, final EventListener listener) { + evPlaced = ctx.createEvent(OnWardPlaced.class, Entity.class); + } + + @OnEntityCreated + public void onCreated(Context ctx, Entity e) { + if (!isWard(e)) return; + + FieldPath lifeStatePath; + + clearCachedState(e); + ensureFieldPathForEntityInitialized(e); + if ((lifeStatePath = getFieldPathForEntity(e)) != null) + processLifeStateChange(e, lifeStatePath); + } + + @OnEntityUpdated + public void onUpdated(Context ctx, Entity e, FieldPath[] fieldPaths, int num) { + FieldPath p; + if ((p = getFieldPathForEntity(e)) != null) { + for (int i = 0; i < num; i++) { + if (fieldPaths[i].equals(p)) { + toProcess.add(new ProcessEntityCommand(e, p)); + break; + } + } + } + } + + @OnEntityDeleted + public void onDeleted(Context ctx, Entity e) { + clearCachedState(e); + } + + @OnCombatLogEntry + public void onCombatLogEntry(Context ctx, CombatLogEntry entry) { + if (!isWardDeath(entry)) return; + + String killer; + if ((killer = entry.getAttackerName()) != null) + wardKillers.add(killer); + } + + @OnTickEnd + public void onTickEnd(Context ctx, boolean synthetic) { + if (!synthetic) return; + + ProcessEntityCommand cmd; + while ((cmd = toProcess.poll()) != null) { + processLifeStateChange(cmd.entity, cmd.fieldPath); + } + } + + private FieldPath getFieldPathForEntity(Entity e) { + return lifeStatePaths.get(e.getDtClass().getClassId()); + } + + private void clearCachedState(Entity e) { + currentLifeState.remove(e.getIndex()); + } + + private void ensureFieldPathForEntityInitialized(Entity e) { + Integer cid = e.getDtClass().getClassId(); + if (!lifeStatePaths.containsKey(cid)) { + lifeStatePaths.put(cid, e.getDtClass().getFieldPathForName("m_lifeState")); + } + } + + private boolean isWard(Entity e) { + return WARDS_DT_CLASSES.contains(e.getDtClass().getDtName()); + } + + private boolean isWardDeath(CombatLogEntry e) { + return e.getType().equals(DotaUserMessages.DOTA_COMBATLOG_TYPES.DOTA_COMBATLOG_DEATH) + && WARDS_TARGET_NAMES.contains(e.getTargetName()); + } + + public void processLifeStateChange(Entity e, FieldPath p) { + int oldState = currentLifeState.containsKey(e.getIndex()) ? currentLifeState.get(e.getIndex()) : 2; + int newState = e.getPropertyForFieldPath(p); + if (oldState != newState) { + switch(newState) { + case 0: + if (evPlaced != null) + evPlaced.raise(e); + break; + case 1: + String killer; + if ((killer = wardKillers.poll()) != null) { + if (evCountered != null) + evCountered.raise(e, killer); + } else { + if (evExpired != null) + evExpired.raise(e); + } + break; + } + } + + currentLifeState.put(e.getIndex(), newState); + } + +} + From cb76494b9458f5ab5441e0776364c8a51b20891a Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Wed, 14 Sep 2016 23:07:00 -0400 Subject: [PATCH 09/12] reword annotions and fix code style --- src/main/java/yasp/Main.java | 22 +++++-------- src/main/java/yasp/Parse.java | 22 ++++++------- ...OnWardCountered.java => OnWardKilled.java} | 2 +- .../java/yasp/processors/warding/Wards.java | 33 +++++++++++-------- 4 files changed, 39 insertions(+), 40 deletions(-) rename src/main/java/yasp/processors/warding/{OnWardCountered.java => OnWardKilled.java} (93%) diff --git a/src/main/java/yasp/Main.java b/src/main/java/yasp/Main.java index aeb86a563..4f6f9a56c 100644 --- a/src/main/java/yasp/Main.java +++ b/src/main/java/yasp/Main.java @@ -11,16 +11,10 @@ public class Main { - public static void main(String[] args) { - try { - - if (args.length > 0 && args[0].equals("--file")) { System.exit(parse(args[1])); } - else if (args.length >0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } - else { startServer(args); } - } - catch (Exception e) { - e.printStackTrace(); - } + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("--file")) { System.exit(parseFile(args[1])); } + else if (args.length > 0 && args[0].equals("--")) { System.exit(parseStream(System.in, System.out)); } + else { startServer(args); } } public static void startServer(String[] args) throws Exception { @@ -30,7 +24,7 @@ public static void startServer(String[] args) throws Exception { server.start(); } - static int parseStream(InputStream is, OutputStream os) throws IOException { + private static int parseStream(InputStream is, OutputStream os) throws IOException { try { new Parse(is, os); } @@ -47,9 +41,9 @@ static int parseStream(InputStream is, OutputStream os) throws IOException { return 0; } - static int parse(String replay_file) throws Exception { - System.out.print(String.format("Parsing file %s", replay_file)); - return parseStream(new FileInputStream(replay_file), System.out); + private static int parseFile(String replayFile) throws Exception { + System.out.print(String.format("Parsing file %s", replayFile)); + return parseStream(new FileInputStream(replayFile), System.out); } static class MyHandler implements HttpHandler { diff --git a/src/main/java/yasp/Parse.java b/src/main/java/yasp/Parse.java index 5dfcf6018..ababb6e98 100644 --- a/src/main/java/yasp/Parse.java +++ b/src/main/java/yasp/Parse.java @@ -37,12 +37,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Iterator; -import yasp.processors.warding.OnWardCountered; import yasp.processors.warding.OnWardExpired; import yasp.processors.warding.OnWardPlaced; - - +import yasp.processors.warding.OnWardKilled; + public class Parse { private class Entry { public Integer time; @@ -298,8 +296,7 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry cle) { } @OnEntityEntered - @OnEntityLeft - public void onEntityExistenceChanged(Context ctx, Entity e) { + public void onEntityEntered(Context ctx, Entity e) { processEntity(ctx, e); } @@ -478,10 +475,10 @@ public void onTickStart(Context ctx, boolean synthetic) { } } - @OnWardCountered - public void onWardCountered(Context ctx, Entity e, String killer_hero_name) { + @OnWardKilled + public void onWardKilled(Context ctx, Entity e, String killerHeroName) { Entry wardEntry = buildWardEntry(ctx, e); - wardEntry.attackername = killer_hero_name; + wardEntry.attackername = killerHeroName; output(wardEntry); } @@ -520,9 +517,9 @@ public void processEntity(Context ctx, Entity e) } } - Entry buildWardEntry(Context ctx, Entity e) { + private Entry buildWardEntry(Context ctx, Entity e) { Entry entry = new Entry(time); - boolean isObserver = e.getDtClass().getDtName().equals("CDOTA_NPC_Observer_Ward"); + boolean isObserver = !e.getDtClass().getDtName().contains("TrueSight"); Integer x = getEntityProperty(e, "CBodyComponent.m_cellX", null); Integer y = getEntityProperty(e, "CBodyComponent.m_cellY", null); Integer z = getEntityProperty(e, "CBodyComponent.m_cellZ", null); @@ -536,8 +533,9 @@ Entry buildWardEntry(Context ctx, Entity e) { entry.key = Arrays.toString(pos); entry.ehandle = e.getHandle(); - if (entry.entityleft) + if (entry.entityleft) { entry.type += "_left"; + } //System.err.println(entry.key); Integer owner = getEntityProperty(e, "m_hOwnerEntity", null); diff --git a/src/main/java/yasp/processors/warding/OnWardCountered.java b/src/main/java/yasp/processors/warding/OnWardKilled.java similarity index 93% rename from src/main/java/yasp/processors/warding/OnWardCountered.java rename to src/main/java/yasp/processors/warding/OnWardKilled.java index 2fe0719da..bc615ad6e 100644 --- a/src/main/java/yasp/processors/warding/OnWardCountered.java +++ b/src/main/java/yasp/processors/warding/OnWardKilled.java @@ -14,6 +14,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(value = ElementType.METHOD) @UsagePointMarker(value = UsagePointType.EVENT_LISTENER, parameterClasses = { Entity.class, String.class }) -public @interface OnWardCountered { +public @interface OnWardKilled { } diff --git a/src/main/java/yasp/processors/warding/Wards.java b/src/main/java/yasp/processors/warding/Wards.java index 34866f9a2..b51178a9e 100644 --- a/src/main/java/yasp/processors/warding/Wards.java +++ b/src/main/java/yasp/processors/warding/Wards.java @@ -33,11 +33,13 @@ * @author micaelbergeron */ @UsesEntities -@Provides({ OnWardCountered.class, OnWardExpired.class, OnWardPlaced.class }) +@Provides({ OnWardKilled.class, OnWardExpired.class, OnWardPlaced.class }) public class Wards { private static final Set WARDS_DT_CLASSES = new HashSet(Arrays.asList( new String[] { + "DT_DOTA_NPC_Observer_Ward", + "DT_DOTA_NPC_Observer_Ward_TrueSight", "CDOTA_NPC_Observer_Ward", "CDOTA_NPC_Observer_Ward_TrueSight" } @@ -56,7 +58,7 @@ public class Wards { private final Queue wardKillers = new ArrayDeque<>(); private Queue toProcess = new ArrayDeque<>(); - private Event evCountered; + private Event evKilled; private Event evExpired; private Event evPlaced; @@ -71,9 +73,9 @@ public ProcessEntityCommand(Entity e, FieldPath p) { } } - @Initializer(OnWardCountered.class) - public void initOnWardCountered(final Context ctx, final EventListener listener) { - evCountered = ctx.createEvent(OnWardCountered.class, Entity.class, String.class); + @Initializer(OnWardKilled.class) + public void initOnWardKilled(final Context ctx, final EventListener listener) { + evKilled = ctx.createEvent(OnWardKilled.class, Entity.class, String.class); } @Initializer(OnWardExpired.class) @@ -94,8 +96,9 @@ public void onCreated(Context ctx, Entity e) { clearCachedState(e); ensureFieldPathForEntityInitialized(e); - if ((lifeStatePath = getFieldPathForEntity(e)) != null) - processLifeStateChange(e, lifeStatePath); + if ((lifeStatePath = getFieldPathForEntity(e)) != null) { + processLifeStateChange(e, lifeStatePath); + } } @OnEntityUpdated @@ -121,8 +124,9 @@ public void onCombatLogEntry(Context ctx, CombatLogEntry entry) { if (!isWardDeath(entry)) return; String killer; - if ((killer = entry.getAttackerName()) != null) - wardKillers.add(killer); + if ((killer = entry.getAttackerName()) != null) { + wardKillers.add(killer); + } } @OnTickEnd @@ -165,17 +169,20 @@ public void processLifeStateChange(Entity e, FieldPath p) { if (oldState != newState) { switch(newState) { case 0: - if (evPlaced != null) + if (evPlaced != null) { evPlaced.raise(e); + } break; case 1: String killer; if ((killer = wardKillers.poll()) != null) { - if (evCountered != null) - evCountered.raise(e, killer); + if (evKilled != null) { + evKilled.raise(e, killer); + } } else { - if (evExpired != null) + if (evExpired != null) { evExpired.raise(e); + } } break; } From 4141fadcdf71aa239c6d3876ad53e239300b33f7 Mon Sep 17 00:00:00 2001 From: "micael.bergeron" Date: Mon, 24 Oct 2016 17:33:57 -0400 Subject: [PATCH 10/12] correct an edge case on same-tick events upon a same-tick event, there is a chance that the ward kill will be credited to the wrong attacker, but this commit limits the impact of this caveat by separating the wards from the sentries. thus you will always be credited a ward kill if you last hit a ward --- pom.xml | 4 ++ .../java/yasp/processors/warding/Wards.java | 65 ++++++++++++------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index 74827b7b7..94d88ee88 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,7 @@ yasp.Main + ${project.build.finalName}-original @@ -94,6 +95,9 @@ + + ${project.build.finalName}.jar +