Skip to content

Commit

Permalink
Enhanced ReplayDataParser with ModeratorEvent Support (#123)
Browse files Browse the repository at this point in the history
* Added ModeratorEvent to ReplayDataParser and handled activeCommandSource (#121)

* WIP

* Removed unused code

* Removed unnecessary code and added basic unit testing for testParseModeratorEvent

* Changed from Float to Integer, represents focus army

* Switched to using Java records instead of traditional classes for less boilerplate code
  • Loading branch information
magge-faf authored Mar 22, 2024
1 parent 77e0b54 commit 6e46109
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.faforever.commons.replay;

import java.time.Duration;

public record ModeratorEvent(Duration time, String sender, String message, int activeCommandSource) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -58,6 +53,8 @@ public class ReplayDataParser {
@Getter
private List<ChatMessage> chatMessages;
@Getter
private List<ModeratorEvent> moderatorEvents;
@Getter
private Map<Integer, Map<Integer, AtomicInteger>> commandsPerMinuteByPlayer;
private float x;
private float y;
Expand All @@ -73,6 +70,7 @@ public ReplayDataParser(Path path, ObjectMapper objectMapper) throws IOException
this.objectMapper = objectMapper;
armies = new HashMap<>();
chatMessages = new ArrayList<>();
moderatorEvents = new ArrayList<>();
commandsPerMinuteByPlayer = new HashMap<>();
parse();
}
Expand Down Expand Up @@ -280,6 +278,10 @@ private void parseTicks(LittleEndianDataInputStream dataStream) throws IOExcepti
parseGiveResourcesToPlayer((Map<String, Object>) lua);
}

if (Objects.equals("ModeratorEvent", functionName)) {
parseModeratorEvent((Map<String, Object>) lua);
}

// No idea what this skips
if (lua != null) {
dataStream.skipBytes(4 * dataStream.readInt());
Expand Down Expand Up @@ -375,6 +377,18 @@ private void parseGiveResourcesToPlayer(Map<String, Object> lua) {
}
}


void parseModeratorEvent(Map<String, Object> lua) {
String messageContent = (String) lua.get("Message");
int fromInt = ((Number) lua.get("From")).intValue();
int activeCommandSource = 0; // activeCommandSource is not available in .fafreplay, yet
if (lua.containsKey("activeCommandSource")) {
activeCommandSource = ((Number) lua.get("activeCommandSource")).intValue();
}
moderatorEvents.add(new ModeratorEvent(tickToTime(ticks), Integer.toString(fromInt), messageContent, activeCommandSource));
}


private Duration tickToTime(int tick) {
return Duration.ofSeconds(tick / 10);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.LittleEndianDataInputStream;
import org.apache.commons.compress.compressors.CompressorException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ReplayDataParserTest {

Expand Down Expand Up @@ -121,4 +125,17 @@ public void testLegacyFormat() throws Exception {
byte[] reference = Files.readAllBytes(referenceFile);
assertThat("Legacy compressed file matches reference", Arrays.equals(data, reference));
}

@Test
public void testParseModeratorEvent() throws CompressorException, IOException {
Path replayFile = temporaryFolder.resolve("TestModeratorEvents.fafreplay");
Files.copy(Objects.requireNonNull(getClass().getResourceAsStream("/replay/TestModeratorEvents.fafreplay")), replayFile);

ReplayDataParser parser = new ReplayDataParser(replayFile, objectMapper);

List<ModeratorEvent> moderatorEvents = parser.getModeratorEvents();
ModeratorEvent firstEvent = moderatorEvents.getFirst();
assertEquals(Duration.ofSeconds(20), firstEvent.time());
assertEquals("Created a marker with the text: 'my fabelous marker test'", firstEvent.message());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"compression":null,"host":"magge","uid":22099630,"title":"FAF Develop test stuff","mapname":"scmp_039","options":null,"teams":{"2=[67103]":["magge"]},"complete":true,"recorder":"magge","state":"CLOSED","game_type":"UNKNOWN","featured_mod":"fafdevelop","max_players":4,"num_players":1,"sim_mods":{},"featured_mod_versions":{},"version_info":{"lobby":"dfaf-2024.3.0"},"game_end":1.710945031215E9,"time":0.0,"launched_at":1.71094495591E9}
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

0 comments on commit 6e46109

Please sign in to comment.