[Kde-games-devel] KBattleship network protocol reveals ship types

Stephen McCamant smcc at CSAIL.MIT.EDU
Thu Mar 16 00:05:35 CET 2006


While looking at the protocol that KBattleship uses for network games,
I noticed an unexpected feature: in the ANSWER_SHOOT message that
tells the opponent whether their shot was a hit or a miss, the client
actually reveals some extra information. Because the "fieldstate"
field of the message is taken directly from the return value of the
shipTypeAt() method, it also reveals the type of ship that the shot
hit.

It seems to me that this was unintentional: in the GUI, the explosion
you see doesn't indicate what length ship you hit (unless you've sunk
it). However, knowing the length of the ship gives the player an
advantage: for instance, depending on other shots you've made, it
might let you deduce the ship's orientation when you otherwise
couldn't.

Having extra information in the protocol that isn't normally revealed
makes it possible to cheat by modifying your client program. In the
case of this information, the modification is pretty easy: I've
appended a patch to the end of this message that demonstrates how to
modify your copy of kbattleship to cheat by showing a ship icon rather
than an explosion icon in the "enemy's board" area. (The patch is
against the version in KDE 3.3.2 from Debian sarge, but probably can
be applied to any recent version.)

However, I'm not suggesting that the real kbattleship be modified to
cheat in this way: I think that instead, the protocol should be
changed to not reveal the extra information (except when you've sunk a
ship, when it's revealed anyway). It looks like it would be compatible
with existing clients to always return the same ship type for
non-sinking hits.

Does that sound like the right change to make? I'm looking into a
patch to the KBattleshipWindow::slotSendEnemyFieldState method in the
latest version from SVN that should fix it, but first I have to
recompile the latest versions of some libraries to test with.

 -- Stephen

diff -u kdegames-3.3.2-orig/kbattleship/kbattleship/kbattlefield.cpp kdegames-3.3.2/kbattleship/kbattleship/kbattlefield.cpp
--- kdegames-3.3.2-orig/kbattleship/kbattleship/kbattlefield.cpp	2003-08-14 10:48:41.000000000 -0400
+++ kdegames-3.3.2/kbattleship/kbattleship/kbattlefield.cpp	2006-03-13 18:16:57.000000000 -0500
@@ -187,7 +187,9 @@
 				default:
 					drawSquare();
 					KShip *ship = app->enemyShipAt(i, j);
-					if(ship->placedLeft())
+					if (!ship)
+						drawShipPiece(m_enemyfield[i][j]);
+					else if(ship->placedLeft())
 						drawShipIcon(m_enemyfield[i][j], true);
 					else
 						drawShipIcon(m_enemyfield[i][j]);
diff -u kdegames-3.3.2-orig/kbattleship/kbattleship/kbattleship.cpp kdegames-3.3.2/kbattleship/kbattleship/kbattleship.cpp
--- kdegames-3.3.2-orig/kbattleship/kbattleship/kbattleship.cpp	2004-07-17 13:53:02.000000000 -0400
+++ kdegames-3.3.2/kbattleship/kbattleship/kbattleship.cpp	2006-03-13 18:01:07.000000000 -0500
@@ -355,7 +355,18 @@
 	else
 	{
 		m_stat->setHit();
-		showstate = KBattleField::HIT;
+		//showstate = KBattleField::HIT;
+		if (enemystate == 0)
+			showstate = KBattleField::SHIP1P1;
+		else if (enemystate == 1)
+			showstate = KBattleField::SHIP2P1;
+		else if (enemystate == 2)
+			showstate = KBattleField::SHIP3P1;
+		else if (enemystate == 3)
+			showstate = KBattleField::SHIP4P1;
+		else
+			showstate = KBattleField::HIT;
+
 	}
 
 	slotChangeEnemyFieldData(fieldx, fieldy, showstate);
diff -u kdegames-3.3.2-orig/kbattleship/kbattleship/kgridwidget.cpp kdegames-3.3.2/kbattleship/kbattleship/kgridwidget.cpp
--- kdegames-3.3.2-orig/kbattleship/kbattleship/kgridwidget.cpp	2003-08-14 10:48:41.000000000 -0400
+++ kdegames-3.3.2/kbattleship/kbattleship/kgridwidget.cpp	2006-03-13 18:30:47.000000000 -0500
@@ -100,6 +100,18 @@
 	drawIcon(deathPng);
 }
 
+void KGridWidget::drawShipPiece(int type)
+{
+	QPixmap *png = &hitPng;
+	switch (type) {
+	case KBattleField::SHIP1P1: png = &ship1p1Png; break;
+	case KBattleField::SHIP2P1: png = &ship2p1Png; break;
+	case KBattleField::SHIP3P1: png = &ship3p1Png; break;
+	case KBattleField::SHIP4P1: png = &ship4p1Png; break;
+	}
+	drawIcon(*png);
+}
+
 void KGridWidget::drawShipIcon(int type, bool rotate, bool hit, bool water)
 {
 	int ship = 0;
diff -u kdegames-3.3.2-orig/kbattleship/kbattleship/kgridwidget.h kdegames-3.3.2/kbattleship/kbattleship/kgridwidget.h
--- kdegames-3.3.2-orig/kbattleship/kbattleship/kgridwidget.h	2003-08-14 10:48:41.000000000 -0400
+++ kdegames-3.3.2/kbattleship/kbattleship/kgridwidget.h	2006-03-13 18:12:38.000000000 -0500
@@ -38,6 +38,7 @@
 	void drawDeathBorder();
 	void drawDeathIcon();
 	void drawHitIcon();
+	void drawShipPiece(int type);
 	void drawShipIcon(int type, bool rotate = false, bool hit = false, bool water = false);
 	void drawShipIcon(int ship, int part, bool rotate = false, bool hit = false);
 



More information about the kde-games-devel mailing list