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 |