lobby-svn Mailing List for Lobby
Brought to you by:
yuranet
You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(9) |
Jun
(3) |
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
|
Feb
(8) |
Mar
(10) |
Apr
(2) |
May
(96) |
Jun
(33) |
Jul
(113) |
Aug
(24) |
Sep
(35) |
Oct
(17) |
Nov
(36) |
Dec
(1) |
2008 |
Jan
(10) |
Feb
|
Mar
(35) |
Apr
(14) |
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(6) |
Aug
(23) |
Sep
(19) |
Oct
(13) |
Nov
(59) |
Dec
(42) |
2013 |
Jan
(7) |
Feb
(10) |
Mar
(29) |
Apr
(10) |
May
(28) |
Jun
(3) |
Jul
(7) |
Aug
(5) |
Sep
|
Oct
|
Nov
|
Dec
(9) |
2014 |
Jan
(7) |
Feb
(1) |
Mar
(11) |
Apr
|
May
|
Jun
|
Jul
(3) |
Aug
(3) |
Sep
|
Oct
|
Nov
(1) |
Dec
(3) |
2015 |
Jan
(10) |
Feb
|
Mar
(5) |
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
(2) |
Oct
(1) |
Nov
(1) |
Dec
(1) |
2016 |
Jan
(2) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
(3) |
Feb
(1) |
Mar
(1) |
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
(3) |
Sep
(7) |
Oct
(4) |
Nov
|
Dec
(16) |
2019 |
Jan
(2) |
Feb
(3) |
Mar
(4) |
Apr
|
May
|
Jun
(2) |
Jul
(2) |
Aug
|
Sep
(3) |
Oct
(8) |
Nov
(3) |
Dec
(6) |
2020 |
Jan
|
Feb
|
Mar
(4) |
Apr
(11) |
May
(12) |
Jun
(12) |
Jul
(8) |
Aug
(10) |
Sep
(3) |
Oct
(11) |
Nov
(7) |
Dec
|
2021 |
Jan
|
Feb
|
Mar
(5) |
Apr
(7) |
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(19) |
Dec
(15) |
2022 |
Jan
(2) |
Feb
(2) |
Mar
|
Apr
|
May
(3) |
Jun
(2) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(2) |
Nov
(1) |
Dec
(3) |
2023 |
Jan
(1) |
Feb
|
Mar
|
Apr
(5) |
May
(4) |
Jun
(4) |
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2024 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
(3) |
2025 |
Jan
|
Feb
(1) |
Mar
(1) |
Apr
(3) |
May
(7) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <yu...@us...> - 2025-05-15 12:11:41
|
Revision: 1059 http://sourceforge.net/p/lobby/code/1059 Author: yuranet Date: 2025-05-15 12:11:38 +0000 (Thu, 15 May 2025) Log Message: ----------- better error text Modified Paths: -------------- trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java trunk/src_server/net/yura/lobby/server/GameLobby.java Modified: trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java =================================================================== --- trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java 2025-05-10 12:30:09 UTC (rev 1058) +++ trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java 2025-05-15 12:11:38 UTC (rev 1059) @@ -118,7 +118,7 @@ saveGameType(makeNewGameType( 5, - "Game of Go", + "Go Blob", null, "net.yura.lobby.client.SimpleTurnBasedClientGame", null, Modified: trunk/src_server/net/yura/lobby/server/GameLobby.java =================================================================== --- trunk/src_server/net/yura/lobby/server/GameLobby.java 2025-05-10 12:30:09 UTC (rev 1058) +++ trunk/src_server/net/yura/lobby/server/GameLobby.java 2025-05-15 12:11:38 UTC (rev 1059) @@ -115,7 +115,7 @@ boolean success = saveToDB(); if (!success) { - Alert.sendAlert("DB", "save fail", database); + Alert.sendAlert("DB", "scheduled save fail", database); } // clean up old private games This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-10 12:30:18
|
Revision: 1058 http://sourceforge.net/p/lobby/code/1058 Author: yuranet Date: 2025-05-10 12:30:09 +0000 (Sat, 10 May 2025) Log Message: ----------- delete LOBBY_GAMEOVER logic Modified Paths: -------------- trunk/src_client/net/yura/lobby/client/AbstractClientGame.java trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java Modified: trunk/src_client/net/yura/lobby/client/AbstractClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/AbstractClientGame.java 2025-05-06 14:36:52 UTC (rev 1057) +++ trunk/src_client/net/yura/lobby/client/AbstractClientGame.java 2025-05-10 12:30:09 UTC (rev 1058) @@ -41,7 +41,7 @@ return lgml; } - abstract void openGame(Game game); + protected abstract void openGame(Game game); public final void openGame(Game game, ChatBox cb, PlayerList pl) { chatbox = cb; @@ -50,7 +50,13 @@ gameUpdate(game); } - abstract void gameUpdated(Game game); + /** + * This is called when the current player changes in the game + * this is NOT called during the turn of a player + * + * This can be used to work out whos turn it is, etc, but all that state is also inside the game itself + */ + protected abstract void gameUpdated(Game game); public final void gameUpdate(Game game) { playerlist.setPlayers(game.getPlayers()); Modified: trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java 2025-05-06 14:36:52 UTC (rev 1057) +++ trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java 2025-05-10 12:30:09 UTC (rev 1058) @@ -37,7 +37,6 @@ protected JButton startButton; - protected boolean needinput; protected boolean paused; protected JProgressBar timer; @@ -84,15 +83,11 @@ public void sendGameMessage(Object message) { - needinput = false; - lgml.sendGameMessage(message); } public final void closeGame() { - needinput=false; - paused=true; - + paused = true; lgml.closeGame(); } @@ -99,9 +94,9 @@ //################################################################### + @Override public final void openGame(Game game) { - needinput=false; - paused=true; + paused = true; if (startButton==null) { @@ -114,7 +109,6 @@ closegameRequested(); } else if (ac.equals("resign")) { - needinput = false; blockInput(); lgml.leave(); } @@ -156,19 +150,15 @@ } } - for (seconds=timer.getMaximum();seconds>0 && !paused;seconds--) { + for (seconds = timer.getMaximum(); seconds > 0 && !paused; seconds--) { timer.setValue(seconds); - timer.setString( String.valueOf(seconds) ); + timer.setString(String.valueOf(seconds)); try { Thread.sleep(1000); } catch(InterruptedException e){} } - if (!paused && needinput) { - //blockInput(); - //sendGameMessage("LOBBY_TIMEOUT"); - } //timer.setValue(0); } //System.out.println("AbstractTurnBasedClientGame-TIMER THREAD DIE"); @@ -179,7 +169,7 @@ } timer.setMinimum(0); - timer.setMaximum( game.getTimeout() ); + timer.setMaximum(game.getTimeout()); chatBoxArea.removeAll(); playerListArea.removeAll(); @@ -190,30 +180,22 @@ startNewGame(game); } + @Override public final void gameMessage(Object obj) { - if ("LOBBY_GAMEOVER".equals(obj)) { - paused = true; + // reset the timer!! + seconds = timer.getMaximum() + 1; // as 1 is subtracted to this number as soon as the loop begins + // we got something for the game, we can unpause the game + // TODO but the game may we over???? we may have just gone to view a already finished game?? + if (paused) { + paused = false; + synchronized(timerThread) { + timerThread.notify(); + } } - else { - // reset the timer!! - seconds = timer.getMaximum() + 1; // as 1 is subtracted to this number as soon as the loop begins - // we got something for the game, we can unpause the game - if (paused) { - paused=false; - synchronized(timerThread) { - timerThread.notify(); - } - } - - newGameMessage(obj); - } + newGameMessage(obj); } - public void gameUpdated(Game game) { - needinput = lgml.whoAmI().equals(game.getWhosTurn()); - } - public void updateButton(boolean amPlayer, boolean space) { String action; String text; Modified: trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java 2025-05-06 14:36:52 UTC (rev 1057) +++ trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java 2025-05-10 12:30:09 UTC (rev 1058) @@ -23,6 +23,8 @@ */ public class SimpleTurnBasedClientGame extends AbstractTurnBasedClientGame { + private static final int NUM_PLAYERS = 2; + @Override public Icon getIcon(String options, Component comp) { return null; @@ -37,7 +39,7 @@ public Game newGameDialog(Frame parent, String options, String myname) { String value = JOptionPane.showInputDialog(parent, "new game name:", myname + " game"); if (value != null) { - return new Game(value, null, 2, 100000); + return new Game(value, null, NUM_PLAYERS, 100000); } return null; } @@ -45,6 +47,7 @@ private JFrame gameWindow; private JTextArea dataArea; private JButton sendButton; + private Game thisGame; @Override public void startNewGame(Game game) { @@ -94,10 +97,15 @@ byte[] payload = (byte[]) object; String text = new String(payload, StandardCharsets.UTF_8); dataArea.setText(text); + + // This is called the very first time the game is loaded, and also for each move + // by defualt the timer is started, but this game may be over + pauseTimerIfGameOver(); } @Override public void gameUpdated(Game game) { + thisGame = game; String me = lgml.whoAmI(); boolean myTurn = me.equals(game.getWhosTurn()); sendButton.setEnabled(myTurn); @@ -106,8 +114,21 @@ // TODO in the real world we may need to check other things // e.g. can we resign, maybe we already lost the game? updateButton(game.hasPlayer(me), false); + + pauseTimerIfGameOver(); } + /** + * normally info about if the game is finished would come from the state of the game + * but in this example the state of the game is just a byte[] so we get the info from here + */ + private void pauseTimerIfGameOver() { + // if someone has resigned, we want to stop the timer as the game is over + if (thisGame.getWhosTurn() == null || thisGame.getNumOfPlayers() < NUM_PLAYERS) { + paused = true; + } + } + @Override public void closegameRequested() { gameWindow.setVisible(false); Modified: trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java =================================================================== --- trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java 2025-05-06 14:36:52 UTC (rev 1057) +++ trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java 2025-05-10 12:30:09 UTC (rev 1058) @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; +import net.yura.lobby.model.Game; /** * adapter for games that use a java serialised object to send the full game @@ -14,6 +15,7 @@ public abstract void gameObject(Object message); public abstract void gameString(String message); + @Override public final void newGameMessage(Object obj) { if (obj instanceof String) { @@ -38,7 +40,13 @@ } } else { - throw new IllegalArgumentException("unknown object "+obj); + throw new IllegalArgumentException("unknown object " + obj); } } + + @Override + public void gameUpdated(Game game) { + // dont care, we do not use any info from this game object + // as we have much more accurate info inside the actual game + } } Modified: trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-06 14:36:52 UTC (rev 1057) +++ trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-10 12:30:09 UTC (rev 1058) @@ -59,9 +59,6 @@ killFuture(); whoiwantinputfrom = null; finished = true; - // TODO this is prob not needed here, move to TurnBasedGame - listoner.messageFromGame("LOBBY_GAMEOVER", spectators); // stops the timeout clock on the client, IF it has been implemented - listoner.sendChatroomMessage("Game over! " + winner + " has won!"); return listoner.gameFinished(winner); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-06 14:37:09
|
Revision: 1057 http://sourceforge.net/p/lobby/code/1057 Author: yuranet Date: 2025-05-06 14:36:52 +0000 (Tue, 06 May 2025) Log Message: ----------- pick first item Modified Paths: -------------- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java Modified: trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2025-05-05 21:31:02 UTC (rev 1056) +++ trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2025-05-06 14:36:52 UTC (rev 1057) @@ -1588,7 +1588,7 @@ DefaultMutableTreeNode gtNode = new DefaultMutableTreeNode(gt); root.add(gtNode); - if (gt.equals(current) || list.size() == 1) { + if (gt.equals(current) || c == 0) { found = new TreePath(gtNode.getPath()); } //System.out.println("Added: "+gt.toString()+" to the game types"); @@ -1597,7 +1597,7 @@ DefaultTreeModel gameTypesModel = new DefaultTreeModel(root); gameTypes.setModel(gameTypesModel); - if (found!=null) { + if (found != null) { gameTypes.setSelectionPath(found); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-05 21:31:19
|
Revision: 1056 http://sourceforge.net/p/lobby/code/1056 Author: yuranet Date: 2025-05-05 21:31:02 +0000 (Mon, 05 May 2025) Log Message: ----------- allow null options, not hurting anyone Modified Paths: -------------- trunk/src_server/net/yura/lobby/database/GameRoom.java Modified: trunk/src_server/net/yura/lobby/database/GameRoom.java =================================================================== --- trunk/src_server/net/yura/lobby/database/GameRoom.java 2025-05-05 12:10:33 UTC (rev 1055) +++ trunk/src_server/net/yura/lobby/database/GameRoom.java 2025-05-05 21:31:02 UTC (rev 1056) @@ -108,7 +108,7 @@ /** * current longest game options is 164 for long map name */ - @Column(name="options", nullable=false, length=200) + @Column(name="options", nullable=true, length=200) public String getOptions() { return game.getOptions(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-05 12:10:50
|
Revision: 1055 http://sourceforge.net/p/lobby/code/1055 Author: yuranet Date: 2025-05-05 12:10:33 +0000 (Mon, 05 May 2025) Log Message: ----------- ClientLogicTurnBasedGame added Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java trunk/src_server/net/yura/lobby/server/TurnBasedGame.java Added Paths: ----------- trunk/src_server/net/yura/lobby/server/ClientLogicTurnBasedGame.java Modified: trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-05 11:43:17 UTC (rev 1054) +++ trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-05 12:10:33 UTC (rev 1055) @@ -145,7 +145,6 @@ objectFromPlayer(username, object); } - // TODO should be synchronized with something? @Override public final void midgameLogin(String oldser,String newuser) { midgamePlayerLogin(oldser, newuser); @@ -168,7 +167,7 @@ } @Override - public void destroyServerGame() { + public final void destroyServerGame() { killFuture(); destroyGame(); } Added: trunk/src_server/net/yura/lobby/server/ClientLogicTurnBasedGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/ClientLogicTurnBasedGame.java (rev 0) +++ trunk/src_server/net/yura/lobby/server/ClientLogicTurnBasedGame.java 2025-05-05 12:10:33 UTC (rev 1055) @@ -0,0 +1,123 @@ +package net.yura.lobby.server; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * A very simple turn based game where the entire state of the game is sent as a byte[] + * + * player1 ready, player2 ready (depending on who goes first, either play 2 also takes a turn or its passed to player1) + * + */ +public class ClientLogicTurnBasedGame extends AbstractTurnBasedServerGame { + + List<String> players; + byte[] gameState; + + @Override + public void startGame(String[] players) { + this.players = new ArrayList(Arrays.asList(players)); + gameState = new byte[0]; + getInputFromClient(players[0]); + } + + @Override + public void loadGame(byte[] gameData) { + gameState = gameData; + // TODO how do we know this list of players? + // TODO or whos turn it is? + } + + @Override + public byte[] saveGameState() { + // TODO maybe also save players and currentPlayer so it can be all restored + return gameState; + } + + @Override + public void clientHasJoined(LobbySession session) { + listoner.messageFromGame(gameState, Collections.singleton(session)); + } + + @Override + public void setOptions(String startGameOptions) { + // we do not need this, the client will create the game object from the options + } + + @Override + public boolean isSupportedClient(LobbySession session) { + // its up to the client for force an update if it recieves data object it does not support + return true; + } + + @Override + public void destroyGame() { + // nothing to do as all logic on the client + } + + @Override + public void objectFromPlayer(String player, Object message) { + if (!player.equals(whoiwantinputfrom)) { + throw new IllegalArgumentException("not your turn " + player); + } + + // TurnBasedMultiplayerClient finishMatch + if ("finishMatch".equals(message)) { // TODO we need to know the winner + gameFinished("TODO"); + return; + } + + gameState = (byte[])message; + listoner.messageFromGame(gameState, spectators); + moveToNextPlayer(); + } + + private void moveToNextPlayer() { + int index = players.indexOf(whoiwantinputfrom); + if (index < 0) { + throw new IllegalStateException("current player not in " + players); + } + index++; + if (index == players.size()) { + index = 0; + } + getInputFromClient(players.get(index)); + } + + @Override + public void playerJoins(String player) { + //players.add(player); + throw new UnsupportedOperationException(); + } + + @Override + public boolean playerResigns(String player) { + players.remove(player); + if (players.size() == 1) { + // if the current player has resigned + //if (whoiwantinputfrom == null) { + // no point in calling this as gameFinished will set current player to null anyway + //getInputFromClient(players.get(0)); + //} + return gameFinished(players.get(0)); + } + if (players.isEmpty()) { + // TODO this is kind of meaninless, as the game is already over by now + return listoner.gameFinished(null); + } + return false; + } + + @Override + public void midgamePlayerLogin(String oldPlayer, String newPlayer) { + players.set(players.indexOf(oldPlayer), newPlayer); + } + + @Override + public void playerTimedOut(String username) { + listoner.sendChatroomMessage(username + " has timed out and has been resigned from the game."); + listoner.resignPlayer(username); + } +} Modified: trunk/src_server/net/yura/lobby/server/TurnBasedGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-05-05 11:43:17 UTC (rev 1054) +++ trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-05-05 12:10:33 UTC (rev 1055) @@ -30,7 +30,7 @@ @Override public abstract void startGame(String[] players); @Override public abstract void loadGame(byte[] gameData); - public abstract void renamePlayer(String oldser,String newuser); + public abstract void renamePlayer(String oldser, String newuser); //comunication public abstract void clientHasJoined(String username); @@ -43,15 +43,15 @@ public final void playerTimedOut(String username) { // when MAX_SKIPS turns have been skipped, the player is resigned - int skip = skips.get(username)==null?1:skips.get(username)+1; + int skip = skips.get(username) == null ? 1 : skips.get(username) + 1; skips.put(username, skip); if (skip >= MAX_SKIPS) { - listoner.sendChatroomMessage(username+" has timed out "+MAX_SKIPS+" times and has been resigned from the game."); + listoner.sendChatroomMessage(username + " has timed out " + MAX_SKIPS + " times and has been resigned from the game."); listoner.resignPlayer(username); } else { - listoner.sendChatroomMessage(username+" has timed out on their turn"); + listoner.sendChatroomMessage(username + " has timed out on their turn"); doBasicGo(username); } } @@ -58,7 +58,7 @@ private Collection<LobbySession> usernameToLobbySessionArray(String username) { List<LobbySession> sessions = new ArrayList(); - for (LobbySession session:spectators) { + for (LobbySession session : spectators) { if (username.equals(session.getUsername())) { sessions.add(session); } @@ -67,7 +67,7 @@ } public final void sendStringToClient(String a, String username) { - listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); + listoner.messageFromGame(a, usernameToLobbySessionArray(username)); } public final void sendStringToAllClient(String a) { @@ -75,11 +75,11 @@ } public final void sendObjectToClient(Serializable a,String username) { - listoner.messageFromGame( serializableToByteArray(a) , usernameToLobbySessionArray(username) ); + listoner.messageFromGame(serializableToByteArray(a), usernameToLobbySessionArray(username)); } public final void sendObjectToAllClient(Serializable a) { - listoner.messageFromGame( serializableToByteArray(a), spectators ); + listoner.messageFromGame(serializableToByteArray(a), spectators); } private static byte[] serializableToByteArray(Serializable a) { @@ -107,13 +107,14 @@ skips.put(username, 0); // if someone does something reset skips counter stringFromPlayer(username, (String) obj); } - + + // TODO should be synchronized with something? @Override public final void midgamePlayerLogin(String oldser, String newuser) { renamePlayer(oldser, newuser); Integer skip = skips.remove(oldser); - if (skip!=null) { + if (skip != null) { skips.put(newuser, skip); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-05 11:43:35
|
Revision: 1054 http://sourceforge.net/p/lobby/code/1054 Author: yuranet Date: 2025-05-05 11:43:17 +0000 (Mon, 05 May 2025) Log Message: ----------- move more methods to TurnBasedGame Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java trunk/src_server/net/yura/lobby/server/TurnBasedGame.java Modified: trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-04 22:57:21 UTC (rev 1053) +++ trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-05 11:43:17 UTC (rev 1054) @@ -16,14 +16,6 @@ */ package net.yura.lobby.server; -import java.io.ByteArrayOutputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -34,8 +26,6 @@ * @author Yura */ public abstract class AbstractTurnBasedServerGame extends AbstractServerGame { - - public static final int MAX_SKIPS = 5; public static final PausableScheduledThreadPoolExecutor scheduler = new PausableScheduledThreadPoolExecutor(1); static { @@ -45,33 +35,21 @@ private Future future; - protected boolean finished,startGameCalled; - String whoiwantinputfrom; + protected boolean finished, startGameCalled; + protected String whoiwantinputfrom; /** * in seconds */ protected int timeout; - - Map<String,Integer> skips = new HashMap(); - - // ################################### abstract methods #################################### - // life cycle of a game - @Override public abstract void startGame(String[] players); - @Override public abstract void loadGame(byte[] gameData); public abstract void destroyGame(); public abstract void playerJoins(String username); public abstract boolean playerResigns(String username); - public abstract void renamePlayer(String oldser,String newuser); - - //comunication - public abstract void clientHasJoined(String username); - public abstract void stringFromPlayer(String username, String message); - - // called by this if the player has left or they have timmed out - public abstract void doBasicGo(String username); + public abstract void midgamePlayerLogin(String oldser, String newuser); + public abstract void playerTimedOut(String username); + public abstract void objectFromPlayer(String username, Object obj); // ################################### methods callable by the game #################################### @@ -80,10 +58,11 @@ public final boolean gameFinished(String winner) { killFuture(); whoiwantinputfrom = null; - finished=true; - sendStringToAllClient("LOBBY_GAMEOVER"); // stops the timeout clock on the client, IF it has been implemented + finished = true; + // TODO this is prob not needed here, move to TurnBasedGame + listoner.messageFromGame("LOBBY_GAMEOVER", spectators); // stops the timeout clock on the client, IF it has been implemented - listoner.sendChatroomMessage("Game over! "+winner+" has won!"); + listoner.sendChatroomMessage("Game over! " + winner + " has won!"); return listoner.gameFinished(winner); } @@ -99,22 +78,10 @@ public void run() { final String username = whoiwantinputfrom; try { - if (username==null) { + if (username == null) { throw new IllegalStateException("username is null"); } - - // when MAX_SKIPS turns have been skipped, the player is resigned - int skip = skips.get(username)==null?1:skips.get(username)+1; - skips.put(username, skip); - - if (skip >= MAX_SKIPS) { - listoner.sendChatroomMessage(username+" has timed out "+MAX_SKIPS+" times and has been resigned from the game."); - listoner.resignPlayer(username); - } - else { - listoner.sendChatroomMessage(username+" has timed out on their turn"); - doBasicGo(username); - } + playerTimedOut(username); } catch(Throwable th) { LobbyLogger.log(id, Level.WARNING, "error in timeout for game: "+id+" for user "+username, th); @@ -137,45 +104,6 @@ listoner.needInputFrom(whoiwantinputfrom); } } - - private Collection<LobbySession> usernameToLobbySessionArray(String username) { - List<LobbySession> sessions = new ArrayList(); - for (LobbySession session:spectators) { - if (username.equals(session.getUsername())) { - sessions.add(session); - } - } - return sessions; - } - - public final void sendStringToClient(String a, String username) { - listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); - } - - public final void sendStringToAllClient(String a) { - listoner.messageFromGame(a, spectators ); - } - - public final void sendObjectToClient(Serializable a,String username) { - listoner.messageFromGame( serializableToByteArray(a) , usernameToLobbySessionArray(username) ); - } - - public final void sendObjectToAllClient(Serializable a) { - listoner.messageFromGame( serializableToByteArray(a), spectators ); - } - - private static byte[] serializableToByteArray(Serializable a) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ObjectOutputStream oout = new ObjectOutputStream(out); - oout.writeObject(a); - oout.flush(); - return out.toByteArray(); - } - catch (Exception ex) { - throw new RuntimeException(ex); - } - } // ################################### implementation of ServerGame #################################### @@ -189,31 +117,24 @@ } @Override - public final void clientHasJoined(LobbySession session) { - // TODO we send game object to every session with this username - // would be better if just sent it to the session we needed to - clientHasJoined(session.getUsername()); - } - - @Override - public boolean playerResigned(String player) { + public final boolean playerResigned(String player) { // TODO what if player clicks resign twice, there is not check if we are already resigned here if (player.equals(whoiwantinputfrom)) { killFuture(); whoiwantinputfrom = null; } - listoner.sendChatroomMessage( player+" has resigned from the game"); + listoner.sendChatroomMessage(player + " has resigned from the game"); // even though a error may happen in the resign, that would lead to us not being resigned // we still have to call the sendChatroomMessage method first, as it will make more sense // in the log (player X resigned, game over) and the game may get deleted by the resign // command, and calling sendChatroomMessage on a deleted game will throw a nullpointer - return playerResigns( player ); // this may lead to the game being deleted (gameFinished called) + return playerResigns(player); // this may lead to the game being deleted (gameFinished called) } @Override - public void playerJoined(String player) { - playerJoins( player ); - listoner.sendChatroomMessage( player+" has joined the game"); + public final void playerJoined(String player) { + playerJoins(player); + listoner.sendChatroomMessage(player + " has joined the game"); } @Override @@ -221,24 +142,19 @@ if (username.equals(whoiwantinputfrom)) { killFuture(); } - skips.put(username, 0); // if someone does something reset skips counter - stringFromPlayer(username, (String)object ); + objectFromPlayer(username, object); } // TODO should be synchronized with something? @Override public final void midgameLogin(String oldser,String newuser) { - renamePlayer( oldser , newuser ); + midgamePlayerLogin(oldser, newuser); - Integer skip = skips.remove(oldser); - if (skip!=null) { - skips.put(newuser, skip); - } if (oldser.equals(whoiwantinputfrom)) { whoiwantinputfrom = newuser; } - listoner.sendChatroomMessage(oldser+" has logged in as "+newuser); + listoner.sendChatroomMessage(oldser + " has logged in as " + newuser); } @Override @@ -259,7 +175,7 @@ void killFuture() { Future f = future; - if (f!=null && !f.isDone() && !f.isCancelled()) { + if (f != null && !f.isDone() && !f.isCancelled()) { f.cancel(true); } } Modified: trunk/src_server/net/yura/lobby/server/TurnBasedGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-05-04 22:57:21 UTC (rev 1053) +++ trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-05-05 11:43:17 UTC (rev 1054) @@ -1,5 +1,14 @@ package net.yura.lobby.server; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * This class extends AbstractTurnBasedServerGame to add extra functionality * - send string and java serialised object @@ -11,4 +20,101 @@ */ public abstract class TurnBasedGame extends AbstractTurnBasedServerGame { + public static final int MAX_SKIPS = 5; + + Map<String,Integer> skips = new HashMap(); + + // ################################### abstract methods #################################### + + // life cycle of a game + @Override public abstract void startGame(String[] players); + @Override public abstract void loadGame(byte[] gameData); + + public abstract void renamePlayer(String oldser,String newuser); + + //comunication + public abstract void clientHasJoined(String username); + public abstract void stringFromPlayer(String username, String message); + + // called by this if the player has left or they have timmed out + public abstract void doBasicGo(String username); + + @Override + public final void playerTimedOut(String username) { + + // when MAX_SKIPS turns have been skipped, the player is resigned + int skip = skips.get(username)==null?1:skips.get(username)+1; + skips.put(username, skip); + + if (skip >= MAX_SKIPS) { + listoner.sendChatroomMessage(username+" has timed out "+MAX_SKIPS+" times and has been resigned from the game."); + listoner.resignPlayer(username); + } + else { + listoner.sendChatroomMessage(username+" has timed out on their turn"); + doBasicGo(username); + } + } + + private Collection<LobbySession> usernameToLobbySessionArray(String username) { + List<LobbySession> sessions = new ArrayList(); + for (LobbySession session:spectators) { + if (username.equals(session.getUsername())) { + sessions.add(session); + } + } + return sessions; + } + + public final void sendStringToClient(String a, String username) { + listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); + } + + public final void sendStringToAllClient(String a) { + listoner.messageFromGame(a, spectators ); + } + + public final void sendObjectToClient(Serializable a,String username) { + listoner.messageFromGame( serializableToByteArray(a) , usernameToLobbySessionArray(username) ); + } + + public final void sendObjectToAllClient(Serializable a) { + listoner.messageFromGame( serializableToByteArray(a), spectators ); + } + + private static byte[] serializableToByteArray(Serializable a) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(out); + oout.writeObject(a); + oout.flush(); + return out.toByteArray(); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public final void clientHasJoined(LobbySession session) { + // TODO we send game object to every session with this username + // would be better if just sent it to the session we needed to + clientHasJoined(session.getUsername()); + } + + @Override + public final void objectFromPlayer(String username, Object obj) { + skips.put(username, 0); // if someone does something reset skips counter + stringFromPlayer(username, (String) obj); + } + + @Override + public final void midgamePlayerLogin(String oldser, String newuser) { + renamePlayer(oldser, newuser); + + Integer skip = skips.remove(oldser); + if (skip!=null) { + skips.put(newuser, skip); + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-05-04 22:57:38
|
Revision: 1053 http://sourceforge.net/p/lobby/code/1053 Author: yuranet Date: 2025-05-04 22:57:21 +0000 (Sun, 04 May 2025) Log Message: ----------- AbstractTurnBasedServerGame Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/AbstractServerGame.java trunk/src_server/net/yura/lobby/server/GameLobby.java trunk/src_server/net/yura/lobby/server/TurnBasedGame.java Added Paths: ----------- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java Modified: trunk/src_server/net/yura/lobby/server/AbstractServerGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractServerGame.java 2025-04-26 16:20:37 UTC (rev 1052) +++ trunk/src_server/net/yura/lobby/server/AbstractServerGame.java 2025-05-04 22:57:21 UTC (rev 1053) @@ -7,8 +7,9 @@ * @author yura */ public abstract class AbstractServerGame implements ServerGame { - + protected int id; + protected String startGameOptions; protected ServerGameListener listoner; protected Collection<LobbySession> spectators = new ConcurrentSkipListSet(); @@ -21,8 +22,13 @@ public int getId() { return id; } - + @Override + public void setOptions(String startGameOptions) { + this.startGameOptions = startGameOptions; + } + + @Override public final void addServerGameListener(ServerGameListener l) { listoner = l; } Copied: trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java (from rev 1052, trunk/src_server/net/yura/lobby/server/TurnBasedGame.java) =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java (rev 0) +++ trunk/src_server/net/yura/lobby/server/AbstractTurnBasedServerGame.java 2025-05-04 22:57:21 UTC (rev 1053) @@ -0,0 +1,266 @@ +/* + (C) 2007-2025 yura.net + This file is part of Lobby. + + Lobby is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License + + Lobby is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +package net.yura.lobby.server; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import net.yura.util.PausableScheduledThreadPoolExecutor; + +/** + * @author Yura + */ +public abstract class AbstractTurnBasedServerGame extends AbstractServerGame { + + public static final int MAX_SKIPS = 5; + + public static final PausableScheduledThreadPoolExecutor scheduler = new PausableScheduledThreadPoolExecutor(1); + static { + // JAVA 7 ONLY + scheduler.setRemoveOnCancelPolicy(true); + } + + private Future future; + + protected boolean finished,startGameCalled; + String whoiwantinputfrom; + + /** + * in seconds + */ + protected int timeout; + + Map<String,Integer> skips = new HashMap(); + + // ################################### abstract methods #################################### + + // life cycle of a game + @Override public abstract void startGame(String[] players); + @Override public abstract void loadGame(byte[] gameData); + public abstract void destroyGame(); + + public abstract void playerJoins(String username); + public abstract boolean playerResigns(String username); + public abstract void renamePlayer(String oldser,String newuser); + + //comunication + public abstract void clientHasJoined(String username); + public abstract void stringFromPlayer(String username, String message); + + // called by this if the player has left or they have timmed out + public abstract void doBasicGo(String username); + + // ################################### methods callable by the game #################################### + + // called by the game when it comes to an end + // set things up for another game + public final boolean gameFinished(String winner) { + killFuture(); + whoiwantinputfrom = null; + finished=true; + sendStringToAllClient("LOBBY_GAMEOVER"); // stops the timeout clock on the client, IF it has been implemented + + listoner.sendChatroomMessage("Game over! "+winner+" has won!"); + return listoner.gameFinished(winner); + } + + public final void getInputFromClient(String username) { + killFuture(); + + String oldPlayer = whoiwantinputfrom; + whoiwantinputfrom = username; + + if (whoiwantinputfrom != null) { + future = scheduler.schedule(new Runnable() { + @Override + public void run() { + final String username = whoiwantinputfrom; + try { + if (username==null) { + throw new IllegalStateException("username is null"); + } + + // when MAX_SKIPS turns have been skipped, the player is resigned + int skip = skips.get(username)==null?1:skips.get(username)+1; + skips.put(username, skip); + + if (skip >= MAX_SKIPS) { + listoner.sendChatroomMessage(username+" has timed out "+MAX_SKIPS+" times and has been resigned from the game."); + listoner.resignPlayer(username); + } + else { + listoner.sendChatroomMessage(username+" has timed out on their turn"); + doBasicGo(username); + } + } + catch(Throwable th) { + LobbyLogger.log(id, Level.WARNING, "error in timeout for game: "+id+" for user "+username, th); + } + } + }, timeout + 10, TimeUnit.SECONDS); // add 10 seconds for bad ping + } + + if (!Objects.equals(oldPlayer, whoiwantinputfrom)) { + + // the first time we need input from a user we know the game has finished setup + // is now started/ready to be opened + if (whoiwantinputfrom != null && !startGameCalled) { + listoner.gameStarted(); + startGameCalled = true; + } + + // if whoiwantinputfrom is null we send it to tell the client + // that we do not need input from any human player + listoner.needInputFrom(whoiwantinputfrom); + } + } + + private Collection<LobbySession> usernameToLobbySessionArray(String username) { + List<LobbySession> sessions = new ArrayList(); + for (LobbySession session:spectators) { + if (username.equals(session.getUsername())) { + sessions.add(session); + } + } + return sessions; + } + + public final void sendStringToClient(String a, String username) { + listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); + } + + public final void sendStringToAllClient(String a) { + listoner.messageFromGame(a, spectators ); + } + + public final void sendObjectToClient(Serializable a,String username) { + listoner.messageFromGame( serializableToByteArray(a) , usernameToLobbySessionArray(username) ); + } + + public final void sendObjectToAllClient(Serializable a) { + listoner.messageFromGame( serializableToByteArray(a), spectators ); + } + + private static byte[] serializableToByteArray(Serializable a) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(out); + oout.writeObject(a); + oout.flush(); + return out.toByteArray(); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // ################################### implementation of ServerGame #################################### + + @Override + public void setTimeout(int seconds) { + this.timeout = seconds; + + if (this.timeout <= 0) { + this.timeout = 60; // a turn based game MUST have a timeout to give players a time to take there turn + } + } + + @Override + public final void clientHasJoined(LobbySession session) { + // TODO we send game object to every session with this username + // would be better if just sent it to the session we needed to + clientHasJoined(session.getUsername()); + } + + @Override + public boolean playerResigned(String player) { + // TODO what if player clicks resign twice, there is not check if we are already resigned here + if (player.equals(whoiwantinputfrom)) { + killFuture(); + whoiwantinputfrom = null; + } + listoner.sendChatroomMessage( player+" has resigned from the game"); + // even though a error may happen in the resign, that would lead to us not being resigned + // we still have to call the sendChatroomMessage method first, as it will make more sense + // in the log (player X resigned, game over) and the game may get deleted by the resign + // command, and calling sendChatroomMessage on a deleted game will throw a nullpointer + return playerResigns( player ); // this may lead to the game being deleted (gameFinished called) + } + + @Override + public void playerJoined(String player) { + playerJoins( player ); + listoner.sendChatroomMessage( player+" has joined the game"); + } + + @Override + public final void messageFromUser(String username, Object object) { + if (username.equals(whoiwantinputfrom)) { + killFuture(); + } + skips.put(username, 0); // if someone does something reset skips counter + stringFromPlayer(username, (String)object ); + } + + // TODO should be synchronized with something? + @Override + public final void midgameLogin(String oldser,String newuser) { + renamePlayer( oldser , newuser ); + + Integer skip = skips.remove(oldser); + if (skip!=null) { + skips.put(newuser, skip); + } + if (oldser.equals(whoiwantinputfrom)) { + whoiwantinputfrom = newuser; + } + + listoner.sendChatroomMessage(oldser+" has logged in as "+newuser); + } + + @Override + public boolean isFinished() { + return finished; + } + + @Override + public String getWhosTurn() { + return whoiwantinputfrom; + } + + @Override + public void destroyServerGame() { + killFuture(); + destroyGame(); + } + + void killFuture() { + Future f = future; + if (f!=null && !f.isDone() && !f.isCancelled()) { + f.cancel(true); + } + } +} Modified: trunk/src_server/net/yura/lobby/server/GameLobby.java =================================================================== --- trunk/src_server/net/yura/lobby/server/GameLobby.java 2025-04-26 16:20:37 UTC (rev 1052) +++ trunk/src_server/net/yura/lobby/server/GameLobby.java 2025-05-04 22:57:21 UTC (rev 1053) @@ -93,9 +93,9 @@ this.database = database; - TurnBasedGame.scheduler.pause(); + AbstractTurnBasedServerGame.scheduler.pause(); loadFromDB(); - TurnBasedGame.scheduler.resume(); + AbstractTurnBasedServerGame.scheduler.resume(); // add shutdown hook only if we manage to create a DB Runtime.getRuntime().addShutdownHook(new Thread() { @@ -1205,7 +1205,7 @@ catch (RuntimeException ex) { StringWriter sw = new StringWriter(); ex.printStackTrace(new PrintWriter(sw)); - Alert.sendAlert("StartGameError", sw.toString(), database); + Alert.sendAlert("StartGameError", sw.toString() + "\nsession: " + session, database); //leaveGame(gameId, username); // there may be other players, we dont want to leave them there removeGame(gameId); Modified: trunk/src_server/net/yura/lobby/server/TurnBasedGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-04-26 16:20:37 UTC (rev 1052) +++ trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-05-04 22:57:21 UTC (rev 1053) @@ -1,273 +1,14 @@ -/* - (C) 2007-2013 yura.net - This file is part of Lobby. - - Lobby is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License - - Lobby is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -package net.yura.lobby.server; - -import java.io.ByteArrayOutputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import net.yura.util.PausableScheduledThreadPoolExecutor; - -/** - * @author Yura - */ -public abstract class TurnBasedGame extends AbstractServerGame { - - public static final int MAX_SKIPS = 5; - - public static final PausableScheduledThreadPoolExecutor scheduler = new PausableScheduledThreadPoolExecutor(1); - static { - // JAVA 7 ONLY - scheduler.setRemoveOnCancelPolicy(true); - } - - private Future future; - - protected boolean finished,startGameCalled; - String whoiwantinputfrom; - - /** - * in seconds - */ - protected int timeout; - - protected String startGameOptions; - - Map<String,Integer> skips = new HashMap(); - - // ################################### abstract methods #################################### - - // life cycle of a game - @Override public abstract void startGame(String[] players); - @Override public abstract void loadGame(byte[] gameData); - public abstract void destroyGame(); - - public abstract void playerJoins(String username); - public abstract boolean playerResigns(String username); - public abstract void renamePlayer(String oldser,String newuser); - - //comunication - public abstract void clientHasJoined(String username); - public abstract void stringFromPlayer(String username, String message); - - // called by this if the player has left or they have timmed out - public abstract void doBasicGo(String username); - - // ################################### methods callable by the game #################################### - - // called by the game when it comes to an end - // set things up for another game - public final boolean gameFinished(String winner) { - killFuture(); - whoiwantinputfrom = null; - finished=true; - sendStringToAllClient("LOBBY_GAMEOVER"); // stops the timeout clock on the client, IF it has been implemented - - listoner.sendChatroomMessage("Game over! "+winner+" has won!"); - return listoner.gameFinished(winner); - } - - public final void getInputFromClient(String username) { - killFuture(); - - String oldPlayer = whoiwantinputfrom; - whoiwantinputfrom = username; - - if (whoiwantinputfrom != null) { - future = scheduler.schedule(new Runnable() { - @Override - public void run() { - final String username = whoiwantinputfrom; - try { - if (username==null) { - throw new IllegalStateException("username is null"); - } - - // when MAX_SKIPS turns have been skipped, the player is resigned - int skip = skips.get(username)==null?1:skips.get(username)+1; - skips.put(username, skip); - - if (skip >= MAX_SKIPS) { - listoner.sendChatroomMessage(username+" has timed out "+MAX_SKIPS+" times and has been resigned from the game."); - listoner.resignPlayer(username); - } - else { - listoner.sendChatroomMessage(username+" has timed out on their turn"); - doBasicGo(username); - } - } - catch(Throwable th) { - LobbyLogger.log(id, Level.WARNING, "error in timeout for game: "+id+" for user "+username, th); - } - } - }, timeout + 10, TimeUnit.SECONDS); // add 10 seconds for bad ping - } - - if (!Objects.equals(oldPlayer, whoiwantinputfrom)) { - - // the first time we need input from a user we know the game has finished setup - // is now started/ready to be opened - if (whoiwantinputfrom != null && !startGameCalled) { - listoner.gameStarted(); - startGameCalled = true; - } - - // if whoiwantinputfrom is null we send it to tell the client - // that we do not need input from any human player - listoner.needInputFrom(whoiwantinputfrom); - } - } - - private Collection<LobbySession> usernameToLobbySessionArray(String username) { - List<LobbySession> sessions = new ArrayList(); - for (LobbySession session:spectators) { - if (username.equals(session.getUsername())) { - sessions.add(session); - } - } - return sessions; - } - - public final void sendStringToClient(String a, String username) { - listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); - } - - public final void sendStringToAllClient(String a) { - listoner.messageFromGame(a, spectators ); - } - - public final void sendObjectToClient(Serializable a,String username) { - listoner.messageFromGame( serializableToByteArray(a) , usernameToLobbySessionArray(username) ); - } - - public final void sendObjectToAllClient(Serializable a) { - listoner.messageFromGame( serializableToByteArray(a), spectators ); - } - - private static byte[] serializableToByteArray(Serializable a) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ObjectOutputStream oout = new ObjectOutputStream(out); - oout.writeObject(a); - oout.flush(); - return out.toByteArray(); - } - catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - // ################################### implementation of ServerGame #################################### - - @Override - public void setTimeout(int seconds) { - this.timeout = seconds; - - if (this.timeout <= 0) { - this.timeout = 60; // a turn based game MUST have a timeout to give players a time to take there turn - } - } - - @Override - public void setOptions(String startGameOptions) { - this.startGameOptions = startGameOptions; - } - - @Override - public final void clientHasJoined(LobbySession session) { - // TODO we send game object to every session with this username - // would be better if just sent it to the session we needed to - clientHasJoined(session.getUsername()); - } - - @Override - public boolean playerResigned(String player) { - // TODO what if player clicks resign twice, there is not check if we are already resigned here - if (player.equals(whoiwantinputfrom)) { - killFuture(); - whoiwantinputfrom = null; - } - listoner.sendChatroomMessage( player+" has resigned from the game"); - // even though a error may happen in the resign, that would lead to us not being resigned - // we still have to call the sendChatroomMessage method first, as it will make more sense - // in the log (player X resigned, game over) and the game may get deleted by the resign - // command, and calling sendChatroomMessage on a deleted game will throw a nullpointer - return playerResigns( player ); // this may lead to the game being deleted (gameFinished called) - } - - @Override - public void playerJoined(String player) { - playerJoins( player ); - listoner.sendChatroomMessage( player+" has joined the game"); - } - - @Override - public final void messageFromUser(String username, Object object) { - if (username.equals(whoiwantinputfrom)) { - killFuture(); - } - skips.put(username, 0); // if someone does something reset skips counter - stringFromPlayer(username, (String)object ); - } - - // TODO should be synchronized with something? - @Override - public final void midgameLogin(String oldser,String newuser) { - renamePlayer( oldser , newuser ); - - Integer skip = skips.remove(oldser); - if (skip!=null) { - skips.put(newuser, skip); - } - if (oldser.equals(whoiwantinputfrom)) { - whoiwantinputfrom = newuser; - } - - listoner.sendChatroomMessage(oldser+" has logged in as "+newuser); - } - - @Override - public boolean isFinished() { - return finished; - } - - @Override - public String getWhosTurn() { - return whoiwantinputfrom; - } - - @Override - public void destroyServerGame() { - killFuture(); - destroyGame(); - } - - void killFuture() { - Future f = future; - if (f!=null && !f.isDone() && !f.isCancelled()) { - f.cancel(true); - } - } -} +package net.yura.lobby.server; + +/** + * This class extends AbstractTurnBasedServerGame to add extra functionality + * - send string and java serialised object + * - treat incoming objects as string + * - keep track of missed turns and handle doing a basic move when turns are missed + * - resign player when player misses 5 ({@link #MAX_SKIPS}) turns + * + * @author Yura + */ +public abstract class TurnBasedGame extends AbstractTurnBasedServerGame { + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-04-26 16:20:55
|
Revision: 1052 http://sourceforge.net/p/lobby/code/1052 Author: yuranet Date: 2025-04-26 16:20:37 +0000 (Sat, 26 Apr 2025) Log Message: ----------- test update Modified Paths: -------------- trunk/test/net/yura/lobby/server/ServerTest.java Modified: trunk/test/net/yura/lobby/server/ServerTest.java =================================================================== --- trunk/test/net/yura/lobby/server/ServerTest.java 2025-04-26 16:01:13 UTC (rev 1051) +++ trunk/test/net/yura/lobby/server/ServerTest.java 2025-04-26 16:20:37 UTC (rev 1052) @@ -3,9 +3,11 @@ import net.yura.lobby.util.LobbyConnection; import java.lang.management.ManagementFactory; import java.util.List; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import javax.management.JMX; import javax.management.ObjectName; import net.yura.lobby.client.Connection; @@ -229,7 +231,7 @@ LobbyConnection mycom2 = new LobbyConnection(id2); Player user2 = mycom2.connect(server, port).get(); GameType type2 = getMockGameType(mycom2.getGameTypes().get()); - Game game2 = mycom2.getGames(type2).take(); + Game game2 = take(mycom2.getGames(type2)); game2 = mycom2.joinGame(game2.getId(), null).get(); // both players go into the game @@ -285,7 +287,7 @@ mycom1.flagUser(user2.getName()); GameType type2 = getMockGameType(mycom2.getGameTypes().get()); - Game game2 = mycom2.getGames(type2).take(); + Game game2 = take(mycom2.getGames(type2)); try { mycom2.joinGame(game2.getId(), null).get(); @@ -342,7 +344,7 @@ LobbyConnection mycom2 = new LobbyConnection(id2); mycom2.connect(server, port).get(); List<GameType> gameTypes2 = mycom2.getGameTypes().get(); - Game game2 = mycom2.getGames(getMockGameType(gameTypes2)).take(); + Game game2 = take(mycom2.getGames(getMockGameType(gameTypes2))); Game newGame2 = mycom2.joinGame(game2.getId(), null).get(); Assert.assertEquals(2, newGame2.getPlayers().size()); @@ -373,7 +375,7 @@ LobbyConnection mycom2 = new LobbyConnection(id2); mycom2.connect(server, port).get(); try { - mycom2.joinGame(mycom2.getGames(getMockGameType(mycom2.getGameTypes().get())).take().getId(), "abracadabra").get(); + mycom2.joinGame(take(mycom2.getGames(getMockGameType(mycom2.getGameTypes().get()))).getId(), "abracadabra").get(); Assert.fail("should not allow join"); } catch (ExecutionException ex) { @@ -420,7 +422,7 @@ System.out.println("expected error: " + ex); } - int removedGame = mycom1.removedGame().take(); + int removedGame = take(mycom1.removedGame()); Assert.assertEquals(1, removedGame); mycom1.disconnect(); @@ -501,4 +503,12 @@ static void sleep(int time) { try { Thread.sleep(time); }catch(Exception ex) {} } + + static <T> T take(BlockingQueue<T> queue) throws InterruptedException { + T result = queue.poll(10, TimeUnit.SECONDS); + if (result == null) { + throw new RuntimeException("unable to take next item from queue " + queue); + } + return result; + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-04-26 16:01:30
|
Revision: 1051 http://sourceforge.net/p/lobby/code/1051 Author: yuranet Date: 2025-04-26 16:01:13 +0000 (Sat, 26 Apr 2025) Log Message: ----------- new turn based server part 1 Modified Paths: -------------- trunk/lib/Grasshopper.jar trunk/src/net/yura/lobby/client/Connection.java trunk/src_blackjack/net/yura/blackjack/client/BlackJackClient.java trunk/src_server/net/yura/lobby/database/GameTypeRoom.java trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java trunk/src_server/net/yura/lobby/service/Alert.java Modified: trunk/lib/Grasshopper.jar =================================================================== (Binary files differ) Modified: trunk/src/net/yura/lobby/client/Connection.java =================================================================== --- trunk/src/net/yura/lobby/client/Connection.java 2025-04-26 15:49:11 UTC (rev 1050) +++ trunk/src/net/yura/lobby/client/Connection.java 2025-04-26 16:01:13 UTC (rev 1051) @@ -60,7 +60,7 @@ void leaveGame(int game_id); void playGame(int gameId); - void sendGameMessage(int game_id,Object message); + void sendGameMessage(int game_id, Object message); void closeGame(int game_id); void delGame(int gameId); Modified: trunk/src_blackjack/net/yura/blackjack/client/BlackJackClient.java =================================================================== --- trunk/src_blackjack/net/yura/blackjack/client/BlackJackClient.java 2025-04-26 15:49:11 UTC (rev 1050) +++ trunk/src_blackjack/net/yura/blackjack/client/BlackJackClient.java 2025-04-26 16:01:13 UTC (rev 1051) @@ -193,7 +193,7 @@ gameframe.addWindowListener( new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { - closegame(); + closegameRequested(); } } ); @@ -213,9 +213,9 @@ } // this NEEDS to call leaveGame(); - public void closegame() { + public void closegameRequested() { gameframe.setVisible(false); - leaveGame(); + closeGame(); } public void gameString(String message) { Modified: trunk/src_server/net/yura/lobby/database/GameTypeRoom.java =================================================================== --- trunk/src_server/net/yura/lobby/database/GameTypeRoom.java 2025-04-26 15:49:11 UTC (rev 1050) +++ trunk/src_server/net/yura/lobby/database/GameTypeRoom.java 2025-04-26 16:01:13 UTC (rev 1051) @@ -82,7 +82,7 @@ return names==null||names.length==0?null:names[0]; } public void setServerJar(String serverJar) { - serverGameType.setJarNames( new String[]{serverJar} ); + serverGameType.setJarNames(serverJar == null ? new String[0] : new String[]{serverJar} ); } @Column(name="client_jar", nullable=false, length=45) @@ -91,7 +91,7 @@ return names==null||names.length==0?null:names[0]; } public void setClientJar(String clientJar) { - clientGameType.setJarNames( new String[]{clientJar} ); + clientGameType.setJarNames(clientJar == null ? new String[0] : new String[]{clientJar} ); } @Column(name="server_class", nullable=false, length=100) Modified: trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java =================================================================== --- trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java 2025-04-26 15:49:11 UTC (rev 1050) +++ trunk/src_server/net/yura/lobby/database/impl/MemoryDatabase.java 2025-04-26 16:01:13 UTC (rev 1051) @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import net.yura.lobby.database.Database; @@ -35,27 +36,27 @@ private Map<String,User> registeredPeople; // <Username,User> final Map<String,User> clientUUIDtoInt; // <UUID,Client> private Map<Integer,GameTypeRoom> gameTypes; - private boolean transaction; + private Set<Thread> transactions = ConcurrentHashMap.newKeySet(); private AtomicInteger gameIdCounter = new AtomicInteger(); @Override public void startTransaction() { - if (transaction) { + if (transactions.contains(Thread.currentThread())) { throw new IllegalStateException("already in transaction"); } - transaction = true; + transactions.add(Thread.currentThread()); } @Override public boolean endTransaction() { - if (!transaction) { + if (!transactions.contains(Thread.currentThread())) { throw new IllegalStateException("not in transaction"); } - transaction = false; + transactions.remove(Thread.currentThread()); return true; } private void checkTransaction() { - if (!transaction) { + if (!transactions.contains(Thread.currentThread())) { throw new IllegalStateException("not in transaction"); } } @@ -113,8 +114,18 @@ "" )); - saveGameType(makeDominationGameType()); + saveGameType(makeDominationGameType()); // id:4 + saveGameType(makeNewGameType( + 5, + "Game of Go", + null, + "net.yura.lobby.client.SimpleTurnBasedClientGame", + null, + "net.yura.lobby.server.ClientLogicTurnBasedGame", + "" + )); + saveUser(makeNewUser("test-guest", Player.PLAYER_GUEST)); saveUser(makeNewUser("test-normal", Player.PLAYER_NORMAL)); saveUser(makeNewUser("test-subscriber", Player.PLAYER_SUBSCRIBER)); Modified: trunk/src_server/net/yura/lobby/service/Alert.java =================================================================== --- trunk/src_server/net/yura/lobby/service/Alert.java 2025-04-26 15:49:11 UTC (rev 1050) +++ trunk/src_server/net/yura/lobby/service/Alert.java 2025-04-26 16:01:13 UTC (rev 1051) @@ -6,7 +6,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Level; -import net.yura.grasshopper.BugSubmitter; +import net.yura.grasshopper.submitter.BugSubmitter; import net.yura.lobby.database.Database; import net.yura.lobby.server.LobbyLogger; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-04-26 15:49:29
|
Revision: 1050 http://sourceforge.net/p/lobby/code/1050 Author: yuranet Date: 2025-04-26 15:49:11 +0000 (Sat, 26 Apr 2025) Log Message: ----------- new client lib to make writing clients simpler Modified Paths: -------------- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java trunk/src_client/net/yura/lobby/client/LobbyGame.java trunk/src_client/net/yura/lobby/client/LobbyGameChatListener.java trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java Added Paths: ----------- trunk/src_client/net/yura/lobby/client/AbstractClientGame.java trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java Added: trunk/src_client/net/yura/lobby/client/AbstractClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/AbstractClientGame.java (rev 0) +++ trunk/src_client/net/yura/lobby/client/AbstractClientGame.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -0,0 +1,71 @@ +/* + (C) 2025 yura.net + This file is part of Lobby. + + Lobby is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License + + Lobby is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +package net.yura.lobby.client; + +import net.yura.lobby.model.Game; + +/** + * @author yura + */ +public abstract class AbstractClientGame implements LobbyGame { + + protected LobbyGameChatListener lgml; + protected ChatBox chatbox; + protected PlayerList playerlist; + + public void addLobbyGameMoveListener(LobbyGameChatListener lgl) { + lgml = lgl; + } + + public void removeLobbyGameMoveListener(LobbyGameChatListener lgl) { + if (lgml == lgl) { + lgml = null; + } + } + + public LobbyGameChatListener getLobbyGameMoveListener() { + return lgml; + } + + abstract void openGame(Game game); + + public final void openGame(Game game, ChatBox cb, PlayerList pl) { + chatbox = cb; + playerlist = pl; + openGame(game); + gameUpdate(game); + } + + abstract void gameUpdated(Game game); + + public final void gameUpdate(Game game) { + playerlist.setPlayers(game.getPlayers()); + + // TODO when opened for the first time, could this be old info? + playerlist.setCurrentPlayer(game.getWhosTurn()); + + gameUpdated(game); + } + + public PlayerList getPlayerList() { + return playerlist; + } + + public ChatBox getChatBox() { + return chatbox; + } +} Added: trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java (rev 0) +++ trunk/src_client/net/yura/lobby/client/AbstractTurnBasedClientGame.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -0,0 +1,235 @@ +/* + (C) 2025 yura.net + This file is part of Lobby. + + Lobby is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License + + Lobby is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +package net.yura.lobby.client; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import net.yura.lobby.model.Game; + +/** + * @author yura + */ +public abstract class AbstractTurnBasedClientGame extends AbstractClientGame { + + private int seconds; + private Thread timerThread; + + protected JPanel chatBoxArea; + protected JPanel playerListArea; + + protected JButton startButton; + + protected boolean needinput; + protected boolean paused; + protected JProgressBar timer; + + /** + * If any resources are needed to open the game, they must be downloaded before this method returns + */ + public abstract void startNewGame(Game game); + + public abstract void newGameMessage(Object message); + + /** + * if the player clicks Resign, there game input must be blocked + * + * // TODO better name, should be onResigned() + */ + public abstract void blockInput(); + + /** + * will first trigger whatever internal game mechanism to close down the game, + * + * then the implementation MUST call {@link #closeGame()} + * @see #closeGame() + */ + @Override + public abstract void closegameRequested(); + + //################################################################### + // implimintation of LobbyGame + //################################################################### + + // these are not actually needed here + + //public abstract ImageIcon getIcon(String options); + + //public abstract GameSetup newGameDialog(Frame parent, String options,String myname); + + //public abstract void gameObject(Object object); + + + //################################################################### + // methods it can use + //################################################################### + + + + public void sendGameMessage(Object message) { + needinput = false; + + lgml.sendGameMessage(message); + } + + public final void closeGame() { + needinput=false; + paused=true; + + lgml.closeGame(); + } + + + //################################################################### + + public final void openGame(Game game) { + needinput=false; + paused=true; + + if (startButton==null) { + + startButton = new JButton(); + startButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + String ac = ae.getActionCommand(); + if (ac.equals("close")) { + // this NEEDS to call closeGame(); + closegameRequested(); + } + else if (ac.equals("resign")) { + needinput = false; + blockInput(); + lgml.leave(); + } + else if (ac.equals("join")) { + lgml.join(); + } + else { + System.err.println("AbstractTurnBasedClientGame unknown command "+ac); + } + } + } + ); + + chatBoxArea = new JPanel(); + playerListArea = new JPanel(); + + chatBoxArea.setLayout( new BorderLayout() ); + playerListArea.setLayout( new BorderLayout() ); + + timer = new JProgressBar(); + timer.setStringPainted(true); + timer.setString(""); + + // this thread is started when there is a game, and will die if there is no game or its finished + timerThread = new Thread("Timer-Thread") { + + public void run() { + + while (true) { + + if (paused) { + + timer.setValue(0); + timer.setString(""); + + synchronized(this) { + try { wait(); } + catch(InterruptedException e) {} + } + } + + for (seconds=timer.getMaximum();seconds>0 && !paused;seconds--) { + + timer.setValue(seconds); + timer.setString( String.valueOf(seconds) ); + + try { Thread.sleep(1000); } + catch(InterruptedException e){} + } + + if (!paused && needinput) { + //blockInput(); + //sendGameMessage("LOBBY_TIMEOUT"); + } + //timer.setValue(0); + } + //System.out.println("AbstractTurnBasedClientGame-TIMER THREAD DIE"); + } + }; + + timerThread.start(); + } + + timer.setMinimum(0); + timer.setMaximum( game.getTimeout() ); + + chatBoxArea.removeAll(); + playerListArea.removeAll(); + + chatBoxArea.add(chatbox); + playerListArea.add(playerlist); + + startNewGame(game); + } + + public final void gameMessage(Object obj) { + if ("LOBBY_GAMEOVER".equals(obj)) { + paused = true; + } + else { + // reset the timer!! + seconds = timer.getMaximum() + 1; // as 1 is subtracted to this number as soon as the loop begins + + // we got something for the game, we can unpause the game + if (paused) { + paused=false; + synchronized(timerThread) { + timerThread.notify(); + } + } + + newGameMessage(obj); + } + } + + public void gameUpdated(Game game) { + needinput = lgml.whoAmI().equals(game.getWhosTurn()); + } + + public void updateButton(boolean amPlayer, boolean space) { + String action; + String text; + if (amPlayer) { + action = "resign"; + text = "Resign"; + } + else if (space) { + action = "join"; + text = "Join"; + } + else { + action = "close"; + text = "Close"; + } + startButton.setActionCommand(action); + startButton.setText(text); + } +} Modified: trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2025-03-15 19:24:48 UTC (rev 1049) +++ trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -717,7 +717,7 @@ private LobbyGameChatListener makeListener(final int id) { return new LobbyGameChatListener() { - public void sendGameMessage(String message) { + public void sendGameMessage(Object message) { LobbyClientGUI.this.sendGameMessage(id, message); } public void sendChat(String text) { @@ -775,7 +775,12 @@ } public static void openURL(URL url) throws Exception { - System.out.println("OPEN URL: "+url); + if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.BROWSE)) { + java.awt.Desktop.getDesktop().browse(url.toURI()); + } + else { + System.out.println("unable to OPEN URL: " + url); + } } public void paintComponent(Graphics g) { @@ -1280,7 +1285,7 @@ showConnectingDialog(true); for (Iterator games = new HashSet(activegames.values()).iterator();games.hasNext();) { // TODO then will in tern call leavegame, is this ok? - ((LobbyGame)games.next()).closegame(); + ((LobbyGame)games.next()).closegameRequested(); } } @@ -1463,8 +1468,8 @@ // ######################### interface LobbyGameChatListener // ######################################################## - public void sendGameMessage(int gameid,String message) { - mycom.sendGameMessage(gameid,message); + public void sendGameMessage(int gameid, Object message) { + mycom.sendGameMessage(gameid, message); } /** Modified: trunk/src_client/net/yura/lobby/client/LobbyGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyGame.java 2025-03-15 19:24:48 UTC (rev 1049) +++ trunk/src_client/net/yura/lobby/client/LobbyGame.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -60,5 +60,5 @@ * this method needs to call closeGame() on LobbyGameChatListener * @see LobbyGameChatListener#closeGame() */ - void closegame(); + void closegameRequested(); } Modified: trunk/src_client/net/yura/lobby/client/LobbyGameChatListener.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyGameChatListener.java 2025-03-15 19:24:48 UTC (rev 1049) +++ trunk/src_client/net/yura/lobby/client/LobbyGameChatListener.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -22,7 +22,7 @@ public interface LobbyGameChatListener { void join(); - void sendGameMessage(String message); + void sendGameMessage(Object message); void leave(); void closeGame(); void sendChat(String text); Added: trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java =================================================================== --- trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java (rev 0) +++ trunk/src_client/net/yura/lobby/client/SimpleTurnBasedClientGame.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -0,0 +1,127 @@ +package net.yura.lobby.client; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Font; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.nio.charset.StandardCharsets; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import net.yura.lobby.model.Game; + +/** + * @author yura + */ +public class SimpleTurnBasedClientGame extends AbstractTurnBasedClientGame { + + @Override + public Icon getIcon(String options, Component comp) { + return null; + } + + @Override + public String getGameDescription(String options) { + return "test game"; + } + + @Override + public Game newGameDialog(Frame parent, String options, String myname) { + String value = JOptionPane.showInputDialog(parent, "new game name:", myname + " game"); + if (value != null) { + return new Game(value, null, 2, 100000); + } + return null; + } + + private JFrame gameWindow; + private JTextArea dataArea; + private JButton sendButton; + + @Override + public void startNewGame(Game game) { + gameWindow = new JFrame(game.getName()); + gameWindow.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closegameRequested(); + } + }); + + JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + split.setTopComponent(playerlist); + split.setBottomComponent(chatbox); + gameWindow.add(split, BorderLayout.EAST); + + dataArea = new JTextArea(); + dataArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, dataArea.getFont().getSize())); + dataArea.setColumns(30); + dataArea.setRows(20); + gameWindow.add(dataArea); + + sendButton = new JButton("Take Turn"); + sendButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + byte[] payload = dataArea.getText().getBytes(StandardCharsets.UTF_8); + lgml.sendGameMessage(payload); + } + }); + + JPanel buttonPanel = new JPanel(); + buttonPanel.add(sendButton); + buttonPanel.add(startButton); + + gameWindow.add(buttonPanel, BorderLayout.SOUTH); + + gameWindow.add(timer, BorderLayout.NORTH); + + gameWindow.pack(); + gameWindow.setLocationRelativeTo(null); + gameWindow.setVisible(true); + } + + @Override + public void newGameMessage(Object object) { + byte[] payload = (byte[]) object; + String text = new String(payload, StandardCharsets.UTF_8); + dataArea.setText(text); + } + + @Override + public void gameUpdated(Game game) { + String me = lgml.whoAmI(); + boolean myTurn = me.equals(game.getWhosTurn()); + sendButton.setEnabled(myTurn); + dataArea.setEnabled(myTurn); + + // TODO in the real world we may need to check other things + // e.g. can we resign, maybe we already lost the game? + updateButton(game.hasPlayer(me), false); + } + + @Override + public void closegameRequested() { + gameWindow.setVisible(false); + gameWindow.dispose(); + gameWindow = null; + closeGame(); + } + + /** + * blocks my input immediately upon resigning on the client, does not wait for server to respond + */ + @Override + public void blockInput() { + sendButton.setEnabled(false); + dataArea.setEnabled(false); + } +} Modified: trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java =================================================================== --- trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java 2025-03-15 19:24:48 UTC (rev 1049) +++ trunk/src_client/net/yura/lobby/client/TurnBasedAdapter.java 2025-04-26 15:49:11 UTC (rev 1050) @@ -1,317 +1,44 @@ -/* - (C) 2007 yura.net - This file is part of Lobby. - - Lobby is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License - - Lobby is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - package net.yura.lobby.client; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JProgressBar; -import java.awt.event.ActionListener; -import java.awt.event.ActionEvent; -import java.awt.BorderLayout; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; -import net.yura.lobby.model.Game; -public abstract class TurnBasedAdapter implements LobbyGame { +/** + * adapter for games that use a java serialised object to send the full game + * and then use strings to send any subsequent commands for the game + */ +public abstract class TurnBasedAdapter extends AbstractTurnBasedClientGame { - private int seconds; - private Thread timerThread; + public abstract void gameObject(Object message); + public abstract void gameString(String message); - protected ChatBox chatbox; - protected PlayerList playerlist; + public final void newGameMessage(Object obj) { - protected JPanel chatBoxArea; - protected JPanel playerListArea; + if (obj instanceof String) { + String message = (String)obj; - protected LobbyGameChatListener lgml; + gameString(message); + } + else if (obj instanceof byte[]) { - protected JButton startButton; - - protected boolean needinput; - protected boolean paused; - protected JProgressBar timer; - - /** - * If any resources are needed to open the game, they must be downloaded before this method returns - */ - public abstract void startNewGame(Game game); - - public abstract void gameObject(Object message); - public abstract void gameString(String message); - - /** - * if the player clicks Resign, there game input must be blocked - */ - public abstract void blockInput(); - - /** - * the implementation has to call leaveGame() - * @see #leaveGame() - */ - public abstract void closegame(); - - //################################################################### - // implimintation of LobbyGame - //################################################################### - - // these are not actually needed here - - //public abstract ImageIcon getIcon(String options); - - //public abstract GameSetup newGameDialog(Frame parent, String options,String myname); - - //public abstract void gameObject(Object object); - - - //################################################################### - // methods it can use - //################################################################### - - - - public void sendGameMessage(String message) { - needinput = false; - - lgml.sendGameMessage(message); - } - - public void leaveGame() { - needinput=false; - paused=true; - - lgml.closeGame(); - } - - - //################################################################### - - - - public void openGame(Game game,ChatBox cb,PlayerList pl) { - - chatbox = cb; - playerlist = pl; - - needinput=false; - paused=true; - - if (startButton==null) { - - startButton = new JButton(); - - startButton.addActionListener( - - new ActionListener() { - - public void actionPerformed(ActionEvent ae) { - String ac = ae.getActionCommand(); - - if (ac.equals("close")) { - - // this NEEDS to call leaveGame(); - closegame(); - } - else if (ac.equals("resign")) { - - needinput = false; - blockInput(); - - lgml.leave(); - - } - else if (ac.equals("join")) { - - lgml.join(); - } - else { - System.err.println("TurnBasedAdapter unknown command "+ac); - } - } - } - ); - - - chatBoxArea = new JPanel(); - playerListArea = new JPanel(); - - chatBoxArea.setLayout( new BorderLayout() ); - playerListArea.setLayout( new BorderLayout() ); - - - - timer = new JProgressBar(); - timer.setStringPainted(true); - timer.setString(""); - - - // this thread is started when there is a game, and will die if there is no game or its finished - timerThread = new Thread("Timer-Thread") { - - public void run() { - - while (true) { - - if (paused) { - - timer.setValue(0); - timer.setString(""); - - synchronized(this) { - try { wait(); } - catch(InterruptedException e) {} - } - } - - for (seconds=timer.getMaximum();seconds>0 && !paused;seconds--) { - - timer.setValue(seconds); - timer.setString( String.valueOf(seconds) ); - - try { Thread.sleep(1000); } - catch(InterruptedException e){} - } - - if (!paused && needinput) { - //blockInput(); - //sendGameMessage("LOBBY_TIMEOUT"); - } - //timer.setValue(0); - } - //System.out.println("LOBBY-RISK-TIMER THREAD DIE"); - } - }; - - timerThread.start(); - } - - timer.setMinimum(0); - timer.setMaximum( game.getTimeout() ); - - chatBoxArea.removeAll(); - playerListArea.removeAll(); - - chatBoxArea.add(chatbox); - playerListArea.add(playerlist); - - startNewGame(game); - - gameUpdate(game); - } - - - public void gameMessage(Object obj) { - - if (obj instanceof String) { - String message = (String)obj; - - if (message.equals("LOBBY_GAMEOVER")) { - paused=true; - } - else { - // reset the timer!! - seconds = timer.getMaximum()+1; // as 1 is subtracted to this number as soon as the loop begins - - // we got something for the game, we can unpause the game - if (paused) { - paused=false; - synchronized(timerThread) { - timerThread.notify(); - } - } - - gameString(message); - } + try { + ByteArrayInputStream in = new ByteArrayInputStream( (byte[])obj ); + ObjectInputStream oin = new ObjectInputStream(in) { + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + return Class.forName(desc.getName(), true, TurnBasedAdapter.this.getClass().getClassLoader()); + } + }; + Object object = oin.readObject(); + gameObject(object); } - else if (obj instanceof byte[]) { - - // we got something for the game, we can unpause the game - if (paused) { - paused=false; - synchronized(timerThread) { - timerThread.notify(); - } - } - - try { - ByteArrayInputStream in = new ByteArrayInputStream( (byte[])obj ); - ObjectInputStream oin = new ObjectInputStream(in) { - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - return Class.forName(desc.getName(),true,TurnBasedAdapter.this.getClass().getClassLoader()); - } - }; - Object object = oin.readObject(); - gameObject(object); - } - catch (Exception ex) { - throw new RuntimeException(ex); - } + catch (Exception ex) { + throw new RuntimeException(ex); } - else { - throw new IllegalArgumentException("unknown object "+obj); - } - } - - public void gameUpdate(Game game) { - playerlist.setPlayers(game.getPlayers()); - playerlist.setCurrentPlayer(game.getWhosTurn() ); - needinput = lgml.whoAmI().equals(game.getWhosTurn()); } - - public void updateButton(boolean amPlayer,boolean space) { - String action; - String text; - if (amPlayer) { - action = "resign"; - text = "Resign"; - } - else if ( space ) { - action = "join"; - text = "Join"; - } - else { - action = "close"; - text = "Close"; - } - startButton.setActionCommand(action); - startButton.setText(text); - } - - public PlayerList getPlayerList() { - return playerlist; - } - - public ChatBox getChatBox() { - return chatbox; - } - - public void addLobbyGameMoveListener(LobbyGameChatListener lgl) { - lgml = lgl; - } - - public void removeLobbyGameMoveListener(LobbyGameChatListener lgl) { - if (lgml==lgl) { - lgml = null; - } - } - - public LobbyGameChatListener getLobbyGameMoveListener() { - return lgml; - } + else { + throw new IllegalArgumentException("unknown object "+obj); + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-03-15 19:24:55
|
Revision: 1049 http://sourceforge.net/p/lobby/code/1049 Author: yuranet Date: 2025-03-15 19:24:48 +0000 (Sat, 15 Mar 2025) Log Message: ----------- AbstractServerGame added to make creating new game easier Modified Paths: -------------- trunk/lobby.proto trunk/src_server/net/yura/lobby/server/ServerGameListener.java trunk/src_server/net/yura/lobby/server/TurnBasedGame.java Added Paths: ----------- trunk/src_server/net/yura/lobby/server/AbstractServerGame.java Modified: trunk/lobby.proto =================================================================== --- trunk/lobby.proto 2025-02-09 11:58:32 UTC (rev 1048) +++ trunk/lobby.proto 2025-03-15 19:24:48 UTC (rev 1049) @@ -78,7 +78,7 @@ REQUEST_JOIN_GAME = 19; // {game_id=id,magic_word=String} REQUEST_LEAVE_GAME = 20; // {game_id=id} - // @deprecated (was used for GooglePlay private games + // @deprecated (was used for GooglePlay private games) COMMAND_GAME_STARTED = 27; // {game_id=id} // play a game Added: trunk/src_server/net/yura/lobby/server/AbstractServerGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/AbstractServerGame.java (rev 0) +++ trunk/src_server/net/yura/lobby/server/AbstractServerGame.java 2025-03-15 19:24:48 UTC (rev 1049) @@ -0,0 +1,67 @@ +package net.yura.lobby.server; + +import java.util.Collection; +import java.util.concurrent.ConcurrentSkipListSet; + +/** + * @author yura + */ +public abstract class AbstractServerGame implements ServerGame { + + protected int id; + protected ServerGameListener listoner; + protected Collection<LobbySession> spectators = new ConcurrentSkipListSet(); + + @Override + public void setId(int id) { + this.id = id; + } + + @Override + public int getId() { + return id; + } + + @Override + public final void addServerGameListener(ServerGameListener l) { + listoner = l; + } + + @Override + public final void removeServerGameListener(ServerGameListener l) { + if (l.equals(listoner)) { + listoner = null; + } + } + + @Override + public Collection<LobbySession> getAllClients() { + return spectators; + } + + @Override + public final void clientEntered(final LobbySession session) { + String username = session.getUsername(); + if (username == null) { + throw new IllegalArgumentException("username is null"); + } + + // we tell everyone currently in the game this person is joining + listoner.sendChatroomMessage(username + " has entered the game"); + + // we add this new player as a spectator to make sure we do not miss any messages + // from the game that can happen between clientHasJoined() and spectators.add() + spectators.add(session); + + // signal that we need to send the game info to this session + clientHasJoined(session); + } + + public abstract void clientHasJoined(LobbySession session); + + @Override + public final void clientLeaves(LobbySession username) { + spectators.remove(username); + listoner.sendChatroomMessage(username.getUsername() + " has left the game"); + } +} Modified: trunk/src_server/net/yura/lobby/server/ServerGameListener.java =================================================================== --- trunk/src_server/net/yura/lobby/server/ServerGameListener.java 2025-02-09 11:58:32 UTC (rev 1048) +++ trunk/src_server/net/yura/lobby/server/ServerGameListener.java 2025-03-15 19:24:48 UTC (rev 1049) @@ -31,7 +31,12 @@ */ void needInputFrom(String whoiwantinputfrom); void resignPlayer(String username); + + /** + * @deprecated (was used for GooglePlay private games) + */ void gameStarted(); + /** * @return true if this game has been deleted */ Modified: trunk/src_server/net/yura/lobby/server/TurnBasedGame.java =================================================================== --- trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-02-09 11:58:32 UTC (rev 1048) +++ trunk/src_server/net/yura/lobby/server/TurnBasedGame.java 2025-03-15 19:24:48 UTC (rev 1049) @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -34,7 +33,7 @@ /** * @author Yura */ -public abstract class TurnBasedGame implements ServerGame { +public abstract class TurnBasedGame extends AbstractServerGame { public static final int MAX_SKIPS = 5; @@ -45,15 +44,9 @@ } private Future future; - - private ServerGameListener listoner; - private Collection<LobbySession> spectators = new ConcurrentSkipListSet(); - protected boolean finished,startGameCalled; String whoiwantinputfrom; - - protected int id; /** * in seconds @@ -78,7 +71,7 @@ //comunication public abstract void clientHasJoined(String username); public abstract void stringFromPlayer(String username, String message); - + // called by this if the player has left or they have timmed out public abstract void doBasicGo(String username); @@ -156,7 +149,7 @@ } return sessions; } - + public final void sendStringToClient(String a, String username) { listoner.messageFromGame(a, usernameToLobbySessionArray(username) ); } @@ -189,16 +182,6 @@ // ################################### implementation of ServerGame #################################### @Override - public void setId(int id) { - this.id = id; - } - - @Override - public int getId() { - return id; - } - - @Override public void setTimeout(int seconds) { this.timeout = seconds; @@ -206,7 +189,7 @@ this.timeout = 60; // a turn based game MUST have a timeout to give players a time to take there turn } } - + @Override public void setOptions(String startGameOptions) { this.startGameOptions = startGameOptions; @@ -213,64 +196,13 @@ } @Override - public final void addServerGameListener(ServerGameListener l) { - listoner = l; - } - - @Override - public final void removeServerGameListener(ServerGameListener l) { - if( listoner.equals(l)) { - listoner = null; - } - } - - @Override - public Collection<LobbySession> getAllClients() { - return spectators; + public final void clientHasJoined(LobbySession session) { + // TODO we send game object to every session with this username + // would be better if just sent it to the session we needed to + clientHasJoined(session.getUsername()); } - - @Override - public final void clientEntered(final LobbySession session) { - String username = session.getUsername(); - if (username == null) { - throw new IllegalArgumentException("username is null"); - } - // we tell everyone currently in the game this person is joining - listoner.sendChatroomMessage(username + " has entered the game"); - - // we add this new player as a spectator to make sure we do not miss any messages - // from the game that can happen between clientHasJoined() and spectators.add() - spectators.add(session); - - // this is here so if the clientHasJoined sends anything to the client - // the game object is already created on the client and ready -// new Thread() { -// -// public void run() { -// -// try { Thread.sleep(1000); } -// catch(InterruptedException e){} -// - // TODO we send game object to every session with this username - // would be better if just sent it to the session we needed to - clientHasJoined(username); -// -// } -// -// }.start(); - - } - - - // game will finish if someone leaves @Override - public final void clientLeaves(LobbySession username) { - spectators.remove(username); - listoner.sendChatroomMessage(username.getUsername()+" has left the game"); - } - - @Override public boolean playerResigned(String player) { // TODO what if player clicks resign twice, there is not check if we are already resigned here if (player.equals(whoiwantinputfrom)) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2025-02-09 11:58:34
|
Revision: 1048 http://sourceforge.net/p/lobby/code/1048 Author: yuranet Date: 2025-02-09 11:58:32 +0000 (Sun, 09 Feb 2025) Log Message: ----------- more loggin for android Modified Paths: -------------- trunk/src/net/yura/lobby/client/LobbyCom.java trunk/src_server/net/yura/lobby/service/ApplePushNotificationService.java Modified: trunk/src/net/yura/lobby/client/LobbyCom.java =================================================================== --- trunk/src/net/yura/lobby/client/LobbyCom.java 2024-12-23 16:44:36 UTC (rev 1047) +++ trunk/src/net/yura/lobby/client/LobbyCom.java 2025-02-09 11:58:32 UTC (rev 1048) @@ -237,7 +237,15 @@ byte[][] parts = new byte[bytes.length / MAX_DATA_SIZE + (bytes.length % MAX_DATA_SIZE == 0 ? 0 : 1)][]; for (int c = 0; c < parts.length; c++) { int position = c * MAX_DATA_SIZE; - parts[c] = encrypt.doFinal(bytes, position, (position + MAX_DATA_SIZE > bytes.length) ? bytes.length % MAX_DATA_SIZE : MAX_DATA_SIZE); + int length = (position + MAX_DATA_SIZE > bytes.length) ? bytes.length % MAX_DATA_SIZE : MAX_DATA_SIZE; + try { + parts[c] = encrypt.doFinal(bytes, position, length); + } + catch (Exception ex) { + // for unknown reasons, android seems to in very rare occasions throw an error here + logger.log(Level.WARNING, "unable to doFinal input=" + bytes.length + " inputOffset=" + position + " inputLen=" + length + " " + ex); + throw ex; + } } return parts; } Modified: trunk/src_server/net/yura/lobby/service/ApplePushNotificationService.java =================================================================== --- trunk/src_server/net/yura/lobby/service/ApplePushNotificationService.java 2024-12-23 16:44:36 UTC (rev 1047) +++ trunk/src_server/net/yura/lobby/service/ApplePushNotificationService.java 2025-02-09 11:58:32 UTC (rev 1048) @@ -11,7 +11,6 @@ import java.io.File; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import net.yura.lobby.client.PushLobbyClient; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2024-12-23 16:44:38
|
Revision: 1047 http://sourceforge.net/p/lobby/code/1047 Author: yuranet Date: 2024-12-23 16:44:36 +0000 (Mon, 23 Dec 2024) Log Message: ----------- do not call disconnected while in interrupted state Modified Paths: -------------- trunk/src/net/yura/lobby/client/TcpClient.java trunk/test/net/yura/lobby/client/LobbyComTest.java Modified: trunk/src/net/yura/lobby/client/TcpClient.java =================================================================== --- trunk/src/net/yura/lobby/client/TcpClient.java 2024-12-15 16:07:28 UTC (rev 1046) +++ trunk/src/net/yura/lobby/client/TcpClient.java 2024-12-23 16:44:36 UTC (rev 1047) @@ -82,7 +82,9 @@ public void stop() { LOG.info("stopping event loop"); try { - thread.interrupt(); + synchronized (thread) { + thread.interrupt(); + } } catch (Exception ex) { LOG.log(Level.WARNING,"can not interrupt thread "+thread, ex); @@ -198,7 +200,22 @@ onConnectionError(e); } finally { connected.set(false); - onDisconnected(); // TODO this can accedently throw/clear the InterruptedException + + synchronized (thread) { + boolean interrupted = Thread.interrupted(); + try { + onDisconnected(); // this can accidentally (throwing InterruptedException) clear the interrupt state of the thread + } + catch (Exception ex) { + LOG.log(Level.WARNING, "Exception in onDisconnected", ex); + } + finally { + if (interrupted) { + thread.interrupt(); + } + } + } + ((Buffer)writeBuf).clear(); ((Buffer)readBuf).clear(); close(channel); Modified: trunk/test/net/yura/lobby/client/LobbyComTest.java =================================================================== --- trunk/test/net/yura/lobby/client/LobbyComTest.java 2024-12-15 16:07:28 UTC (rev 1046) +++ trunk/test/net/yura/lobby/client/LobbyComTest.java 2024-12-23 16:44:36 UTC (rev 1047) @@ -15,25 +15,30 @@ Server server = new Server(port, new MemoryDatabase()); server.start(); - + Connection mycom = new LobbyCom("123-456-789", "JUnit-Test", "1"); mycom.addEventListener(new LobbyConnection.LoggingClient() { + @Override public void disconnected() { - //Thread.interrupted(); + super.disconnected(); + // test something random happening in the client code + // reset the interrupt status of the thread + Thread.interrupted(); } }); - + port = server.getPort(); mycom.connect("localhost", port); Thread.sleep(1000); // wait for connection - + Assert.assertEquals(1, server.getClientCount()); - + Assert.assertTrue(Thread.getAllStackTraces().keySet().stream().filter(thread -> thread.getName().contains("TCP-Client")).findFirst().isPresent()); + mycom.disconnect(); Thread.sleep(1000); // wait for disconnection - + Assert.assertEquals(0, server.getClientCount()); // check that the mycom client really is dead Set<Thread> threads = Thread.getAllStackTraces().keySet(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2024-12-15 16:07:29
|
Revision: 1046 http://sourceforge.net/p/lobby/code/1046 Author: yuranet Date: 2024-12-15 16:07:28 +0000 (Sun, 15 Dec 2024) Log Message: ----------- better test fail when no mysql running Modified Paths: -------------- trunk/test/net/yura/lobby/database/impl/DatabaseTest.java Modified: trunk/test/net/yura/lobby/database/impl/DatabaseTest.java =================================================================== --- trunk/test/net/yura/lobby/database/impl/DatabaseTest.java 2024-12-15 15:45:18 UTC (rev 1045) +++ trunk/test/net/yura/lobby/database/impl/DatabaseTest.java 2024-12-15 16:07:28 UTC (rev 1046) @@ -13,6 +13,9 @@ import org.junit.Test; /** + * This test requires mysql to be running locally with details from persistence.xml + * TODO make this test not require that, maybe use Testcontainers + * * @author Yura Mamyrin */ public class DatabaseTest { @@ -46,14 +49,16 @@ //NucleusContext nucCtx = ((JPAEntityManagerFactory)database.emf).getNucleusContext(); //((SchemaAwareStoreManager)nucCtx.getStoreManager()).deleteSchema(null, null); - try { - ManagementFactory.getPlatformMBeanServer().unregisterMBean(new ObjectName("net.yura.lobby:type=JPADatabase")); + if (database != null) { + try { + ManagementFactory.getPlatformMBeanServer().unregisterMBean(new ObjectName("net.yura.lobby:type=JPADatabase")); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + + database = null; } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - - database = null; } @Test This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2024-12-15 15:45:20
|
Revision: 1045 http://sourceforge.net/p/lobby/code/1045 Author: yuranet Date: 2024-12-15 15:45:18 +0000 (Sun, 15 Dec 2024) Log Message: ----------- allow dynamic ports in tests Modified Paths: -------------- trunk/src/net/yura/lobby/client/TcpClient.java trunk/src_server/net/yura/lobby/netty/Server.java trunk/test/net/yura/lobby/util/LobbyConnection.java Added Paths: ----------- trunk/test/net/yura/lobby/client/ trunk/test/net/yura/lobby/client/LobbyComTest.java Modified: trunk/src/net/yura/lobby/client/TcpClient.java =================================================================== --- trunk/src/net/yura/lobby/client/TcpClient.java 2024-08-27 20:39:35 UTC (rev 1044) +++ trunk/src/net/yura/lobby/client/TcpClient.java 2024-12-15 15:45:18 UTC (rev 1045) @@ -44,8 +44,8 @@ private long reconnectInterval = INITIAL_RECONNECT_INTERVAL; - private ByteBuffer readBuf = ByteBuffer.allocateDirect(READ_BUFFER_SIZE); // 1Mb (1,048,576 Bytes) - private ByteBuffer writeBuf = ByteBuffer.allocateDirect(WRITE_BUFFER_SIZE); // 1Mb (1,048,576 Bytes) + private final ByteBuffer readBuf = ByteBuffer.allocateDirect(READ_BUFFER_SIZE); // 1Mb (1,048,576 Bytes) + private final ByteBuffer writeBuf = ByteBuffer.allocateDirect(WRITE_BUFFER_SIZE); // 1Mb (1,048,576 Bytes) private final Thread thread = new Thread(null,this,"TCP-Client",100000000); Modified: trunk/src_server/net/yura/lobby/netty/Server.java =================================================================== --- trunk/src_server/net/yura/lobby/netty/Server.java 2024-08-27 20:39:35 UTC (rev 1044) +++ trunk/src_server/net/yura/lobby/netty/Server.java 2024-12-15 15:45:18 UTC (rev 1045) @@ -13,6 +13,7 @@ import io.netty.util.AttributeKey; import io.netty.util.concurrent.GlobalEventExecutor; import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; @@ -44,7 +45,7 @@ public static final Logger logger = Logger.getLogger(Server.class.getName()); - private final int port; + private int port; private final LobbyController controller; EventLoopGroup bossGroup,workerGroup; @@ -53,6 +54,9 @@ public static final AttributeKey<LobbySession> SESSION_KEY = AttributeKey.valueOf("LobbySession"); public final ChannelGroup allClientChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + /** + * @param port 0 for dynamic port + */ public Server(int port, Database database) { this.port = port; @@ -86,8 +90,14 @@ serverChannel = f.channel(); - logger.info("Netty server started on port "+port); + // if we used a dynamic port (used mainly for testing) + if (port == 0) { + InetSocketAddress inetSocketAddress = (InetSocketAddress)serverChannel.localAddress(); + port = inetSocketAddress.getPort(); + } + logger.info("Netty server started on port " + port); + // Wait until the server socket is closed. //serverChannel.closeFuture().sync(); } Added: trunk/test/net/yura/lobby/client/LobbyComTest.java =================================================================== --- trunk/test/net/yura/lobby/client/LobbyComTest.java (rev 0) +++ trunk/test/net/yura/lobby/client/LobbyComTest.java 2024-12-15 15:45:18 UTC (rev 1045) @@ -0,0 +1,46 @@ +package net.yura.lobby.client; + +import java.util.Set; +import net.yura.lobby.database.impl.MemoryDatabase; +import net.yura.lobby.netty.Server; +import net.yura.lobby.util.LobbyConnection; +import org.junit.Assert; +import org.junit.Test; + +public class LobbyComTest { + + @Test + public void testClient() throws Exception { + int port = 0; // use dynamic port + + Server server = new Server(port, new MemoryDatabase()); + server.start(); + + Connection mycom = new LobbyCom("123-456-789", "JUnit-Test", "1"); + mycom.addEventListener(new LobbyConnection.LoggingClient() { + public void disconnected() { + //Thread.interrupted(); + } + }); + + port = server.getPort(); + mycom.connect("localhost", port); + + Thread.sleep(1000); // wait for connection + + Assert.assertEquals(1, server.getClientCount()); + + mycom.disconnect(); + + Thread.sleep(1000); // wait for disconnection + + Assert.assertEquals(0, server.getClientCount()); + // check that the mycom client really is dead + Set<Thread> threads = Thread.getAllStackTraces().keySet(); + for (Thread thread: threads) { + Assert.assertTrue("thread found: " + thread, !thread.getName().contains("TCP-Client")); + } + + server.shutdown(); + } +} Modified: trunk/test/net/yura/lobby/util/LobbyConnection.java =================================================================== --- trunk/test/net/yura/lobby/util/LobbyConnection.java 2024-08-27 20:39:35 UTC (rev 1044) +++ trunk/test/net/yura/lobby/util/LobbyConnection.java 2024-12-15 15:45:18 UTC (rev 1045) @@ -28,7 +28,7 @@ public LobbyConnection(String clientId) { this(clientId, "3"); } - + public LobbyConnection(String clientId, String version) { client = new LoggingClient(); mycom = new LobbyCom(clientId, "JUnit-Test", version); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2024-08-27 20:39:37
|
Revision: 1044 http://sourceforge.net/p/lobby/code/1044 Author: yuranet Date: 2024-08-27 20:39:35 +0000 (Tue, 27 Aug 2024) Log Message: ----------- can use keys to scroll players in table Modified Paths: -------------- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java Modified: trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2023-07-25 16:28:53 UTC (rev 1043) +++ trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2024-08-27 20:39:35 UTC (rev 1044) @@ -37,6 +37,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.geom.AffineTransform; @@ -2029,8 +2030,9 @@ } } - class ListEditor extends AbstractCellEditor implements TableCellEditor { + class ListEditor extends AbstractCellEditor implements TableCellEditor, KeyListener { + private JTable table; private JList list = new JList(); private JScrollPane scroll = new JScrollPane(list); @@ -2045,6 +2047,7 @@ } }); PlayerList.addRightClickPlayerOptions(list, g); + list.addKeyListener(this); scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); @@ -2053,6 +2056,7 @@ @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + this.table = table; if (value instanceof java.util.Vector) { list.setListData((java.util.Vector)value); } @@ -2059,6 +2063,9 @@ else if (value instanceof Collection) { list.setListData(new java.util.Vector((Collection)value)); } + if (list.getModel().getSize() > 0) { + list.setSelectedIndex(0); + } list.scrollRectToVisible(new Rectangle(1, 1)); return scroll; } @@ -2081,6 +2088,33 @@ } return true; } + + public void keyTyped(KeyEvent event) { } + + public void keyPressed(KeyEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_UP: + case KeyEvent.VK_DOWN: + int newRow = table.getEditingRow() + (e.getKeyCode()== KeyEvent.VK_UP ? -1 : 1); + if (newRow >= 0 && newRow < table.getRowCount()) { + table.scrollRectToVisible(new Rectangle(table.getCellRect(newRow, 0, true))); + table.getSelectionModel().setSelectionInterval(newRow, newRow); + table.editCellAt(newRow, table.getEditingColumn(), e); + list.requestFocusInWindow(); + e.consume(); + } + break; + case KeyEvent.VK_ENTER: + Object selected = list.getSelectedValue(); + if (selected != null) { + showInfoDialog(selected.toString()); + e.consume(); + } + break; + } + } + + public void keyReleased(KeyEvent e) { } } class ButtonRenderer implements TableCellRenderer { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-07-25 16:28:55
|
Revision: 1043 http://sourceforge.net/p/lobby/code/1043 Author: yuranet Date: 2023-07-25 16:28:53 +0000 (Tue, 25 Jul 2023) Log Message: ----------- removed space not needed Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/LobbyController.java Modified: trunk/src_server/net/yura/lobby/server/LobbyController.java =================================================================== --- trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-06-26 17:09:43 UTC (rev 1042) +++ trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-07-25 16:28:53 UTC (rev 1043) @@ -393,7 +393,7 @@ lobby.database.endTransaction(); } - String subject = "flagged " + (user == null ? " game " + optionalGameId : user.getId()); + String subject = "flagged " + (user == null ? "game " + optionalGameId : user.getId()); String flaggedString = user == null ? "" : ("flagged=" + toAdminString(user) + "\n "); String messageString = "gameId=" + gameId + " message=" + text + "\n "; String reporterString = "reporter=" + toAdminString(reporter); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-06-26 17:09:47
|
Revision: 1042 http://sourceforge.net/p/lobby/code/1042 Author: yuranet Date: 2023-06-26 17:09:43 +0000 (Mon, 26 Jun 2023) Log Message: ----------- refresh username fields when opening play info window Modified Paths: -------------- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java trunk/src_client/net/yura/lobby/client/PlayerInfoWindow.java Modified: trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java =================================================================== --- trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2023-06-26 16:39:16 UTC (rev 1041) +++ trunk/src_client/net/yura/lobby/client/LobbyClientGUI.java 2023-06-26 17:09:43 UTC (rev 1042) @@ -1175,9 +1175,7 @@ if (infoWindow == null) { infoWindow = new PlayerInfoWindow(this, mycom, false); - infoWindow.setUsername(user); - infoWindow.showPanels(user.equals(myusername), isUser(Player.PLAYER_MODERATOR)); infoWindow.setSize(500, 450); infoWindow.setLocationRelativeTo(this); @@ -1184,6 +1182,7 @@ playerinfo.put(user,infoWindow); } + infoWindow.showPanels(user.equals(myusername), isUser(Player.PLAYER_MODERATOR)); infoWindow.setVisible(true); } Modified: trunk/src_client/net/yura/lobby/client/PlayerInfoWindow.java =================================================================== --- trunk/src_client/net/yura/lobby/client/PlayerInfoWindow.java 2023-06-26 16:39:16 UTC (rev 1041) +++ trunk/src_client/net/yura/lobby/client/PlayerInfoWindow.java 2023-06-26 17:09:43 UTC (rev 1042) @@ -99,7 +99,6 @@ public void setUsername(String name) { this.name = name; setTitle("Info: " + name); - nameField.setText(name); } public void showPanels(boolean me, boolean mod) { @@ -125,6 +124,48 @@ top.add(makeAdminPanel("resignUserFromAllGames",ProtoAccess.REQUEST_RESIGN_FROM_ALL_GAMES, "username")); top.add(makeAdminPanel("flagUser",ProtoAccess.REQUEST_FLAG_USER, "username")); } + + nameField.setText(name); + connection.getPlayerInfo(name); + +/* + boolean edit = user.equals(myusername); + + try { + + PlayerInfo info = mycom.getPlayerInfo(user); + + Object[] message = new Object[2]; + message[0] = new JLabel("Info:"); + message[1] = new JTextField( info.getInfo() ); + + + String[] options = { + "OK", + "cancel" + }; + + int result = JOptionPane.showOptionDialog( + this, // the parent that the dialog blocks + message, // the dialog message array + "info for "+user, // the title of the dialog window + edit?JOptionPane.OK_CANCEL_OPTION:JOptionPane.OK_OPTION, // option type + JOptionPane.PLAIN_MESSAGE, // message type + null, // optional icon, use null to use the default icon + edit?options:new String[] {options[0]}, // options string array, will be made into buttons + options[0] // option that should be made into a default button + ); + + info.setInfo( ((JTextField)message[1]).getText() ); + + if (edit && result == JOptionPane.OK_OPTION ) { + mycom.setMyPlayerInfo(info); + } + } + catch(IOException ex) { + disconnected(); + } +*/ } public void updateInfo(List list) { @@ -203,55 +244,6 @@ } } - @Override - public void setVisible(boolean b) { - super.setVisible(b); - - if (b) { - // get the latest player info for this player - connection.getPlayerInfo(name); - -/* - boolean edit = user.equals(myusername); - - try { - - PlayerInfo info = mycom.getPlayerInfo(user); - - Object[] message = new Object[2]; - message[0] = new JLabel("Info:"); - message[1] = new JTextField( info.getInfo() ); - - - String[] options = { - "OK", - "cancel" - }; - - int result = JOptionPane.showOptionDialog( - this, // the parent that the dialog blocks - message, // the dialog message array - "info for "+user, // the title of the dialog window - edit?JOptionPane.OK_CANCEL_OPTION:JOptionPane.OK_OPTION, // option type - JOptionPane.PLAIN_MESSAGE, // message type - null, // optional icon, use null to use the default icon - edit?options:new String[] {options[0]}, // options string array, will be made into buttons - options[0] // option that should be made into a default button - ); - - info.setInfo( ((JTextField)message[1]).getText() ); - - if (edit && result == JOptionPane.OK_OPTION ) { - mycom.setMyPlayerInfo(info); - } - } - catch(IOException ex) { - disconnected(); - } -*/ - } - } - private JPanel makeAdminPanel(String label, final String command, final String usernameParamName, final Param... param) { JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-06-26 16:39:21
|
Revision: 1041 http://sourceforge.net/p/lobby/code/1041 Author: yuranet Date: 2023-06-26 16:39:16 +0000 (Mon, 26 Jun 2023) Log Message: ----------- better delete of games Modified Paths: -------------- trunk/src_server/net/yura/lobby/database/impl/JPADatabase.java Modified: trunk/src_server/net/yura/lobby/database/impl/JPADatabase.java =================================================================== --- trunk/src_server/net/yura/lobby/database/impl/JPADatabase.java 2023-06-23 22:01:48 UTC (rev 1040) +++ trunk/src_server/net/yura/lobby/database/impl/JPADatabase.java 2023-06-26 16:39:16 UTC (rev 1041) @@ -180,10 +180,22 @@ return find(GameRoom.class, id); } + /** + * @see #remove(java.lang.Object) + */ @Override public void removeGame(GameRoom gameRoom) { + Interaction in = getTransaction(); + logger.info("going to remove " + gameRoom); + + Query q = in.em.createQuery("DELETE FROM GameRoom g WHERE g.id = ?1"); + q.setParameter(1, gameRoom.getId()); + q.executeUpdate(); // this returns 0 for unknown reasons, but seems to work correctly + + commitTransaction(); +/* + // this was not able to handle RollbackException! try { - // TODO what we want to do is do deleteById remove(gameRoom); } catch (RollbackException rollback) { @@ -190,6 +202,7 @@ // we are trying to remove a game, we do not care about // OptimisticLocking, so we will retry if (rollback.getCause() instanceof OptimisticLockException) { + // TODO this is NOT good enough, we are NOT in a transaction now, this WILL fail! remove(getGame(gameRoom.getId())); } else { @@ -196,6 +209,7 @@ throw rollback; } } +*/ } @Override @@ -339,9 +353,12 @@ commitTransaction(); } + /** + * WARNING! using this method can cause OptimisticLockException + */ private void remove(Object obj) { Interaction in = getTransaction(); - logger.info("going to remove "+obj); + logger.info("going to remove " + obj); in.em.remove(obj); commitTransaction(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-06-23 22:01:49
|
Revision: 1040 http://sourceforge.net/p/lobby/code/1040 Author: yuranet Date: 2023-06-23 22:01:48 +0000 (Fri, 23 Jun 2023) Log Message: ----------- utf url fix Modified Paths: -------------- trunk/lib/UtilME.jar Modified: trunk/lib/UtilME.jar =================================================================== (Binary files differ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-06-07 11:17:13
|
Revision: 1039 http://sourceforge.net/p/lobby/code/1039 Author: yuranet Date: 2023-06-07 11:17:06 +0000 (Wed, 07 Jun 2023) Log Message: ----------- better info in user info screen Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/LobbyController.java trunk/src_server/net/yura/lobby/service/GoogleLogin.java trunk/test/net/yura/lobby/server/ServerTest.java Modified: trunk/src_server/net/yura/lobby/server/LobbyController.java =================================================================== --- trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-05-20 12:15:24 UTC (rev 1038) +++ trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-06-07 11:17:06 UTC (rev 1039) @@ -223,7 +223,10 @@ if (admin || username.equals(session.getUsername())) { info.add(new PlayerInfo("sessions", String.valueOf(sessions.size()), false)); info.add(new PlayerInfo("OAuthLogin", user.getOauthId() == null ? "no" : "yes", false)); - info.add(new PlayerInfo("pushToken", user.getPushToken() == null ? "no" : "yes", false)); + + String pushToken = user.getPushToken(); + info.add(new PlayerInfo("pushToken", pushToken == null ? "none" : + (pushToken.startsWith(ApplePushNotificationService.TOKEN_PREFIX) ? "apple" : "android"), false)); } if (!sessions.isEmpty()) { LobbySession playerSession = sessions.iterator().next(); Modified: trunk/src_server/net/yura/lobby/service/GoogleLogin.java =================================================================== --- trunk/src_server/net/yura/lobby/service/GoogleLogin.java 2023-05-20 12:15:24 UTC (rev 1038) +++ trunk/src_server/net/yura/lobby/service/GoogleLogin.java 2023-06-07 11:17:06 UTC (rev 1039) @@ -36,7 +36,7 @@ userId = "Test"; return; } - + GoogleIdToken idToken = verifier.verify(idTokenString); if (idToken != null) { Payload payload = idToken.getPayload(); @@ -56,10 +56,10 @@ // Use or store profile information // ... - - } else { - System.out.println("Invalid ID token."); } + else { + System.out.println("Invalid ID token: " + idTokenString); + } } catch (Exception ex) { ex.printStackTrace(); Modified: trunk/test/net/yura/lobby/server/ServerTest.java =================================================================== --- trunk/test/net/yura/lobby/server/ServerTest.java 2023-05-20 12:15:24 UTC (rev 1038) +++ trunk/test/net/yura/lobby/server/ServerTest.java 2023-06-07 11:17:06 UTC (rev 1039) @@ -391,7 +391,7 @@ MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("sessions", "1", false))); MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("OAuthLogin", "no", false))); - MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("pushToken", "no", false))); + MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("pushToken", "none", false))); MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("type", "PLAYER_GUEST", false))); MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("app", "JUnit-Test 3", false))); MatcherAssert.assertThat(playerInfo, CoreMatchers.hasItem(new PlayerInfo("games", "[]", false))); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-05-20 12:15:28
|
Revision: 1038 http://sourceforge.net/p/lobby/code/1038 Author: yuranet Date: 2023-05-20 12:15:24 +0000 (Sat, 20 May 2023) Log Message: ----------- avoid null pointers on server from sending push token too early Modified Paths: -------------- trunk/src/net/yura/lobby/client/LobbyCom.java Modified: trunk/src/net/yura/lobby/client/LobbyCom.java =================================================================== --- trunk/src/net/yura/lobby/client/LobbyCom.java 2023-05-12 16:38:21 UTC (rev 1037) +++ trunk/src/net/yura/lobby/client/LobbyCom.java 2023-05-20 12:15:24 UTC (rev 1038) @@ -287,12 +287,10 @@ else { serverPublicKey( (byte[])map.get("key") ); sendLogin(); - + handshakeComplete = true; myclient.connecting("Handshake Complete"); + myclient.connected(); myclient.connecting("You are now connected"); - myclient.connected(); - - handshakeComplete = true; } } else if (ProtoLobby.COMMAND_ALL_GAMETYPES.equals(command)) { @@ -549,6 +547,10 @@ if (!PushLobbyClient.PUSH_SYSTEM_FCM.equals(system) && !PushLobbyClient.PUSH_SYSTEM_APN.equals(system)) { throw new IllegalArgumentException("unsupported system: " + system); } + if (!handshakeComplete) { + logger.info("setPushToken called but handshake not Complete yet " + system + " " + token); + return; + } Map request = new HashMap(); request.put("system", system); request.put("token", encrypt(token)); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-05-12 16:38:24
|
Revision: 1037 http://sourceforge.net/p/lobby/code/1037 Author: yuranet Date: 2023-05-12 16:38:21 +0000 (Fri, 12 May 2023) Log Message: ----------- throw better errors Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/GameLobby.java trunk/src_server/net/yura/lobby/server/LobbySession.java Modified: trunk/src_server/net/yura/lobby/server/GameLobby.java =================================================================== --- trunk/src_server/net/yura/lobby/server/GameLobby.java 2023-05-12 11:18:16 UTC (rev 1036) +++ trunk/src_server/net/yura/lobby/server/GameLobby.java 2023-05-12 16:38:21 UTC (rev 1037) @@ -1146,6 +1146,11 @@ public GameRoom joinGame(int gameId, LobbySession session, String magicWord, LobbySession creator) { String username = session.getUsername(); + + if (username == null) { + throw new IllegalArgumentException("session not logged in"); + } + ServerGame serverGame = runningGames.get(gameId); GameRoom game; @@ -1217,6 +1222,10 @@ @Override public void leaveGame(int gameId, String username) { + if (username == null) { + throw new IllegalArgumentException("username must not be null"); + } + ServerGame serverGame = runningGames.get(gameId); GameRoom game; boolean gameRemoved=false; Modified: trunk/src_server/net/yura/lobby/server/LobbySession.java =================================================================== --- trunk/src_server/net/yura/lobby/server/LobbySession.java 2023-05-12 11:18:16 UTC (rev 1036) +++ trunk/src_server/net/yura/lobby/server/LobbySession.java 2023-05-12 16:38:21 UTC (rev 1037) @@ -36,6 +36,9 @@ return player == null ? null : player.getName(); } public int getPlayerType() { + if (player == null) { + throw new IllegalStateException("player not logged in"); + } return player.getType(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-05-12 11:18:19
|
Revision: 1036 http://sourceforge.net/p/lobby/code/1036 Author: yuranet Date: 2023-05-12 11:18:16 +0000 (Fri, 12 May 2023) Log Message: ----------- log message if you can not read it Modified Paths: -------------- trunk/src_server/net/yura/lobby/netty/ProtoDecoder.java trunk/src_server/net/yura/lobby/netty/ProtoEncoder.java Modified: trunk/src_server/net/yura/lobby/netty/ProtoDecoder.java =================================================================== --- trunk/src_server/net/yura/lobby/netty/ProtoDecoder.java 2023-05-05 20:06:24 UTC (rev 1035) +++ trunk/src_server/net/yura/lobby/netty/ProtoDecoder.java 2023-05-12 11:18:16 UTC (rev 1036) @@ -2,10 +2,14 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import java.util.List; +import java.util.logging.Level; +import net.yura.lobby.model.Message; import net.yura.lobby.server.LobbyController; +import net.yura.lobby.server.LobbyLogger; /** * @author Yura Mamyrin @@ -24,6 +28,7 @@ if (in.readableBytes() < 4) { return; } + in.markReaderIndex(); int dataLength = in.readInt(); if (in.readableBytes() < dataLength) { @@ -30,7 +35,36 @@ in.resetReaderIndex(); return; } - ml.add(controller.decode(new ByteBufInputStream(in), dataLength)); + + Message message; + + try { + if (dataLength < 0) { + throw new IllegalStateException("negative size " + dataLength); + } + // WARNING! "new ByteBufInputStream()" calls "in.markReaderIndex()" + message = controller.decode(new ByteBufInputStream(in), dataLength); + if (message == null) { + throw new IllegalStateException("controller.decode returned null"); + } + } + catch (Exception ex) { + in.resetReaderIndex(); // this resets it to when the ByteBufInputStream was created (or if length was less then 0, then the very start) + + String messageAsString; + try { + messageAsString = ByteBufUtil.hexDump(in, in.readerIndex(), dataLength); + // we have successfully read the strange data, go to the end + in.skipBytes(dataLength); + } + catch (Exception ex2) { + messageAsString = in + " " + ByteBufUtil.hexDump(in) + " " + ex2; + } + LobbyLogger.logger.log(Level.WARNING, "error in decoding message of size: " + dataLength + " data: " + messageAsString, ex); + throw ex; + } + + ml.add(message); } } } Modified: trunk/src_server/net/yura/lobby/netty/ProtoEncoder.java =================================================================== --- trunk/src_server/net/yura/lobby/netty/ProtoEncoder.java 2023-05-05 20:06:24 UTC (rev 1035) +++ trunk/src_server/net/yura/lobby/netty/ProtoEncoder.java 2023-05-12 11:18:16 UTC (rev 1036) @@ -37,7 +37,7 @@ LobbyLogger.logger.log(Level.WARNING, "error in toString", th); messageAsString = message.getCommand(); } - + // TODO if i do not log this here, it does not seem to be logged // fields that are LAZY but we have no transaction create a error here LobbyLogger.logger.log(Level.WARNING, "error in encoding: " + messageAsString, ex); @@ -46,5 +46,4 @@ // this message has already been encoded //LobbyServer.logger.info("Sent "+chc+" "+message); } - } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yu...@us...> - 2023-05-05 20:06:25
|
Revision: 1035 http://sourceforge.net/p/lobby/code/1035 Author: yuranet Date: 2023-05-05 20:06:24 +0000 (Fri, 05 May 2023) Log Message: ----------- better error for session not logged in Modified Paths: -------------- trunk/src_server/net/yura/lobby/server/GameLobby.java trunk/src_server/net/yura/lobby/server/LobbyController.java Modified: trunk/src_server/net/yura/lobby/server/GameLobby.java =================================================================== --- trunk/src_server/net/yura/lobby/server/GameLobby.java 2023-04-15 14:14:08 UTC (rev 1034) +++ trunk/src_server/net/yura/lobby/server/GameLobby.java 2023-05-05 20:06:24 UTC (rev 1035) @@ -993,10 +993,15 @@ } private User getUser(LobbySession session) { - User user = database.getUserByUsername(session.getUsername()); - if (user==null) { - throw new IllegalArgumentException("no user for " + session.getUsername()); + String username = session.getUsername(); + if (username == null) { + throw new IllegalArgumentException("this session is not logged in yet: " + session); } + + User user = database.getUserByUsername(username); + if (user == null) { + throw new IllegalArgumentException("no user for: " + username); + } return user; } private GameRoom getGame(int id) { Modified: trunk/src_server/net/yura/lobby/server/LobbyController.java =================================================================== --- trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-04-15 14:14:08 UTC (rev 1034) +++ trunk/src_server/net/yura/lobby/server/LobbyController.java 2023-05-05 20:06:24 UTC (rev 1035) @@ -491,8 +491,13 @@ +/** + * This encryption ONLY protects against packet sniffers finding out the content of the encrypted data + * it does NOT: + * 1) prevent man in the middle, where the attacker sends there own private key + * 2) prevent already encrypted data being re-sent to authenticate on the server + */ - private static KeyPairGenerator kpg; private static RSAPrivateKey privKey; private static RSAPublicKey pubKey; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |