Java RMI游戏未运行

时间:2013-11-28 06:32:33

标签: java client-server rmi

我一直在撞墙试图解决这个问题。很确定我今天丢了一些头发。

基本上,我们获得了一些工作类,并被要求在其上实施RMI。在给定的代码中有一些错误,但我修复了它们。现在我没有任何错误,而且它无法正常工作。

以下是课程:

GameClient.java - 由我完成

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class GameClient extends UnicastRemoteObject implements IGUI, IGameEngine, Runnable {
    IGameServer ser;
    PlayerInfo player;
    IGUI g;
    IGameEngine ge;

    public GameClient(IGameServer ss) throws RemoteException {
        ser = ss;
        ser.registerClient(this);
    }

    @Override
    public void markedAsOriginalDisplayMode() throws RemoteException {
        g.markedAsOriginalDisplayMode();
    }

    @Override
    public void noMarkedDisplayMode() throws RemoteException {
        g.noMarkedDisplayMode();
    }

    @Override
    public void normalDisplayMode() throws RemoteException {
        g.normalDisplayMode();
    }

    @Override
    public void update() throws RemoteException {
        g.update();
    }

    @Override
    public void exit(int i) throws RemoteException {
        g = null;
        setGUI(g);
        ser.setGameOver();
        System.exit(i);
    }

    @Override
    public PlayingBlock getNextBlock() throws RemoteException {
        return ser.getNextBlock();
    }

    @Override
    public PlayArea getPlayArea() throws RemoteException {
        return ser.getPlayArea();
    }

    @Override
    public String getPlayerName() throws RemoteException {
        return ser.getPlayerName();
    }

    @Override
    public int getPlayerScore() throws RemoteException {
        return ser.getPlayerScore();
    }

    @Override
    public boolean isGameOver() throws RemoteException {
        return ser.isGameOver();
    }

    @Override
    public void setGameOver() throws RemoteException {
        ser.setGameOver();
    }

    public void setGUI(IGUI gui) {
        g = gui;
    }

    @Override
    public void setPlayer(PlayerInfo pi) {
        try {
            ser.setPlayer(pi);
        }
        catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setPlayerName(String name) throws RemoteException {
        ser.setPlayerName(name);
    }

    @Override
    public void start() throws RemoteException {
        ser.start();
    }

    @Override
    public void treatEvent(int event) throws RemoteException {
        ser.treatEvent(event);
    }

    @Override
    public void run() {
        String playerName = "Vasilis";
        setPlayer(new PlayerInfo(playerName));
        IGUI gui = new GUI(this, 20, 25);
        setGUI(gui);
    }
} 

IGameEngine.java

import java.rmi.RemoteException;

/**
 * Interface representing the logic of the game
 */

public interface IGameEngine {

    public void treatEvent(int event) throws RemoteException;

    public void start() throws RemoteException;

    public PlayingBlock getNextBlock() throws RemoteException;

    public boolean isGameOver() throws RemoteException;

    public void setGameOver() throws RemoteException;

    public PlayArea getPlayArea() throws RemoteException;

    public int getPlayerScore() throws RemoteException;

    public void setPlayerName(String name) throws RemoteException;

    public void setPlayer(PlayerInfo pi);

    public String getPlayerName() throws RemoteException;

    public void setGUI(IGUI gui);

    public void exit(int status) throws RemoteException;

}

GameEngine.java

import java.rmi.RemoteException;
import java.util.*;

class GameEngine {
    private PlayArea board;

    private PlayerInfo player;

    private PlayingBlock activeBlock;

    private PlayingBlock nextBlock;

    private Timer timer;

    private TimerTask pendingTask;

    private int timerValue;

    private float timerScaleFactor;

    private int minTimerValue;

    private int timerValueChangeInterval;

    private int numBlocks;

    private Random rng;

    private IGUI gui;

    private boolean gameOver;

    private boolean controlsLocked;

    public GameEngine(int size) {
        board = new PlayArea(size);
        rng = new Random(System.currentTimeMillis());
        resetGame();
    }

    protected void resetGame() {
        nextBlock = null;
        board.init();
        timerScaleFactor = Settings.TIMERSCALE;
        minTimerValue = Settings.MINTIMER;
        timerValue = Settings.INITTIMER;
        timerValueChangeInterval = Settings.CHANGETIMER;
        timer = new Timer();
        gameOver = false;
        controlsLocked = true;
        if (player != null) player.reset();
    }

    public void setGUI(IGUI gui) {
        this.gui = gui;
    }

    private void updateGUI() throws RemoteException {
        gui.update();
    }

    public void setPlayer(PlayerInfo player) {
        this.player = player;
    }

    public String getPlayerName() {
        return player.getName();
    }

    public void setPlayerName(String name) {
        player.setName(name);
    }

    public int getPlayerScore() {
        return player.getScore();
    }

    public PlayArea getPlayArea() {
        return board;
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public void setGameOver() {
        this.gameOver = true;
    }

    public PlayingBlock getNextBlock() {
        return nextBlock;
    }

    // --> game_engine_timer_methods
    private void adjustTimerValue() {
        if (++numBlocks % timerValueChangeInterval == 0) {
            float nextTimerValue = (float) timerValue / timerScaleFactor;
            timerValue = nextTimerValue < minTimerValue ? minTimerValue : Math.round(nextTimerValue);
        }
    }

    private void rescheduleTimer() {
        stopTimer();
        final PlayingBlock block = activeBlock;
        pendingTask = new TimerTask() {
            public void run() {
                synchronized (GameEngine.this) {
                    if (block.equals(activeBlock)) try {
                        treatEvent(GameEvent.TIMEOUT);
                    }
                    catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        timer.schedule(pendingTask, timerValue);
    }

    // --<
    // --> game_engine_start_method
    public void start() throws RemoteException {
        resetGame();
        nextBlock = new PlayingBlock(rng.nextInt(3) + 1, Colour.randomColour(rng), PlayArea.randomSide(rng));
        nextBlock();
        updateGUI();
        controlsLocked = false;
        rescheduleTimer();
    }

    public void stopTimer() {
        if (pendingTask != null) pendingTask.cancel();
    }

    public void exit(int status) {
        System.exit(status);
    }

    // --<
    // --> game_engine_nextBlock_method
    private boolean nextBlock() {
        int size = board.getSize();
        switch (nextBlock.getSide()) {
            case PlayArea.NORTHSIDE:
                nextBlock.activate(new Coord(size / 2, 1).add(nextBlock.getCoG().neg()));
                break;
            case PlayArea.SOUTHSIDE:
                nextBlock.activate(new Coord(size / 2, size - 2).add(nextBlock.getCoG().neg()));
                break;
            case PlayArea.EASTSIDE:
                nextBlock.activate(new Coord(size - 2, size / 2).add(nextBlock.getCoG().neg()));
                break;
            case PlayArea.WESTSIDE:
                nextBlock.activate(new Coord(1, size / 2).add(nextBlock.getCoG().neg()));
                break;
            default: // should never occur
                break;
        }
        activeBlock = nextBlock;
        if (board.collision(activeBlock)) return false;
        else {
            board.flipDraw(activeBlock);
            nextBlock = new PlayingBlock(rng.nextInt(3) + 1, Colour.randomColour(rng), PlayArea.randomSide(rng));
            adjustTimerValue();
            return true;
        }
    }

    // --<
    // --> game_engine_movement_methods
    private boolean rotate() {
        return move(null);
    }

    private boolean slideActiveBlock() {
        return move(activeBlock.getSlidingDirection());
    }

    private boolean move(Direction direction) {
        boolean success = false;

        // is the move forbidden?
        if (direction != null && direction.equals(activeBlock.getSlidingDirection().getReverse())) return false;

        board.flipDraw(activeBlock);
        if (direction == null) activeBlock.rotate();
        else activeBlock.move(direction);
        if (!board.collision(activeBlock)) success = true;
        else // put activeBlock back
            if (direction == null) activeBlock.rotate();
            else activeBlock.move(direction.getReverse());
        board.flipDraw(activeBlock);
        return success;
    }

    // --<
    // --> game_engine_event_handler
    synchronized public void treatEvent(int event) throws RemoteException {
        if (controlsLocked || gameOver) return;

        switch (event) {
            case GameEvent.TIMEOUT:
                if (slideActiveBlock()) {
                    rescheduleTimer();
                    updateGUI();
                    break;
                }
                else {
                    updateScore();
                    return;
                }
            case GameEvent.UP:
                if (move(Direction.up())) updateGUI();
                break;
            case GameEvent.DOWN:
                if (move(Direction.down())) updateGUI();
                break;
            case GameEvent.RIGHT:
                if (move(Direction.right())) updateGUI();
                break;
            case GameEvent.LEFT:
                if (move(Direction.left())) updateGUI();
                break;
            case GameEvent.ROTATE:
                if (rotate()) updateGUI();
                break;
            case GameEvent.FLY:
                pendingTask.cancel();
                pendingTask = null;
                while (slideActiveBlock()) ;
                updateScore();
                return;
            default:
                // should never occur
        }
    }

    // --<
    // --> game_engine_scoring_methods
    private void updateScore() {
        controlsLocked = true;
        new Thread() {
            public void run() {
                int rounds = 0;
                while (findSquares(++rounds)) {
                    // animate square
                    for (int i = 0; i < 4; i++) {
                        if (i % 2 == 0) try {
                            gui.markedAsOriginalDisplayMode();
                        }
                        catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        else try {
                            gui.normalDisplayMode();
                        }
                        catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        try {
                            updateGUI();
                        }
                        catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        try {
                            Thread.sleep(150);
                        }
                        catch (InterruptedException e) {
                            e.printStackTrace();
                            exit(1);
                        }
                    }
                    try {
                        updateBoard();
                    }
                    catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

                if (nextBlock()) {
                    rescheduleTimer();
                }
                else {
                    timer.cancel();
                    gameOver = true;
                }
                try {
                    updateGUI(); // new block is active, display
                }
                catch (RemoteException e) {
                    e.printStackTrace();
                }
                controlsLocked = false; // unlock controls
            }
        }.start();
    }

    private boolean findSquares(int round) {
        int roundScore = 0;
        // brute force
        boolean found = false;
        int playSize = board.getSize();
        for (int size = 3; size >= 2; size--)
            for (int x = 0; x < playSize; x++)
                for (int y = 0; y < playSize; y++) {
                    int squareColour = board.getSquareColour(x, y, size);
                    if (Colour.isPlayBrick(squareColour)) {
                        roundScore += size * size;
                        // player.incScore((int) Math.pow(size * size, round));
                        if (size == 2) {
                            board.mark(x, y, size);
                            found = true;
                        }
                    }
                }
        if (roundScore > 0) player.incScore((int) Math.pow(roundScore, round));
        return found;
    }

    public void updateBoard() throws RemoteException {
        Direction blockDir = activeBlock.getSlidingDirection();
        Direction updateDir = blockDir.getReverse();
        Coord checkBrick;
        boolean falling;
        int size = board.getSize();

        gui.noMarkedDisplayMode();
        for (int i = 0; i < size; i++) {
            falling = false;

            if (blockDir.equals(Direction.up())) checkBrick = new Coord(i, 0);
            else if (blockDir.equals(Direction.down())) checkBrick = new Coord(i, size - 1);
            else if (blockDir.equals(Direction.left())) checkBrick = new Coord(0, i);
            else checkBrick = new Coord(size - 1, i);

            for (int j = 0; j < size; j++) {
                int brickColour = board.getBrick(checkBrick);
                if (Colour.isMarked(brickColour)) {
                    falling = true;
                    board.setBrick(checkBrick, Colour.BASE);
                }
                else if (falling) if (Colour.isPlayBrick(brickColour)) {
                    board.setBrick(checkBrick, Colour.BASE);
                    PlayingBlock tmpBlock = new PlayingBlock(1, brickColour, PlayArea.NORTHSIDE);
                    // we just need any temporary block
                    tmpBlock.activate(checkBrick.add(blockDir.getCoordIncrement()));
                    while (!board.collision(tmpBlock)) {
                        // animate the fall
                        board.flipDraw(tmpBlock);
                        updateGUI();
                        try {
                            Thread.sleep(50);
                        }
                        catch (InterruptedException e) {
                            e.printStackTrace();
                            exit(1);
                        }
                        board.flipDraw(tmpBlock);
                        tmpBlock.move(blockDir);
                    }
                    tmpBlock.move(updateDir);
                    board.flipDraw(tmpBlock);
                }
                else {
                    break; /* stop falling, finish with this loop */
                }
                checkBrick = checkBrick.add(updateDir.getCoordIncrement());
            }
        }
        gui.normalDisplayMode();
    }
    // --<
}

IGUI.java

/**
 * The server's remote reference to a client
 *
 *
 */

import java.rmi.*;

public interface IGUI extends Remote {

    public void update() throws RemoteException;

    public void normalDisplayMode() throws RemoteException;

    public void noMarkedDisplayMode() throws RemoteException;

    public void markedAsOriginalDisplayMode() throws RemoteException;

}

Squares.java

import java.rmi.RemoteException;

//--> squares_class
class Squares {

    public static void main(String[] args) throws RemoteException {
        GameClient gc = new GameClient();
        String playerName = "Quidam";

        if (args.length == 1) if (args[0].length() > 15) playerName = args[0].substring(0, 15);
        else playerName = args[0];
        gc.setPlayer(new PlayerInfo(playerName));

        IGUI gui = new GUI(gc, 20, 25);
        gc.setGUI(gui);

    }
}
// --<

IGameServer.java

/**
 * The interface which defines what operations our server can perform for clients
 *
 *
 */

import java.rmi.*;

public interface IGameServer extends Remote {

    public void registerClient(IGUI clientGUI) throws RemoteException;

    public void treatEvent(int event) throws RemoteException;

    public void start() throws RemoteException;

    public PlayingBlock getNextBlock() throws RemoteException;

    public boolean isGameOver() throws RemoteException;

    public void setGameOver() throws RemoteException;

    public PlayArea getPlayArea() throws RemoteException;

    public int getPlayerScore() throws RemoteException;

    public void setPlayerName(String name) throws RemoteException;

    public void setPlayer(PlayerInfo pi) throws RemoteException;

    public String getPlayerName() throws RemoteException;

}

这是我创建的文件GameServer.java

import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;

/**
 * Created with IntelliJ IDEA.
 * User: akay
 * Date: 25/11/2013
 * Time: 19:07
 * To change this template use File | Settings | File Templates.
 */
public class GameServer extends UnicastRemoteObject implements IGameServer, Serializable {
    LinkedList<IGUI> array;
    GameEngine ge = new GameEngine(25);

    public GameServer() throws RemoteException {
        array = new LinkedList();
    }

    @Override
    public PlayingBlock getNextBlock() throws RemoteException {
        return ge.getNextBlock();
    }

    @Override
    public PlayArea getPlayArea() throws RemoteException {
        return ge.getPlayArea();
    }

    @Override
    public String getPlayerName() {
        return ge.getPlayerName();
    }

    @Override
    public int getPlayerScore() {
        return ge.getPlayerScore();
    }

    @Override
    public boolean isGameOver() throws RemoteException {
        return ge.isGameOver();
    }

    @Override
    public void registerClient(IGUI clientGUI) throws RemoteException {
        array.add(clientGUI);
        ge.setGUI(clientGUI);
    }

    @Override
    public void setGameOver() throws RemoteException {
        ge.setGameOver();
    }

    @Override
    public void setPlayer(PlayerInfo pi) {
        ge.setPlayer(pi);
    }

    @Override
    public void setPlayerName(String name) {
        ge.setPlayerName(name);
    }

    @Override
    public void start() throws RemoteException {
        ge.start();
    }

    @Override
    public void treatEvent(int event) throws RemoteException {
        ge.treatEvent(event);
    }

    public static void main(String args[]) throws RemoteException {

        Registry registry;
        GameServer s;
        final int port = Registry.REGISTRY_PORT;

        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new java.rmi.RMISecurityManager());
        }

        try {
            registry = LocateRegistry.createRegistry(port);
        }
        catch (RemoteException e) {
            System.out.println("The registry couldn't be created.");
            e.printStackTrace();
        }

        try {
            s = new GameServer();
            java.rmi.Naming.rebind("Server", s);
        }
        catch (MalformedURLException e) {
            System.out.println("Bad server URI in registration.");
        }
        catch (RemoteException e) {
            System.out.println("Couldn't bind server.");
            e.printStackTrace();
        }

        try {
            System.in.read();
        }
        catch (IOException e) {
        }

        System.exit(0);
    }
}

修改了这些文件以修复错误并实施RMI。现在,应该采取的步骤如下:

  1. 创建实现GameClientIGUI的{​​{1}}类 IGameEngine接口。它将使用注册表找到服务器, 并接受来自GUI的本地电话,将其转换为远程电话 调用服务器并返回任何结果。
  2. 更改GUI类,使其对GameEngine的引用的类型为IGameEngine,而不是
  3. Squares类将启动游戏的客户端部分,现在需要创建GameClient的实例并将其作为参考传递给GUIIGameEngine
  4. 创建实现GameServer接口的IGameServer类,并包含启动服务器和游戏引擎的main()方法
  5. 更改GameEngine类,使其对GUI的引用现在为IGUI类型;这将是它对客户端的远程引用。由于GameEngine现在远程调用GUI,您需要捕获一些例外情况。
  6. 编译您所做的事情,修复您遇到的任何错误,然后尝试运行您的分布式游戏。您可能会看到一些您还需要解决的运行时异常。
  7. 这些是建议的步骤。我已经实现了除了一个之外的所有,这是第三个。

    感谢任何帮助。

    如果您想下载zip文件中的所有文件,请输入:http://akay.me/gameCode.zip

    感谢您的任何指示。

    编辑: 我编辑了我的Squares类,通过包含以下内容从注册表中获取服务器名称:

    String host = null;
    
    Registry registry = LocateRegistry.getRegistry(host);
    IGameServer s = (IGameServer) registry.lookup("Server");
    GameClient gc = new GameClient(s);
    

    正如所建议的那样。

    现在我收到以下错误:

    java.rmi.MarshalException: error marshalling arguments; nested exception is: 
        java.io.NotSerializableException: PlayerInfo
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:138)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
        at com.sun.proxy.$Proxy0.setPlayer(Unknown Source)
        at GameClient.setPlayer(GameClient.java:80)
        at Squares.main(Squares.java:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
    Caused by: java.io.NotSerializableException: PlayerInfo
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1165)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:329)
        at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:274)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:133)
        ... 10 more
    Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at GameEngine.getPlayerName(GameEngine.java:67)
    

1 个答案:

答案 0 :(得分:2)

您确实需要学习阅读错误消息。它们具有问题的精确位置,并且问题的描述也很清楚:

  GameClient类中的

构造函数GameClient不能应用于给定的类型; required:发现IGameServer:无参数原因:实际和正式参数列表的长度不同

那么,这是什么意思?这意味着你在没有任何参数的情况下调用new GameClient(),而GameClient的构造函数被声明为

public GameClient(IGameServer ss) throws RemoteException {

因此,您必须将IGameServer类型的对象传递给构造函数,而不是传递任何内容。