📄 mjserver.java
字号:
package com.newpalm.game.mj.server;
import java.util.Observer;
import com.newpalm.game.framework.Client;
import com.newpalm.game.framework.Server;
import com.newpalm.game.mj.client.MJBotClient;
import com.newpalm.game.mj.client.MJClient;
import com.newpalm.game.mj.share.GameState;
import com.newpalm.game.mj.share.MJCard;
import com.newpalm.game.mj.share.MJEventEat;
import com.newpalm.game.mj.share.Player;
import com.newpalm.game.mj.share.MJEventObject;
import com.newpalm.game.mj.share.MJEventRoundResult;
public class MJServer
extends Server {
/**
*@see java.lang.Object#Object()
*/
public MJServer() {
setServerModule(new MJModule());
}
// Query interfaces
public MJModule getMJModule() {
return (MJModule)this.getServerModule();
}
private GameState getGameState() {
return getMJModule().getGameState();
}
// Client commands.
/* (non-Javadoc)
* @see com.inxun.game.framework.Server#startNewGame()
*/
public void onNewGame() {
int left = 4 - countObservers();
for (int i = 0; i < left; i++) {
Player p = new Player("COM" + i, 25000);
MJBotClient clt = new MJBotClient(p);
clt.joinServer(this);
}
setChanged();
notifyObservers(MJEventObject.getNewGameInstance());
}
public void onNewRound() {
runMainCycler();
}
public void onDropACard(Object cid, MJCard card) {
int cltNo = getClientPlayerNo(cid);
if (getMJModule().getCurrentPlayerNo() != cltNo) {
return;
}
getMJModule().getCardModule().dropCard(cltNo, card);
}
public void onPassSignal(Object cid) {
int playerNo = getClientPlayerNo(cid);
getMJModule().setPassResult(playerNo, MJEventObject.getPassInstance());
}
public void onEatWithPair(Object cid, MJCard card, MJCard[] pair) {
int playerNo = getClientPlayerNo(cid);
MJEventEat eeat = new MJEventEat(card, pair);
getMJModule().setPassResult(playerNo, eeat);
}
public void onPeng(Object cid, MJCard card) {
int playerNo = getClientPlayerNo(cid);
MJEventObject epeng = MJEventObject.getPengInstance(card);
getMJModule().setPassResult(playerNo, epeng);
}
public void onGang(Object cid, MJCard card) {
int playerNo = getClientPlayerNo(cid);
MJEventObject egang = MJEventObject.getGangInstance(card);
getMJModule().setPassResult(playerNo, egang);
}
public void onAnGang(Object cid, MJCard card) {
int playerNo = getClientPlayerNo(cid);
MJEventObject egang = MJEventObject.getAnGangInstance(card);
getMJModule().setPassResult(playerNo, egang);
}
public void onHu(Object cid) {
int playerNo = getClientPlayerNo(cid);
int bankNo = getMJModule().getBankerNo();
MJEventRoundResult ehu = MJEventRoundResult.getHuInstance();
ehu.setWinnerNo(playerNo);
int[] jetons = ehu.getJetons();
int jetonwin = 0;
for (int i = 0; i < jetons.length; i++) {
if (i != playerNo) {
jetons[i] = -1000;
if (i == bankNo) {
jetons[i] += -1000;
}
if (bankNo == playerNo) {
jetons[i] *= 2;
}
jetonwin += ( -jetons[i]);
}
}
jetons[playerNo] = jetonwin;
ehu.setJetons(jetons);
String winner = getMJModule().getOnlineClient(playerNo).getPlayer().getName();
String str = winner + " WIN!\n\n";
for (int i = 0; i < 4; i++) {
str += getMJModule().getOnlineClient(i).getPlayer().getName();
str += ": " + jetons[i] + "\n";
}
ehu.setDescription(str);
getMJModule().setPassResult(playerNo, ehu);
}
// Private method
private void runMainCycler() {
// goes round after round
while (true) {
int bankerNo = getMJModule().getBankerNo();
bankerNo = (bankerNo + 1) % 4;
getMJModule().getGameState().setBankerSeatNo(bankerNo);
getMJModule().getCardModule().sendInitialCards(bankerNo);
getMJModule().getCardModule().setCurrentPlayerNo(bankerNo);
getMJModule().getCardModule().setLastPlayerNo(bankerNo);
setChanged();
notifyObservers(MJEventObject.getNewRoundInstance());
MJEventRoundResult rt = runPlayCycler();
for (int i = 0; i < 4; i++) {
Player p = getMJModule().getOnlineClient(i).getPlayer();
p.setJeton(p.getJeton() + rt.getJetons()[i]);
}
setChanged();
notifyObservers(rt);
try {
Thread.sleep(3000);
}
catch (InterruptedException e) {
System.err.println(e);
}
}
}
/**
* 处理出牌逻辑,主循环是
* 1、通知当前玩家出牌
* 1.1如果当前玩家胡(自摸),退出循环
* 1.2如果当前玩家暗杠,则跳至3
* 1.3不胡不暗杠,就是舍牌的情况,继续到2
* 2、询问其他玩家,是否要吃、碰、杠、胡(点炮)舍牌
* 3、发下一张牌,返回1
*
* 需要注意的是对notify的处理,一般情况下,接受到Client的指令,需要立即
* 做处理,并推进循环(比如在onDropACard中set CurrentPlayer++)
* 但是,有个很严重的潜在问题:
* 因为是单线程,server-(notify)->client-(command)->server-(notify)->client
* 是顺序执行的,所以会形成多个方法间的递归调用,加上有多个client……
*
* 解决办法是client对server的指令存放在passResult里,但不推进循环,存放
* 结果后立即返回主循环,由主循环负责结果指令,并推进
*
* @return
*/
private MJEventRoundResult runPlayCycler() {
MJEventRoundResult rt = null;
boolean hasMoreCard = true;
int playerNo;
int passResultNo;
MJEventObject passResult;
int lastPlayerNo;
// play -> eat|peng|gang|hu -> play ... loop
while (hasMoreCard) {
playerNo = getMJModule().getCurrentPlayerNo();
getMJModule().clearPassResult();
//因为用单线程,调用会立即返回。
notifyClient(playerNo, MJEventObject.getWaitPlayInstance());
if (getMJModule().getPassResultCount() > 0) {
// hu, zimo, an gang
passResult = getMJModule().getPassResult(playerNo);
if (passResult.getEventId() == MJEventObject.HU) {
return (MJEventRoundResult) passResult;
}
else if (passResult.getEventId() == MJEventObject.AN_GANG) {
MJCard card = (MJCard) passResult.getData();
getMJModule().getCardModule().anGang(playerNo, card);
card =
getMJModule()
.getCardModule()
.fetchNextBoardCardToCurrentPlayer();
if (card == null) {
// hasMoreCard = false;
break;
}
else {
continue;
}
}
}
lastPlayerNo = getMJModule().getLastPlayerNo();
getMJModule().clearPassResult();
//因为用单线程,调用会立即返回。
notifyOtherClientsByOrder(
lastPlayerNo,
MJEventObject.getWaitPassInstance());
// Choose priority result
// getMJModule().getPassResultCount() == 3;
passResultNo =
getMJModule().getPriotityPassNo( (lastPlayerNo + 1) % 4);
passResult =
(passResultNo == -1)
? null
: getMJModule().getPassResult(passResultNo);
if (passResultNo == -1) {
// all pass
playerNo = (playerNo + 1) % 4;
getMJModule().getCardModule().setCurrentPlayerNo(playerNo);
}
else if (passResult.getEventId() == MJEventObject.EAT) {
// eat
MJEventEat eeat = (MJEventEat) passResult;
getMJModule().getCardModule().eatWithPair(
passResultNo,
eeat.getCard(),
eeat.getPair());
getMJModule().getCardModule().setCurrentPlayerNo(passResultNo);
}
else if (passResult.getEventId() == MJEventObject.PENG) {
// peng
MJCard card = (MJCard) passResult.getData();
getMJModule().getCardModule().peng(passResultNo, card);
getMJModule().getCardModule().setCurrentPlayerNo(passResultNo);
}
else if (passResult.getEventId() == MJEventObject.GANG) {
// gang
MJCard card = (MJCard) passResult.getData();
getMJModule().getCardModule().gang(passResultNo, card);
getMJModule().getCardModule().setCurrentPlayerNo(passResultNo);
}
else if (passResult.getEventId() == MJEventObject.HU) {
// hu
return (MJEventRoundResult) passResult;
}
if (passResultNo == -1
|| passResult.getEventId() == MJEventObject.GANG) {
MJCard card =
getMJModule()
.getCardModule()
.fetchNextBoardCardToCurrentPlayer();
if (card == null) {
hasMoreCard = false;
}
}
} // while
return MJEventRoundResult.getDrawInstance();
}
private int getClientPlayerNo(Object cid) {
return getMJModule().getClientPlayerNo(cid);
}
// observable methods
private void notifyClient(int playerNo, Object arg) {
Client clt = getMJModule().getOnlineClient(playerNo);
if (clt != null) {
clt.update(this, arg);
}
}
private void notifyOtherClientsByOrder(int playerNo, Object arg) {
for (int i = playerNo + 1; i < playerNo + 4; i++) {
notifyClient(i % 4, arg);
}
}
public synchronized void addObserver(Observer o) {
if (! (o instanceof MJClient)) {
return;
}
MJClient clt = (MJClient) o;
int playerNo = countObservers();
getMJModule().setOnlineClient(playerNo, clt);
super.addObserver(clt);
setChanged();
notifyObservers(MJEventObject.getNewJoinInstance());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -