Stefan Schuermans commited on 2019-08-13 20:05:32
Showing 7 changed files, with 78 additions and 13 deletions.
| ... | ... |
@@ -75,6 +75,16 @@ |
| 75 | 75 |
e.g. <code>18x8-1/256</code> for 18 pixels width, 8 pixels height |
| 76 | 76 |
in 256 grayscales. |
| 77 | 77 |
</p> |
| 78 |
+ <h3>Locking</h3> |
|
| 79 |
+ <p> |
|
| 80 |
+ It is possible to interlock different games among each other, |
|
| 81 |
+ i.e., to make sure that only one of the those games can be started at the |
|
| 82 |
+ same time. |
|
| 83 |
+ If the file <code>lockName</code> exists, it defines the name of a |
|
| 84 |
+ mutual exclusion lock that is acquired when the game is started. |
|
| 85 |
+ If the lock with this name is already taken by another game, the game |
|
| 86 |
+ will not start. |
|
| 87 |
+ </p> |
|
| 78 | 88 |
<h3>Maximum Scrore</h3> |
| 79 | 89 |
<p> |
| 80 | 90 |
The file <code>maxScore</code> configures at which score the game ends. |
| ... | ... |
@@ -0,0 +1 @@ |
| 1 |
+only_one_game |
| ... | ... |
@@ -0,0 +1 @@ |
| 1 |
+only_one_game |
| ... | ... |
@@ -15,6 +15,7 @@ |
| 15 | 15 |
#include "Format.h" |
| 16 | 16 |
#include "FormatFile.h" |
| 17 | 17 |
#include "Game.h" |
| 18 |
+#include "LockNameFile.h" |
|
| 18 | 19 |
#include "Mgrs.h" |
| 19 | 20 |
#include "Module.h" |
| 20 | 21 |
#include "NameFile.h" |
| ... | ... |
@@ -35,6 +36,7 @@ Game::Game(const std::string &name, Mgrs &mgrs, const Directory &dirBase): |
| 35 | 36 |
m_fileBackgroundColor(dirBase.getFile("backgroundColor")),
|
| 36 | 37 |
m_fileOutStream(dirBase.getFile("outstream"), mgrs.m_streamMgr),
|
| 37 | 38 |
m_height(0), m_width(0), m_channels(0), m_imgBuf(), m_backgroundColor(), |
| 39 |
+ m_fileLockName(dirBase.getFile("lockName"), mgrs.m_lockMgr),
|
|
| 38 | 40 |
m_haveTimeStep(false), m_timeStepTime(), m_opConnSounds(), m_opConnsClose() |
| 39 | 41 |
{
|
| 40 | 42 |
} |
| ... | ... |
@@ -72,6 +74,9 @@ void Game::updateConfig() |
| 72 | 74 |
m_fileOutStream.update(); |
| 73 | 75 |
} |
| 74 | 76 |
|
| 77 |
+ // process lock name updates |
|
| 78 |
+ m_fileLockName.updateIfModified(); |
|
| 79 |
+ |
|
| 75 | 80 |
// check config update of derived game |
| 76 | 81 |
updateConfigGame(doReinit, doRedraw); |
| 77 | 82 |
|
| ... | ... |
@@ -110,19 +115,40 @@ void Game::timeCall() |
| 110 | 115 |
planTimeCall(); |
| 111 | 116 |
} |
| 112 | 117 |
|
| 113 |
-/// activate game: set up image buffer, call redraw() |
|
| 114 |
-void Game::activate() |
|
| 118 |
+/** |
|
| 119 |
+ * @brief check if game can be actiavted: if interlock is free |
|
| 120 |
+ * @return whether game can be activated (activate() might still fail) |
|
| 121 |
+ */ |
|
| 122 |
+bool Game::canActivate() |
|
| 115 | 123 |
{
|
| 124 |
+ return m_fileLockName.isfree(); |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+/** |
|
| 128 |
+ * @brief activate game: |
|
| 129 |
+ * take interlock, set up image buffer, call redraw() |
|
| 130 |
+ * @return whether game could be activated |
|
| 131 |
+ */ |
|
| 132 |
+bool Game::activate() |
|
| 133 |
+{
|
|
| 134 |
+ if (! m_fileLockName.take()) {
|
|
| 135 |
+ return false; |
|
| 136 |
+ } |
|
| 116 | 137 |
createImgBuf(); |
| 117 | 138 |
reinitialize(); |
| 118 | 139 |
redraw(); |
| 140 |
+ return true; |
|
| 119 | 141 |
} |
| 120 | 142 |
|
| 121 |
-/// deactivate game: tear down image buffer, deactivate output |
|
| 143 |
+/** |
|
| 144 |
+ * @brief deactivate game: |
|
| 145 |
+ * tear down image buffer, deactivate output, release interlock |
|
| 146 |
+ */ |
|
| 122 | 147 |
void Game::deactivate() |
| 123 | 148 |
{
|
| 124 | 149 |
destroyImgBuf(); |
| 125 | 150 |
sendFrame(); |
| 151 |
+ m_fileLockName.release(); |
|
| 126 | 152 |
} |
| 127 | 153 |
|
| 128 | 154 |
/// check if game is active |
| ... | ... |
@@ -18,6 +18,7 @@ |
| 18 | 18 |
#include "File.h" |
| 19 | 19 |
#include "Format.h" |
| 20 | 20 |
#include "FormatFile.h" |
| 21 |
+#include "LockNameFile.h" |
|
| 21 | 22 |
#include "Mgrs.h" |
| 22 | 23 |
#include "Module.h" |
| 23 | 24 |
#include "NameFile.h" |
| ... | ... |
@@ -93,10 +94,23 @@ protected: |
| 93 | 94 |
/// process next time step of game |
| 94 | 95 |
virtual void timeStep() = 0; |
| 95 | 96 |
|
| 96 |
- /// activate game: set up image buffer, call redraw() |
|
| 97 |
- void activate(); |
|
| 97 |
+ /** |
|
| 98 |
+ * @brief check if game can be actiavted: if interlock is free |
|
| 99 |
+ * @return whether game can be activated (activate() might still fail) |
|
| 100 |
+ */ |
|
| 101 |
+ bool canActivate(); |
|
| 98 | 102 |
|
| 99 |
- /// deactivate game: tear down image buffer, deactivate output |
|
| 103 |
+ /** |
|
| 104 |
+ * @brief activate game: |
|
| 105 |
+ * take interlock, set up image buffer, call redraw() |
|
| 106 |
+ * @return whether game could be activated |
|
| 107 |
+ */ |
|
| 108 |
+ bool activate(); |
|
| 109 |
+ |
|
| 110 |
+ /** |
|
| 111 |
+ * @brief deactivate game: |
|
| 112 |
+ * tear down image buffer, deactivate output, release interlock |
|
| 113 |
+ */ |
|
| 100 | 114 |
void deactivate(); |
| 101 | 115 |
|
| 102 | 116 |
/// check if game is active |
| ... | ... |
@@ -235,6 +249,7 @@ protected: |
| 235 | 249 |
ColorData m_backgroundColor; ///< background color |
| 236 | 250 |
|
| 237 | 251 |
private: |
| 252 |
+ LockNameFile m_fileLockName; ///< lock name file for game interlock |
|
| 238 | 253 |
bool m_haveTimeStep; ///< if a time step is pending |
| 239 | 254 |
Time m_timeStepTime; ///< time of next time step |
| 240 | 255 |
OpConnSounds m_opConnSounds; ///< sound to play on operator connections |
| ... | ... |
@@ -118,6 +118,10 @@ void Pong::updateConfigGame(bool &doReinit, bool &doRedraw) |
| 118 | 118 |
*/ |
| 119 | 119 |
bool Pong::acceptNewOpConn(const std::string &name) |
| 120 | 120 |
{
|
| 121 |
+ // game cannot be activates -> reject connection |
|
| 122 |
+ if (! canActivate()) {
|
|
| 123 |
+ return false; |
|
| 124 |
+ } |
|
| 121 | 125 |
// left player can join if none there yet |
| 122 | 126 |
if (name == m_name + c_opConnSuffixLeft && ! m_pConnLeft) {
|
| 123 | 127 |
return true; |
| ... | ... |
@@ -159,9 +163,14 @@ void Pong::newOpConn(const std::string &name, OpConn *pConn) |
| 159 | 163 |
if (isActive()) {
|
| 160 | 164 |
redraw(); // player color is different for phone / computer |
| 161 | 165 |
} |
| 162 |
- // first player joined |
|
| 166 |
+ // first player joined -> activate |
|
| 163 | 167 |
else {
|
| 164 |
- activate(); |
|
| 168 |
+ if (! activate()) {
|
|
| 169 |
+ // activation failed (interlock), close connection as soon as possible |
|
| 170 |
+ requestOpConnClose(pConn); |
|
| 171 |
+ m_pConnLeft = nullptr; |
|
| 172 |
+ m_pConnRight = nullptr; |
|
| 173 |
+ } |
|
| 165 | 174 |
} |
| 166 | 175 |
} |
| 167 | 176 |
|
| ... | ... |
@@ -104,8 +104,8 @@ bool Tetris::acceptNewOpConn(const std::string &name) |
| 104 | 104 |
{
|
| 105 | 105 |
(void)name; |
| 106 | 106 |
|
| 107 |
- // accept player if no one there yet |
|
| 108 |
- return ! m_pConn; |
|
| 107 |
+ // accept player if no one there yet and game can be activated |
|
| 108 |
+ return ! m_pConn && canActivate(); |
|
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 | 111 |
/** |
| ... | ... |
@@ -121,14 +121,17 @@ void Tetris::newOpConn(const std::string &name, OpConn *pConn) |
| 121 | 121 |
|
| 122 | 122 |
// player arrives and starts game |
| 123 | 123 |
if (! m_pConn) {
|
| 124 |
+ if (activate()) {
|
|
| 124 | 125 |
m_pConn = pConn; |
| 125 | 126 |
requestOpConnSound(m_pConn, m_fileStartSound); |
| 126 |
- activate(); |
|
| 127 |
+ } else {
|
|
| 128 |
+ // activation failed (interlock), close connection as soon as possible |
|
| 129 |
+ requestOpConnClose(pConn); |
|
| 127 | 130 |
} |
| 128 |
- // close imcoming connection as soon as possible, nothing else happens |
|
| 131 |
+ } |
|
| 132 |
+ // close imcoming connection as soon as possible |
|
| 129 | 133 |
else {
|
| 130 | 134 |
requestOpConnClose(pConn); |
| 131 |
- return; |
|
| 132 | 135 |
} |
| 133 | 136 |
} |
| 134 | 137 |
|
| 135 | 138 |