-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
252 additions
and
199 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
...replay/semantics/records/ChatMessage.java → ...faforever/commons/replay/ChatMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...lay/semantics/records/ModeratorEvent.java → ...orever/commons/replay/ModeratorEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
faf-commons-data/src/main/java/com/faforever/commons/replay/RegisteredEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.faforever.commons.replay; | ||
|
||
import com.faforever.commons.replay.body.Event; | ||
import com.faforever.commons.replay.header.Source; | ||
|
||
/** | ||
* Combines the tick and source of an event. The tick represents when the event was registered. The source represents who authorised the event. | ||
* | ||
* @param tick | ||
* @param source | ||
* @param event | ||
* @see Event | ||
*/ | ||
public record RegisteredEvent(int tick, Source source, Event event) { | ||
} |
11 changes: 8 additions & 3 deletions
11
faf-commons-data/src/main/java/com/faforever/commons/replay/ReplayContainer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
package com.faforever.commons.replay; | ||
|
||
import com.faforever.commons.replay.body.Event; | ||
import com.faforever.commons.replay.header.ReplayHeader; | ||
import com.faforever.commons.replay.semantics.records.TrackedEvent; | ||
|
||
import java.util.List; | ||
|
||
public record ReplayContainer(ReplayMetadata metadata, ReplayHeader header, List<TrackedEvent> trackedEvents) { | ||
/** | ||
* A container of all the information that a replay may hold once parsed. | ||
* | ||
* @param metadata | ||
* @param header | ||
* @param registeredEvents | ||
*/ | ||
public record ReplayContainer(ReplayMetadata metadata, ReplayHeader header, List<RegisteredEvent> registeredEvents) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
faf-commons-data/src/main/java/com/faforever/commons/replay/ReplaySemantics.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package com.faforever.commons.replay; | ||
|
||
import com.faforever.commons.replay.body.Event; | ||
import com.faforever.commons.replay.header.Source; | ||
import com.faforever.commons.replay.shared.LuaData; | ||
|
||
import java.time.Duration; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
public class ReplaySemantics { | ||
|
||
public static Duration tickToDuration(int tick) { | ||
return Duration.ofSeconds(tick / 10); | ||
} | ||
|
||
/** | ||
* Registers the events by attaching a tick and a source to them. | ||
* @param sources | ||
* @param events | ||
* @return | ||
*/ | ||
public static List<RegisteredEvent> registerEvents(List<Source> sources, List<Event> events) { | ||
final int[] tick = {-1}; | ||
final int[] clientId = {-1}; | ||
|
||
return events.stream().map((event) -> switch (event) { | ||
case Event.Advance e -> { | ||
tick[0] = tick[0] + e.ticksToAdvance(); | ||
yield null; | ||
} | ||
|
||
case Event.SetCommandSource e -> { | ||
clientId[0] = e.playerIndex(); | ||
yield null; | ||
} | ||
|
||
default -> new RegisteredEvent(tick[0], sources.get(clientId[0]), event); | ||
}).filter(Objects::nonNull).toList(); | ||
} | ||
|
||
/** | ||
* Retrieves all events that are chat messages | ||
* | ||
* @param events A list of events | ||
* @return A list of events that are chat messages | ||
*/ | ||
public static List<ChatMessage> findChatMessages(List<Source> sources, List<RegisteredEvent> events) { | ||
return events.stream().map((registeredEvent) -> switch (registeredEvent.event()) { | ||
|
||
// TODO: the fact that we piggy-back on the 'GiveResourcesToPlayer' callback to embed chat messages is all wrong! We should instead introduce an alternative callback with the sole purpose to send messages. | ||
// Requires refactoring in the game! | ||
|
||
case Event.LuaSimCallback( | ||
String func, LuaData.Table callbackTable, Event.CommandUnits commandUnits | ||
) when func.equals("GiveResourcesToPlayer") -> { | ||
// TODO: this field has no meaning and can be manipulated, instead use the authorised command source. | ||
// Requires refactoring in the game! | ||
if (!(callbackTable.value().get("From") instanceof LuaData.Number from)) { | ||
yield null; | ||
} | ||
|
||
// focus army starts is 1-based instead of 0-based, to align it we subtract 1 | ||
if (from.value() - 1 <= -2) { | ||
yield null; | ||
} | ||
|
||
// TODO: this field has no meaning and can be manipulated, instead use the authorised command source. | ||
// Requires refactoring in the game! | ||
if (!(callbackTable.value().get("Sender") instanceof LuaData.String sender)) { | ||
yield null; | ||
} | ||
|
||
// TODO: apparently all players create a sim callback that contains the chat message. This hack is how we skip it, | ||
// Requires refactoring in the game! | ||
if (!Objects.equals(sender.value(), registeredEvent.source().name())) { | ||
yield null; | ||
} | ||
|
||
if (!(callbackTable.value().get("Msg") instanceof LuaData.Table msgTable)) { | ||
yield null; | ||
} | ||
|
||
// TODO: this is 1 out of the 2 legitimate fields | ||
if (!(msgTable.value().get("to") instanceof LuaData.String msgTo)) { | ||
yield null; | ||
} | ||
|
||
// TODO: this is 2 out of the 2 legitimate fields | ||
if (!(msgTable.value().get("text") instanceof LuaData.String msgText)) { | ||
yield null; | ||
} | ||
|
||
yield new ChatMessage(tickToDuration(registeredEvent.tick()), registeredEvent.source().name(), msgTo.value(), msgText.value()); | ||
|
||
|
||
} | ||
default -> null; | ||
}).filter(Objects::nonNull).toList(); | ||
} | ||
|
||
|
||
/** | ||
* Retrieves all events that are moderator related | ||
* | ||
* @param events A list of events | ||
* @return A list of events that are moderator related | ||
*/ | ||
public static List<ModeratorEvent> findModeratorMessages(List<Source> sources, List<RegisteredEvent> events) { | ||
return events.stream().map((registeredEvent) -> switch (registeredEvent.event()) { | ||
|
||
// TODO: also read other interesting events, such as: | ||
// - Ping creation callbacks | ||
|
||
case Event.LuaSimCallback( | ||
String func, LuaData.Table callbackTable, Event.CommandUnits commandUnits | ||
) when func.equals("ModeratorEvent") -> { | ||
|
||
String playerNameFromCommandSource = registeredEvent.source().name(); | ||
Integer activeCommandSource = registeredEvent.source().sourceId(); | ||
|
||
String messageContent = null; | ||
String playerNameFromArmy = null; | ||
Integer fromArmy = null; | ||
|
||
// This fields only exists to function as a trap - it doesn't actually affect the messaging even though it appears it does so in-game | ||
if ((callbackTable.value().get("From") instanceof LuaData.Number from)) { | ||
|
||
// focus army starts is 1-based instead of 0-based, to align it we subtract 1 | ||
fromArmy = (int) from.value() - 1; | ||
|
||
if (fromArmy != -2) { | ||
Source source = sources.get(fromArmy); | ||
|
||
if (source != null) { | ||
playerNameFromArmy = (String) source.name(); | ||
} | ||
} | ||
} | ||
|
||
if ((callbackTable.value().get("Message") instanceof LuaData.String content)) { | ||
messageContent = content.value(); | ||
} | ||
|
||
yield new ModeratorEvent(tickToDuration(registeredEvent.tick()), activeCommandSource, fromArmy, messageContent, playerNameFromArmy, playerNameFromCommandSource); | ||
} | ||
default -> null; | ||
}).filter(Objects::nonNull).toList(); | ||
} | ||
} |
Oops, something went wrong.