mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Comparator for GameView object to get diff
This commit is contained in:
parent
6461622204
commit
0adb2220fb
5 changed files with 287 additions and 0 deletions
|
|
@ -0,0 +1,22 @@
|
|||
package mage.network.protocol.change;
|
||||
|
||||
/**
|
||||
* Defines chunk of update: what is updated and data.
|
||||
*
|
||||
* @author magenoxx
|
||||
*/
|
||||
public class ChangePart {
|
||||
|
||||
private ChangeType changeType;
|
||||
|
||||
private Object data;
|
||||
|
||||
public ChangePart(final ChangeType changeType, Object data) {
|
||||
this.changeType = changeType;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package mage.network.protocol.change;
|
||||
|
||||
/**
|
||||
* Defines parts that can be sent to client as partly update instead of full game update.
|
||||
*
|
||||
* @author magenoxx
|
||||
*/
|
||||
public enum ChangeType {
|
||||
|
||||
PRIORITY_PLAYER_NAME,
|
||||
PRIORITY_TIME,
|
||||
|
||||
ACTIVE_PLAYER_ID,
|
||||
ACTIVE_PLAYER_NAME,
|
||||
|
||||
CAN_PLAY_IN_HAND,
|
||||
HAND,
|
||||
OPPONENT_HANDS,
|
||||
WATCHED_HANDS,
|
||||
LOOKED_AT,
|
||||
REVEALED,
|
||||
|
||||
EXILE,
|
||||
STACK,
|
||||
PLAYERS,
|
||||
|
||||
COMBAT,
|
||||
SPECIAL,
|
||||
PHASE,
|
||||
STEP,
|
||||
TURN,
|
||||
SPELLS_CAST_THIS_TURN,
|
||||
|
||||
/**
|
||||
* This is full update that repeats previous approach.
|
||||
*/
|
||||
FULL
|
||||
;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package mage.network.protocol.change.compator;
|
||||
|
||||
/**
|
||||
* Compares two objects
|
||||
*
|
||||
* @author magenoxx
|
||||
*/
|
||||
public interface Comparator<T> {
|
||||
|
||||
/**
|
||||
* Compares two objects and returns {@link CompareResult} with map of partly updates
|
||||
*
|
||||
* @param objectA object to compare with
|
||||
* @param objectB object to compare with
|
||||
* @return result of compare
|
||||
*/
|
||||
CompareResult compare(T objectA, T objectB);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package mage.network.protocol.change.compator;
|
||||
|
||||
import mage.network.protocol.change.ChangePart;
|
||||
import mage.network.protocol.change.ChangeType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author magenoxx
|
||||
*/
|
||||
public class CompareResult extends HashMap<ChangeType, ChangePart> implements Serializable {
|
||||
|
||||
private boolean isEqual = false;
|
||||
|
||||
public void setEqual(final boolean equal) {
|
||||
isEqual = equal;
|
||||
}
|
||||
|
||||
public boolean isEqual() {
|
||||
return isEqual;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package mage.network.protocol.change.compator.impl;
|
||||
|
||||
import mage.network.protocol.change.ChangePart;
|
||||
import mage.network.protocol.change.ChangeType;
|
||||
import mage.network.protocol.change.compator.Comparator;
|
||||
import mage.network.protocol.change.compator.CompareResult;
|
||||
import mage.view.ExileView;
|
||||
import mage.view.GameView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link Comparator} for {@link GameView}
|
||||
*
|
||||
* Compares various parts independently and returns only parts that differ.
|
||||
*
|
||||
* @author magenoxx
|
||||
*/
|
||||
public class GameViewComparator implements Comparator<GameView> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GameViewComparator.class);
|
||||
|
||||
@Override
|
||||
public CompareResult compare(final GameView newGameView, final GameView prevGameView) {
|
||||
final CompareResult result = new CompareResult();
|
||||
|
||||
if (newGameView == null) {
|
||||
throw new IllegalArgumentException("New GameView can't be null");
|
||||
}
|
||||
if (prevGameView == null) {
|
||||
throw new IllegalArgumentException("Prev GameView can't be null");
|
||||
}
|
||||
|
||||
// Priority Player Name
|
||||
if (!Objects.equals(newGameView.getPriorityPlayerName(), prevGameView.getPriorityPlayerName())) {
|
||||
logger.debug("Priority Player Name has changed");
|
||||
result.put(ChangeType.PRIORITY_PLAYER_NAME ,new ChangePart(ChangeType.PRIORITY_PLAYER_NAME, newGameView
|
||||
.getPriorityPlayerName()));
|
||||
}
|
||||
|
||||
// Active player
|
||||
if (!Objects.equals(newGameView.getActivePlayerId(), prevGameView.getActivePlayerId())) {
|
||||
logger.debug("Active player has changed");
|
||||
result.put(ChangeType.ACTIVE_PLAYER_ID ,new ChangePart(ChangeType.ACTIVE_PLAYER_ID, newGameView.getActivePlayerId()));
|
||||
result.put(ChangeType.ACTIVE_PLAYER_NAME ,new ChangePart(ChangeType.ACTIVE_PLAYER_NAME, newGameView.getActivePlayerName()));
|
||||
}
|
||||
|
||||
if (!Objects.equals(newGameView.getExile(), prevGameView.getExile())) {
|
||||
logger.debug("Exile has changed");
|
||||
result.put(ChangeType.EXILE ,new ChangePart(ChangeType.EXILE, newGameView.getExile()));
|
||||
}
|
||||
|
||||
// Hand
|
||||
if (!Objects.equals(newGameView.getHand(), prevGameView.getHand())) {
|
||||
logger.debug("Hand has changed");
|
||||
result.put(ChangeType.HAND, new ChangePart(ChangeType.HAND, newGameView.getHand()));
|
||||
}
|
||||
|
||||
// Can play in hand
|
||||
if (result.containsKey(ChangeType.HAND) || !Objects.equals(newGameView.getCanPlayInHand(), prevGameView.getCanPlayInHand())) {
|
||||
// TODO: improve - separate from HAND
|
||||
logger.debug("Can play in hand has changed");
|
||||
result.put(ChangeType.CAN_PLAY_IN_HAND ,new ChangePart(ChangeType.CAN_PLAY_IN_HAND, newGameView.getCanPlayInHand()));
|
||||
}
|
||||
|
||||
|
||||
// isSpecial
|
||||
if (newGameView.getSpecial() != prevGameView.getSpecial()) {
|
||||
logger.debug("Special has changed");
|
||||
result.put(ChangeType.SPECIAL ,new ChangePart(ChangeType.SPECIAL, newGameView.getSpecial()));
|
||||
}
|
||||
|
||||
// LookedAt
|
||||
if (!Objects.equals(newGameView.getLookedAt(), prevGameView.getLookedAt())) {
|
||||
logger.debug("LookedAt has changed");
|
||||
result.put(ChangeType.LOOKED_AT ,new ChangePart(ChangeType.LOOKED_AT, newGameView.getLookedAt()));
|
||||
}
|
||||
|
||||
// Phase
|
||||
if (!Objects.equals(newGameView.getPhase(), prevGameView.getPhase())) {
|
||||
logger.debug("Phase has changed");
|
||||
result.put(ChangeType.PHASE ,new ChangePart(ChangeType.PHASE, newGameView.getPhase()));
|
||||
}
|
||||
// Step
|
||||
if (!Objects.equals(newGameView.getStep(), prevGameView.getStep())) {
|
||||
logger.debug("Step has changed");
|
||||
result.put(ChangeType.PHASE ,new ChangePart(ChangeType.STEP, newGameView.getStep()));
|
||||
}
|
||||
|
||||
// Revealed
|
||||
if (!Objects.equals(newGameView.getRevealed(), prevGameView.getRevealed())) {
|
||||
logger.debug("Revealed has changed");
|
||||
result.put(ChangeType.REVEALED ,new ChangePart(ChangeType.REVEALED, newGameView.getRevealed()));
|
||||
}
|
||||
|
||||
if (!Objects.equals(newGameView.getOpponentHands(), prevGameView.getOpponentHands())) {
|
||||
logger.debug("Opponent Hands has changed");
|
||||
result.put(ChangeType.OPPONENT_HANDS ,new ChangePart(ChangeType.OPPONENT_HANDS, newGameView.getOpponentHands()));
|
||||
}
|
||||
|
||||
if (newGameView.getSpellsCastCurrentTurn() != prevGameView.getSpellsCastCurrentTurn()) {
|
||||
logger.debug("Spells Cast Current Turn has changed");
|
||||
result.put(ChangeType.SPELLS_CAST_THIS_TURN ,new ChangePart(ChangeType.SPELLS_CAST_THIS_TURN, newGameView.getSpellsCastCurrentTurn()));
|
||||
}
|
||||
|
||||
if (newGameView.getTurn() != prevGameView.getTurn()) {
|
||||
logger.debug("Turn has changed");
|
||||
result.put(ChangeType.TURN ,new ChangePart(ChangeType.TURN, newGameView.getTurn()));
|
||||
}
|
||||
|
||||
if (!Objects.equals(newGameView.getWatchedHands(), prevGameView.getWatchedHands())) {
|
||||
logger.debug("Wathed hands have changed");
|
||||
result.put(ChangeType.WATCHED_HANDS ,new ChangePart(ChangeType.WATCHED_HANDS, newGameView.getWatchedHands()));
|
||||
}
|
||||
|
||||
// Combat
|
||||
if (!Objects.equals(newGameView.getCombat(), prevGameView.getCombat())) {
|
||||
logger.debug("Combat has changed");
|
||||
result.put(ChangeType.COMBAT ,new ChangePart(ChangeType.COMBAT, newGameView.getCombat()));
|
||||
}
|
||||
|
||||
// Stack
|
||||
if (!Objects.equals(newGameView.getStack(), prevGameView.getStack())) {
|
||||
logger.debug("Stack has changed");
|
||||
result.put(ChangeType.STACK ,new ChangePart(ChangeType.STACK, newGameView.getStack()));
|
||||
}
|
||||
|
||||
// Players with Battlefield/Graveyard/Exile/etc.
|
||||
// TODO: place to improve (and split)
|
||||
if (!Objects.equals(newGameView.getPlayers(), prevGameView.getPlayers())) {
|
||||
logger.debug("Players has changed");
|
||||
result.put(ChangeType.PLAYERS ,new ChangePart(ChangeType.PLAYERS, newGameView.getPlayers()));
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
logger.debug("GameViews are equal");
|
||||
result.setEqual(true);
|
||||
} else {
|
||||
// priority time is changed every second so we don't want to send it on every update
|
||||
// instead of doing so we spend priorityTime update only if previous result is not empty
|
||||
//TODO: probably we should send it also if we haven't updated too long (e.g. 10 seconds)
|
||||
result.put(ChangeType.PRIORITY_TIME ,new ChangePart(ChangeType.PRIORITY_TIME, newGameView.getPriorityTime()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean equalsWithNull(final Object objectA, final Object objectB) {
|
||||
if (objectA == null || objectB == null) {
|
||||
return objectA == null && objectB == null;
|
||||
}
|
||||
|
||||
return objectA.equals(objectB);
|
||||
}
|
||||
|
||||
private void compare(final ChangeType type, final List<ExileView> exile1, final
|
||||
List<ExileView> exile2, final CompareResult result) {
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
try {
|
||||
if (exile1.size() != exile2.size()) {
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (final ExileView exileView : exile1) {
|
||||
if (!exileView.equals(exile2)) {
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (changed) {
|
||||
logger.debug("Exile has changed");
|
||||
result.put(type, new ChangePart(type, exile2));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue