92efc5f63475576cc9a8ee7702b2c63e6c47f03e
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

1) /* Blinker
2)    Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

6) #include <map>
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

7) #include <set>
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

8) #include <sstream>
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

9) #include <string>
10) #include <vector>
11) 
12) #include <BlinkenLib/BlinkenFrame.h>
13) 
14) #include "File.h"
15) #include "Format.h"
16) #include "FormatFile.h"
17) #include "Game.h"
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

18) #include "LockNameFile.h"
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

19) #include "Mgrs.h"
20) #include "Module.h"
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

21) #include "NameFile.h"
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

22) #include "OutStreamFile.h"
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

23) #include "UIntFile.h"
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

24) 
25) namespace Blinker {
26) 
27) /**
28)  * @brief constructor
29)  * @param[in] name module name
30)  * @param[in] mgrs managers
31)  * @param[in] dirBase base directory
32)  */
33) Game::Game(const std::string &name, Mgrs &mgrs, const Directory &dirBase):
34)   Module(name, mgrs, dirBase),
35)   m_fileFormat(dirBase.getFile("format")),
36)   m_fileBackgroundColor(dirBase.getFile("backgroundColor")),
37)   m_fileOutStream(dirBase.getFile("outstream"), mgrs.m_streamMgr),
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

38)   m_height(0), m_width(0), m_channels(0), m_imgBuf(), m_backgroundColor(),
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

39)   m_fileLockName(dirBase.getFile("lockName"), mgrs.m_lockMgr),
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

40)   m_haveTimeStep(false), m_timeStepTime(), m_opConnSounds(), m_opConnsClose()
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

41) {
42) }
43) 
44) /// virtual destructor
45) Game::~Game()
46) {
47)   // clean up
48)   deactivate();
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

49) 
50)   // cancel time callback request
51)   m_mgrs.m_callMgr.cancelTimeCall(this);
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

52) }
53) 
54) /// check for update of configuration
55) void Game::updateConfig()
56) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

57)   bool doReinit = false;
58)   bool doRedraw = false;
59) 
60)   // format file was modified -> re-create canvas and schedule redraw
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

61)   if (m_fileFormat.checkModified()) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

62)     m_fileFormat.update();
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

63)     createImgBuf();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

64)     doReinit = true;
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

65)   }
66) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

67)   // color file was modified -> convert color, schedule redraw
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

68)   if (colorUpdate(m_fileBackgroundColor, 0, m_backgroundColor)) {
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

69)     doRedraw = true;
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

70)   }
71) 
72)   // output stream name file was modified -> re-get output stream
73)   if (m_fileOutStream.checkModified()) {
74)     m_fileOutStream.update();
75)   }
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

76) 
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

77)   // process lock name updates
78)   m_fileLockName.updateIfModified();
79) 
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

80)   // check config update of derived game
Stefan Schuermans change of some game params...

Stefan Schuermans authored 5 years ago

81)   updateConfigGame(doReinit, doRedraw);
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

82) 
83)   // re-initialize / redraw
84)   if (doReinit) {
85)     reinitialize();
86)     doRedraw = true;
87)   }
88)   if (doRedraw) {
89)     redraw();
90)   }
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

91) }
92) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

93) /// callback when requested time reached
94) void Game::timeCall()
95) {
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

96)   // play sounds on operator connections
97)   for (auto & opConnSound : m_opConnSounds) {
98)     playOpConnSound(opConnSound.first, *opConnSound.second);
99)   }
100)   m_opConnSounds.clear();
101) 
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

102)   // close operator connections
103)   for (OpConn *pConn : m_opConnsClose) {
104)     pConn->close();
105)   }
106)   m_opConnsClose.clear();
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

107) 
108)   // time step of game has been reached -> call game
109)   if (m_haveTimeStep && Time::now() >= m_timeStepTime) {
110)     m_haveTimeStep = false;
111)     timeStep();
112)   }
113) 
114)   // plan next time call - if any
115)   planTimeCall();
116) }
117) 
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

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()
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

123) {
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

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)   }
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

137)   createImgBuf();
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

138)   reinitialize();
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

139)   redraw();
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

140)   return true;
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

141) }
142) 
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

143) /**
144)  * @brief deactivate game:
145)  *        tear down image buffer, deactivate output, release interlock
146)  */
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

147) void Game::deactivate()
148) {
149)   destroyImgBuf();
150)   sendFrame();
Stefan Schuermans add game interlock

Stefan Schuermans authored 5 years ago

151)   m_fileLockName.release();
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

152) }
153) 
Stefan Schuermans pong: activate when player...

Stefan Schuermans authored 5 years ago

154) /// check if game is active
155) bool Game::isActive() const
156) {
157)   return ! m_imgBuf.empty(); // game is active if there is an image buffer
158) }
159) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

160) /// set pixel in image buffer
161) void Game::pixel(int y, int x, ColorData const &cd)
162) {
163)   if (m_imgBuf.empty() ||
164)       ! checkLimitInt(y, 0, m_height - 1) ||
165)       ! checkLimitInt(x, 0, m_width - 1)) {
166)     return;
167)   }
168)   int pos = (y * m_width + x) * m_channels;
169)   std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
170) }
171) 
172) /// draw horizontal line to image buffer
173) void Game::lineHor(int y, int x1, int x2, ColorData const &cd)
174) {
175)   if (m_imgBuf.empty() ||
176)       ! checkLimitInt(y, 0, m_height - 1) ||
177)       ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) {
178)     return;
179)   }
180)   int pos = (y * m_width + x1) * m_channels;
181)   int dx = m_channels;
182)   for (int x = x1; x <= x2; ++x) {
183)     std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
184)     pos += dx;
185)   }
186) }
187) 
188) /// draw vertical line to image buffer
189) void Game::lineVert(int y1, int y2, int x, ColorData const &cd)
190) {
191)   if (m_imgBuf.empty() ||
192)       ! checkIntRangeLimit(y1, y2, 0, m_height - 1) ||
193)       ! checkLimitInt(x, 0, m_width - 1)) {
194)     return;
195)   }
196)   int pos = (y1 * m_width + x) * m_channels;
197)   int dy = m_width * m_channels;
198)   for (int y = y1; y <= y2; ++y) {
199)     std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
200)     pos += dy;
201)   }
202) }
203) 
204) /// draw non-filled rectangle to image buffer
205) void Game::rect(int y1, int y2, int x1, int x2, ColorData const &cd)
206) {
207)   lineHor(y1, x1, x2, cd);
208)   lineHor(y2, x1, x2, cd);
209)   lineVert(y1, y2, x1, cd);
210)   lineVert(y1, y2, x2, cd);
211) }
212) 
213) /// draw filled rectangle to image buffer
214) void Game::rectFill(int y1, int y2, int x1, int x2, ColorData const &cd)
215) {
216)   if (m_imgBuf.empty() ||
217)       ! checkIntRangeLimit(y1, y2, 0, m_height - 1) ||
218)       ! checkIntRangeLimit(x1, x2, 0, m_width - 1)) {
219)     return;
220)   }
221)   int pos = (y1 * m_width + x1) * m_channels;
222)   int dx = m_channels;
223)   int dy = m_width - (x2 - x1 + 1) * m_channels;
224)   for (int y = y1; y <= y2; ++y) {
225)     for (int x = x1; x <= x2; ++x) {
226)       std::copy(cd.begin(), cd.end(), m_imgBuf.begin() + pos);
227)       pos += dx;
228)     }
229)     pos += dy;
230)   }
231) }
232) 
Stefan Schuermans pong: display score

Stefan Schuermans authored 5 years ago

233) /**
234)  * @brief draw a small digit (3x5 pixels) to image buffer
235)  * @param[in] topY y coordinate of top of digit
236)  * @param[in] leftX x coordinate of left of digit
237)  * @param[in] digit to draw ('0'..'9')
238)  * @param[in] cd color to use for drawing
239)  */
240) void Game::digit3x5(int topY, int leftX, char digit, ColorData const &cd)
241) {
242)   /**
243)    * digit data in octal,
244)    * each row is 3 bits, msb of row is left,
245)    * msb row is top
246)    */
247)   static const unsigned int digitData[10] = {
248)     075557, 022222, 071747, 071717, 055711,
249)     074717, 074757, 071111, 075757, 075717
250)   };
251) 
252)   if (digit < '0' || digit > '9') {
253)     return;
254)   }
255)   int idx = digit - '0';
256)   unsigned int data = digitData[idx];
257)   for (int y = topY; y < topY + 5; ++y) {
258)     for (int x = leftX; x < leftX + 3; ++x) {
259)       data <<= 1;
260)       if (data & 0100000) {
261)         pixel(y, x, cd);
262)       }
263)     }
264)   }
265) }
266) 
267) /**
268)  * @brief draw small digits (3x5 each, 1 pixel gap) to image buffer
269)  * @param[in] topY y coordinate of top of digits
270)  * @param[in] leftX x coordinate of left of digits
271)  * @param[in] digits to draw (string of '0'..'9')
272)  * @param[in] cd color to use for drawing
273)  */
274) void Game::digits3x5(int topY, int leftX, std::string const &digits,
275)                      ColorData const &cd)
276) {
277)   for (char digit: digits) {
278)     digit3x5(topY, leftX, digit, cd);
279)     leftX += 4;
280)   }
281) }
282) 
283) /**
284)  * @brief draw number using 3x5 digits to image buffer
285)  * @param[in] anchorY y coordinate of anchor point
286)  * @param[in] anchorX x coordinate of anchor point
287)  * @param[in] alignY y alignment, -1 for top, 0 for center, 1 for bottom
288)  * @param[in] alignX x alignment, -1 for left, 0 for center, 1 for right
289)  * @param[in] number non-negative number to draw
290)  * @param[in] cd color to use for drawing
291)  */
292) void Game::number3x5(int anchorY, int anchorX, int alignY, int alignX,
293)                      int number, ColorData const &cd)
294) {
295)   // convert number to digits string
296)   if (number < 0) {
297)     return;
298)   }
299)   std::stringstream digitsStrm;
300)   digitsStrm << number;
301)   std::string const &digits = digitsStrm.str();
302) 
303)   // compute top left position
304)   int topY, leftX;
305)   switch (alignY) {
306)   case -1: topY = anchorY; break;
307)   case 0: topY = anchorY - 2; break;
308)   case 1: topY = anchorY - 4; break;
309)   default: return;
310)   }
311)   switch (alignX) {
312)   case -1: leftX = anchorX; break;
313)   case 0: leftX = anchorX - 2 * digits.length() + 1; break;
314)   case 1: leftX = anchorX - 4 * digits.length() + 2; break;
315)   default: return;
316)   }
317) 
318)   // draw digits
319)   digits3x5(topY, leftX, digits, cd);
320) }
321) 
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

322) /**
323)  * @brief process update of color file
324)  * @param[in] colorFile file containing color as string
325)  * @param[in] def default color (grayscale) in case file is invalid (0..255)
326)  * @pram[out] data color data
327)  * @return true on update
328)  */
329) bool Game::colorUpdate(ColorFile &colorFile, unsigned char def,
330)                        ColorData &data) const
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

331) {
332)   if (colorFile.checkModified()) {
333)     colorFile.update();
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

334)     color2data(colorFile, def, data);
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

335)     return true;
336)   } else {
337)     return false;
338)   }
339) }
340) 
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

341) /**
342)  * @brief convert color to raw color data
343)  * @param[in] colorFile file containing color as string
344)  * @param[in] def default color (grayscale) in case file is invalid (0..255)
345)  * @pram[out] data color data
346)  */
347) void Game::color2data(ColorFile const &colorFile, unsigned char def,
348)                       ColorData &data) const
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

