From: Erik V. <ev...@us...> - 2009-10-07 19:00:46
|
Update of /cvsroot/rails/18xx/rails/game/move In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv9081/rails/game/move Modified Files: ObjectMove.java MoveSet.java PriceTokenMove.java Added Files: MoveStack.java Log Message: Created basic mechanism to allow more games running in parallel at the server side (which itself will not be implemented anytime soon). NDC is used to assign a key to each GameManager. GameManager.getInstance() uses this to find the correct instance. Using this static method to find the GM from anywhere is now 'blessed'. MoveStack added. MoveSet uses the above to have a separate stack per game. Index: MoveSet.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/move/MoveSet.java,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** MoveSet.java 4 Jun 2008 19:00:33 -0000 1.11 --- MoveSet.java 7 Oct 2009 19:00:38 -0000 1.12 *************** *** 1,4 **** /* $Header$ ! * * Created on 17-Jul-2006 * Change Log: --- 1,4 ---- /* $Header$ ! * * Created on 17-Jul-2006 * Change Log: *************** *** 6,16 **** package rails.game.move; ! import java.util.ArrayList; ! import java.util.List; import org.apache.log4j.Logger; ! import rails.game.ReportBuffer; ! import rails.util.LocalText; /** --- 6,15 ---- package rails.game.move; ! import java.util.*; import org.apache.log4j.Logger; ! import rails.game.GameManager; ! import rails.game.GameManagerI; /** *************** *** 19,198 **** public class MoveSet { - private static boolean enabled = false; private List<Move> moves = new ArrayList<Move>(); private boolean undoableByPlayer; /** If TRUE, undoing this move will also undo the previous one. */ private boolean linkedToPrevious = false; - private static MoveSet currentAction = null; - private static List<MoveSet> actionStack = new ArrayList<MoveSet>(); - private static int lastIndex = -1; - protected static Logger log = Logger.getLogger(MoveSet.class.getPackage().getName()); ! private MoveSet(boolean undoableByPlayer) { this.undoableByPlayer = undoableByPlayer; } ! /** ! * Start making moves undoable. Will be called once, after all ! * initialisations are complete. ! */ ! public static void enable() { ! enabled = true; ! } ! ! public static boolean start(boolean undoableByPlayer) { ! log.debug(">>> Start MoveSet (index=" + (lastIndex + 1) + ")"); ! if (currentAction == null) { ! currentAction = new MoveSet(undoableByPlayer); ! while (lastIndex < actionStack.size() - 1) { ! actionStack.remove(actionStack.size() - 1); ! } ! return true; ! } else { ! log.warn("MoveSet is already open"); ! return false; ! } ! } ! ! public static boolean finish() { ! log.debug("<<< Finish MoveSet (index=" + (lastIndex + 1) + ")"); ! if (currentAction == null) { ! log.warn("No action open for finish"); ! return false; ! } else if (currentAction.isEmpty()) { ! log.warn("Action to finish is empty and will be discarded"); ! currentAction = null; ! return true; ! } else { ! actionStack.add(currentAction); ! lastIndex++; ! currentAction = null; ! return true; ! } ! } ! ! public static boolean cancel() { ! if (currentAction != null) { ! currentAction.unexecute(); ! currentAction = null; ! return true; ! } else { ! log.warn("No action open for cancel"); ! return false; ! } } ! public static boolean add(Move move) { ! ! move.execute(); ! if (!enabled) return true; ! ! if (currentAction != null) { ! currentAction.moves.add(0, move); // Prepare for undo in reverse ! // order! ! log.debug("Done: " + move); ! return true; ! } else { ! // Uncomment one of the next statements to detect un-undoable ! // actions ! log.warn("No MoveSet open for " + move); ! return false; ! } ! } ! public static void setLinkedToPrevious() { ! if (currentAction != null) { ! currentAction.linkedToPrevious = true; ! } else { ! log.warn("No MoveSet open"); } } ! public static boolean undo(boolean forced) { ! if ((forced || isUndoableByPlayer()) && currentAction == null ! && lastIndex >= 0 && lastIndex < actionStack.size()) { ! MoveSet undoAction; ! do { ! ReportBuffer.add(LocalText.getText("UNDO")); ! // log.debug ("MoveSet undo index is "+lastIndex); ! undoAction = (MoveSet) actionStack.get(lastIndex--); ! undoAction.unexecute(); ! } while (undoAction.linkedToPrevious); ! return true; ! } else { ! log.error("Invalid undo: index=" + lastIndex + " size=" ! + actionStack.size() + " currentAction=" + currentAction ! + " forced=" + forced + " byPlayer=" ! + isUndoableByPlayer()); ! return false; ! } ! } ! public static boolean redo() { ! if (currentAction == null && lastIndex < actionStack.size() - 1) { ! ReportBuffer.add(LocalText.getText("REDO")); ! ((MoveSet) actionStack.get(++lastIndex)).execute(); ! // log.debug ("MoveSet redo index is "+lastIndex); ! return true; ! } else { ! log.error("Invalid redo: index=" + lastIndex + " size=" ! + actionStack.size()); ! return false; } } ! public static boolean isUndoableByPlayer() { ! return lastIndex >= 0 && actionStack.get(lastIndex).undoableByPlayer; } ! public static boolean isRedoable() { ! return lastIndex < actionStack.size() - 1; } ! public static boolean isUndoableByManager() { ! return lastIndex >= 0; } ! public static boolean isOpen() { ! return currentAction != null; } ! /** ! * Clear the whole stack. To be used if a state change occurs that cannot ! * (yet) be undone. ! * ! * @return ! */ ! public static boolean clear() { ! if (currentAction != null) currentAction.execute(); ! actionStack.clear(); ! currentAction = null; ! lastIndex = -1; ! return true; ! ! } ! private void execute() { ! for (Move move : moves) { ! move.execute(); ! log.debug("Redone: " + move); ! } } ! private void unexecute() { ! ! // TODO Should not the move order be reversed? ! for (Move move : moves) { ! move.undo(); ! log.debug("Undone: " + move); ! } } - private boolean isEmpty() { - return moves.isEmpty(); - } } --- 18,94 ---- public class MoveSet { private List<Move> moves = new ArrayList<Move>(); + private List<Move> reversedMoves = null; private boolean undoableByPlayer; /** If TRUE, undoing this move will also undo the previous one. */ private boolean linkedToPrevious = false; protected static Logger log = Logger.getLogger(MoveSet.class.getPackage().getName()); ! protected MoveSet(boolean undoableByPlayer) { this.undoableByPlayer = undoableByPlayer; } ! protected void addMove (Move move) { ! moves.add(move); ! log.debug("Done: " + move); } ! protected void reexecute() { ! for (Move move : moves) { ! move.execute(); ! log.debug("Redone: " + move); } } ! protected void unexecute() { ! // Create a reversed move list, if not yet done ! if (reversedMoves == null) { ! reversedMoves = new ArrayList<Move>(moves); ! Collections.reverse(reversedMoves); ! } ! for (Move move : reversedMoves) { ! move.undo(); ! log.debug("Undone: " + move); } } ! protected boolean isEmpty() { ! return moves.isEmpty(); } ! public void setLinkedToPrevious() { ! linkedToPrevious = true; } ! protected boolean isLinkedToPrevious() { ! return linkedToPrevious; } ! protected boolean isUndoableByPlayer () { ! return undoableByPlayer; } ! /* Static methods to enable access from anywhere */ ! protected static void add (Move move) { ! move.execute(); ! MoveStack moveStack = getMoveStack(); ! if (moveStack != null) moveStack.addMove(move); } ! private static MoveStack getMoveStack () { ! GameManagerI gameManager = GameManager.getInstance(); ! if (gameManager != null) { ! return gameManager.getMoveStack(); ! } else { ! // No GM during game setup; no problem, as MoveSets are not yet enabled then. ! return null; ! } } } Index: PriceTokenMove.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/move/PriceTokenMove.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** PriceTokenMove.java 25 Sep 2009 19:29:56 -0000 1.4 --- PriceTokenMove.java 7 Oct 2009 19:00:38 -0000 1.5 *************** *** 1,4 **** /* $Header$ ! * * Created on 22-Jul-2006 * Change Log: --- 1,4 ---- /* $Header$ ! * * Created on 22-Jul-2006 * Change Log: *************** *** 6,13 **** package rails.game.move; ! import rails.game.PublicCompanyI; ! import rails.game.StockMarket; ! import rails.game.StockMarketI; ! import rails.game.StockSpaceI; /** --- 6,10 ---- package rails.game.move; ! import rails.game.*; /** *************** *** 30,44 **** } ! public boolean execute() { stockMarket.processMove(company, from, to); return true; } ! public boolean undo() { stockMarket.processMove(company, to, from); return true; } ! public String toString() { return "PriceTokenMove: " + company.getName() + " from " + from + " to " + to; --- 27,44 ---- } ! @Override ! public boolean execute() { stockMarket.processMove(company, from, to); return true; } ! @Override ! public boolean undo() { stockMarket.processMove(company, to, from); return true; } ! @Override ! public String toString() { return "PriceTokenMove: " + company.getName() + " from " + from + " to " + to; --- NEW FILE: MoveStack.java --- /* $Header: /cvsroot/rails/18xx/rails/game/move/MoveStack.java,v 1.1 2009/10/07 19:00:38 evos Exp $ * * Created on 17-Jul-2006 * Change Log: */ package rails.game.move; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import rails.game.ReportBuffer; import rails.util.LocalText; /** * This class represent one game's complete "move stack", which is a list * of MoveSets. Each MoveSet contains the (low-level) changes caused by * one particular player action. * <p>The only purpose of the move stack is to enable Undo and Redo. * @author Erik Vos */ public class MoveStack { private MoveSet currentMoveSet = null; private List<MoveSet> moveStack = new ArrayList<MoveSet>(); private int lastIndex = -1; private boolean enabled = false; protected static Logger log = Logger.getLogger(MoveStack.class.getPackage().getName()); public MoveStack () { } /** * Start making moves undoable. Will be called once, after all * initialisations are complete. */ public void enable() { enabled = true; } public boolean start(boolean undoableByPlayer) { log.debug(">>> Start MoveSet(index=" + (lastIndex + 1) + ")"); if (currentMoveSet == null) { currentMoveSet = new MoveSet(undoableByPlayer); while (lastIndex < moveStack.size() - 1) { moveStack.remove(moveStack.size() - 1); } return true; } else { log.warn("MoveStack is already open"); return false; } } public boolean finish() { log.debug("<<< Finish MoveSet (index=" + (lastIndex + 1) + ")"); if (currentMoveSet == null) { log.warn("No action open for finish"); return false; } else if (currentMoveSet.isEmpty()) { log.warn("Action to finish is empty and will be discarded"); currentMoveSet = null; return true; } else { moveStack.add(currentMoveSet); lastIndex++; currentMoveSet = null; return true; } } public boolean cancel() { if (currentMoveSet != null) { currentMoveSet.unexecute(); currentMoveSet = null; return true; } else { log.warn("No action open for cancel"); return false; } } public boolean addMove (Move move) { if (!enabled) return true; if (currentMoveSet != null) { currentMoveSet.addMove(move); return true; } else { log.warn("No MoveSet open for " + move); return false; } } public void setLinkedToPrevious() { if (currentMoveSet != null) { currentMoveSet.setLinkedToPrevious(); } else { log.warn("No MoveSet open"); } } public boolean undoMoveSet (boolean forced) { if (lastIndex >= 0 && lastIndex < moveStack.size() && (forced || moveStack.get(lastIndex).isUndoableByPlayer()) && currentMoveSet == null) { MoveSet undoAction; do { ReportBuffer.add(LocalText.getText("UNDO")); // log.debug ("MoveStack undo index is "+lastIndex); undoAction = moveStack.get(lastIndex--); undoAction.unexecute(); } while (undoAction.isLinkedToPrevious()); return true; } else { log.error("Invalid undo: index=" + lastIndex + " size=" + moveStack.size() + " currentAction=" + currentMoveSet + " forced=" + forced + " byPlayer=" + isUndoableByPlayer()); return false; } } public boolean redoMoveSet () { if (currentMoveSet == null && lastIndex < moveStack.size() - 1) { ReportBuffer.add(LocalText.getText("REDO")); (moveStack.get(++lastIndex)).reexecute(); // log.debug ("MoveStack redo index is "+lastIndex); return true; } else { log.error("Invalid redo: index=" + lastIndex + " size=" + moveStack.size()); return false; } } public boolean isUndoableByPlayer() { return lastIndex >= 0 && moveStack.get(lastIndex).isUndoableByPlayer(); } public boolean isRedoable() { return lastIndex < moveStack.size() - 1; } public boolean isUndoableByManager() { return lastIndex >= 0; } public boolean isOpen() { return currentMoveSet != null; } } Index: ObjectMove.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/move/ObjectMove.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** ObjectMove.java 4 Jun 2008 19:00:33 -0000 1.5 --- ObjectMove.java 7 Oct 2009 19:00:38 -0000 1.6 *************** *** 1,4 **** /* $Header$ ! * * Created on 17-Jul-2006 * Change Log: --- 1,4 ---- /* $Header$ ! * * Created on 17-Jul-2006 * Change Log: *************** *** 22,26 **** * a Base Token lay, which is physically removed from a PublicCompany and * added to a Station on a MapHex. ! * * @param moveableObject The moveableObject to be moved (e.g. a BaseToken). * @param from Where the moveableObject is removed from (e.g. a --- 22,26 ---- * a Base Token lay, which is physically removed from a PublicCompany and * added to a Station on a MapHex. ! * * @param moveableObject The moveableObject to be moved (e.g. a BaseToken). * @param from Where the moveableObject is removed from (e.g. a *************** *** 40,50 **** } ! public boolean execute() { ! return (from == null || from.removeObject(moveableObject)) && to.addObject(moveableObject); } ! public boolean undo() { return to.removeObject(moveableObject) --- 40,52 ---- } ! @Override ! public boolean execute() { ! return (from == null || from.removeObject(moveableObject)) && to.addObject(moveableObject); } ! @Override ! public boolean undo() { return to.removeObject(moveableObject) *************** *** 52,56 **** } ! public String toString() { if (moveableObject == null) log.error("Token is null"); if (from == null) log.warn("From is null"); --- 54,59 ---- } ! @Override ! public String toString() { if (moveableObject == null) log.error("Token is null"); if (from == null) log.warn("From is null"); |