349) {
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

350)   unsigned int channels = m_fileFormat.m_obj.m_channels;
351)   unsigned int maxval = m_fileFormat.m_obj.m_maxval;
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

352)   if (! m_fileFormat.m_valid || ! colorFile.m_valid) {
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

353)     data.resize(m_fileFormat.m_obj.m_channels,
354)                 (unsigned char)(def * maxval / 255.0 + 0.5));
Stefan Schuermans begin of Pong game

Stefan Schuermans authored 5 years ago

355)   } else {
356)     data.resize(m_fileFormat.m_obj.m_channels);
357)     Color const &color = colorFile.m_obj;
358)     if (channels == 1) {
359)       // single channel
360)       // convert to monochrome according to CIE XYZ
361)       double val = 0.2125 * color.m_red + 0.7154 * color.m_green
362)                                         + 0.0721 * color.m_blue;
363)       // adapt to maxval and round
364)       data.at(0) = (unsigned char)(val * maxval / 255.0 + 0.5);
365)     } else if (channels == 2) {
366)       // two channels
367)       // adapt to maxval and round, ignore blue
368)       data.at(0) = (unsigned char)(color.m_red * maxval / 255.0 + 0.5);
369)       data.at(1) = (unsigned char)(color.m_green * maxval / 255.0 + 0.5);
370)     } else if (channels >= 3) {
371)       // three channels (more than three channels: further channels are dark)
372)       // adapt to maxval and round
373)       data.at(0) = (unsigned char)(color.m_red * maxval / 255.0 + 0.5);
374)       data.at(1) = (unsigned char)(color.m_green * maxval / 255.0 + 0.5);
375)       data.at(2) = (unsigned char)(color.m_blue * maxval / 255.0 + 0.5);
376)     }
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

377)   }
378) }
379) 
Stefan Schuermans pong: configurable speed

Stefan Schuermans authored 5 years ago

380) /// process update of value file, return true on update
381) bool Game::valueUpdate(UIntFile &valueFile, ValueDescr const &descr,
382)                        unsigned int &value)
383) {
384)   if (valueFile.checkModified()) {
385)     valueFile.update();
386)     valueFromFile(valueFile, descr, value);
387)     return true;
388)   } else {
389)     return false;
390)   }
391) }
392) 
393) /// get value from value file
394) void Game::valueFromFile(UIntFile &valueFile, ValueDescr const &descr,
395)                          unsigned int &value)
396) {
397)   if (! valueFile.m_valid) {
398)     value = descr.default_;
399)   } else {
400)     value = valueFile.m_obj.m_uint;
401)     if (value < descr.minimum) {
402)       value = descr.minimum;
403)     }
404)     else if (value > descr.maximum) {
405)       value = descr.maximum;
406)     }
407)   }
408) }
409) 
Stefan Schuermans sound support for pong game

Stefan Schuermans authored 5 years ago

410) /// process update of sound name file
411) void Game::soundUpdate(NameFile &soundFile)
412) {
413)   if (soundFile.checkModified()) {
414)     soundFile.update();
415)   }
416) }
417) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

418) /// send current image buffer as frame to output stream
419) void Game::sendFrame()
420) {
421)   // image buffer available -> send its contents as frame
422)   if (! m_imgBuf.empty()) {
423)     Format const &fmt = m_fileFormat.m_obj;
424)     stBlinkenFrame *pFrame = BlinkenFrameNew(fmt.m_height, fmt.m_width,
425)                                              fmt.m_channels, fmt.m_maxval, 1);
426)     BlinkenFrameSetPixelData(pFrame, 0, m_height, 0, m_width, 0, m_channels,
427)                              m_imgBuf.data());
428)     m_fileOutStream.setFrame(pFrame);
429)     BlinkenFrameFree(pFrame);
430)   }
431)   // no image buffer available -> send "no frame" information
432)   else {
433)     m_fileOutStream.setFrame(NULL);
434)   }
435) }
436) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

437) /// set next game time step - plan timed action of game
438) void Game::setTimeStep(const Time& timeStepTime)
439) {
440)   m_haveTimeStep = true;
441)   m_timeStepTime = timeStepTime;
442)   planTimeCall();
443) }
444) 
445) /// unset game time step - do timed action for game
446) void Game::unsetTimeStep()
447) {
448)   m_haveTimeStep = false;
449)   planTimeCall();
450) }
451) 
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

452) /// play a sound on operator connection (NULL ok) (direct)
453) void Game::playOpConnSound(OpConn *pConn, NameFile const &soundFile)
454) {
455)   if (pConn && soundFile.m_valid) {
456)     pConn->sendPlay(soundFile.m_obj.m_str);
457)   }
458) }
459) 
460) //// request playing a sound on operator connection (NULL ok) (via time call)
461) void Game::requestOpConnSound(OpConn *pConn, NameFile const &soundFile)
462) {
463)   if (pConn) {
464)     m_opConnSounds[pConn] = &soundFile;
Stefan Schuermans add time call for sound req

Stefan Schuermans authored 5 years ago

465)     planTimeCall();
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

466)   }
467) }
468) 
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

469) /// request closing operator connection (NULL ok) (closed via time call)
470) void Game::requestOpConnClose(OpConn *pConn)
471) {
472)   if (pConn) {
473)     m_opConnsClose.insert(pConn);
474)     planTimeCall();
475)   }
476) }
477) 
478) /// remove operator connection from requests (call when op conn is closed)
479) void Game::forgetOpConn(OpConn *pConn)
480) {
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

481)   m_opConnSounds.erase(pConn);
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

482)   m_opConnsClose.erase(pConn);
483)   planTimeCall();
484) }
485) 
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

486) /// (re-)create image buffer
487) void Game::createImgBuf()
488) {
489)   // get rid of old image buffer
490)   destroyImgBuf();
491) 
492)   // read format from format file
493)   m_fileFormat.update();
494)   if (! m_fileFormat.m_valid)
495)     return;
496) 
497)   // read background color
498)   m_fileBackgroundColor.update();
499)   if (! m_fileBackgroundColor.m_valid)
500)     return;
501) 
502)   // store parameters
503)   m_height = m_fileFormat.m_obj.m_height;
504)   m_width = m_fileFormat.m_obj.m_width;
505)   m_channels = m_fileFormat.m_obj.m_channels;
506) 
507)   // create image buffer
508)   m_imgBuf.resize(m_height * m_width * m_channels);
509) 
510)   // convert background color
Stefan Schuermans use default colors when mis...

Stefan Schuermans authored 5 years ago

511)   color2data(m_fileBackgroundColor, 0, m_backgroundColor);
Stefan Schuermans base class for games

Stefan Schuermans authored 5 years ago

512) }
513) 
514) /// tear down image buffer
515) void Game::destroyImgBuf()
516) {
517)   m_imgBuf.clear();
518)   m_backgroundColor.clear();
519) }
520) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

521) /// request next time call - or cancel request if not needed
522) void Game::planTimeCall()
523) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

524)   // request immediate time call if there are internal time-based actions
Stefan Schuermans add playing sounds to game...

Stefan Schuermans authored 5 years ago

525)   if (! m_opConnSounds.empty() || ! m_opConnsClose.empty()) {
Stefan Schuermans add op conn close requests

Stefan Schuermans authored 5 years ago

526)     m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
527)     return;
528)   }
529) 
Stefan Schuermans move time call logic to gam...

Stefan Schuermans authored 5 years ago

530)   // no time step requested by game
531)   if (! m_haveTimeStep) {
532)     m_mgrs.m_callMgr.cancelTimeCall(this);
533)     return;
534)   }
535) 
536)   // request next time call
537)   m_mgrs.m_callMgr.requestTimeCall(this, m_timeStepTime);
538) }
539)