123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "platform/event.h"
- #include "game/gameInterface.h"
- #include "io/fileStream.h"
- #include "console/console.h"
- #include "platform/threads/mutex.h"
- // Script binding.
- #include "game/gameInterface_ScriptBinding.h"
- GameInterface *Game = NULL;
- void *gGameEventQueueMutex = NULL;
- FileStream gJournalStream;
- #ifdef TORQUE_DEBUG
- static U32 sReentrantCount = 0;
- #endif
- //-----------------------------------------------------------------------------
- struct ReadEvent : public Event
- {
- U8 data[3072];
- };
- //-----------------------------------------------------------------------------
- GameInterface::GameInterface()
- {
- AssertFatal(Game == NULL, "ERROR: Multiple games declared.");
- Game = this;
- mJournalMode = JournalOff;
- mRunning = true;
- mRequiresRestart = false;
- if(!gGameEventQueueMutex)
- gGameEventQueueMutex = Mutex::createMutex();
- eventQueue = &eventQueue1;
- }
- //-----------------------------------------------------------------------------
- void GameInterface::processEvent(Event *event)
- {
- if(!mRunning)
- return;
- if(PlatformAssert::processingAssert()) // ignore any events if an assert dialog is up.
- return;
- #ifdef TORQUE_DEBUG
- sReentrantCount++;
- AssertFatal(sReentrantCount == 1, "Error! ProcessEvent is NOT re-entrant.");
- #endif
- switch(event->type)
- {
- case PacketReceiveEventType:
- processPacketReceiveEvent((PacketReceiveEvent *) event);
- break;
- case MouseMoveEventType:
- processMouseMoveEvent((MouseMoveEvent *) event);
- break;
- case InputEventType:
- processInputEvent((InputEvent *) event);
- break;
- case ScreenTouchEventType:
- processScreenTouchEvent((ScreenTouchEvent *) event);
- break;
- case QuitEventType:
- processQuitEvent();
- break;
- case TimeEventType:
- processTimeEvent((TimeEvent *) event);
- break;
- case ConsoleEventType:
- processConsoleEvent((ConsoleEvent *) event);
- break;
- case ConnectedAcceptEventType:
- processConnectedAcceptEvent( (ConnectedAcceptEvent *) event );
- break;
- case ConnectedReceiveEventType:
- processConnectedReceiveEvent( (ConnectedReceiveEvent *) event );
- break;
- case ConnectedNotifyEventType:
- processConnectedNotifyEvent( (ConnectedNotifyEvent *) event );
- break;
- }
- #ifdef TORQUE_DEBUG
- sReentrantCount--;
- #endif
- }
- //-----------------------------------------------------------------------------
- void GameInterface::postEvent(Event &event)
- {
- #ifdef TORQUE_ALLOW_JOURNALING
- if(mJournalMode == JournalPlay && event.type != QuitEventType)
- return;
- #endif //TORQUE_ALLOW_JOURNALING
- // Only one thread can post at a time.
- Mutex::lockMutex(gGameEventQueueMutex);
- #ifdef TORQUE_ALLOW_JOURNALING
- if(mJournalMode == JournalSave)
- {
- gJournalStream.write(event.size, &event);
- gJournalStream.flush();
- }
- #endif //TORQUE_ALLOW_JOURNALING
- // Create a deep copy of event, and save a pointer to the copy in a vector.
- Event* copy = (Event*)dMalloc(event.size);
- dMemcpy(copy, &event, event.size);
- eventQueue->push_back(copy);
-
- Mutex::unlockMutex(gGameEventQueueMutex);
- }
- void GameInterface::processEvents()
- {
- // We want to lock the queue when processing as well - don't need
- // anyone putting new events in the middle of this.
- // We double-buffer the event queues so we'll block the other thread(s) for
- // a minimum amount of time.
- Mutex::lockMutex(gGameEventQueueMutex);
- // swap event queue pointers
- Vector<Event*> &fullEventQueue = *eventQueue;
- if(eventQueue == &eventQueue1)
- eventQueue = &eventQueue2;
- else
- eventQueue = &eventQueue1;
- Mutex::unlockMutex(gGameEventQueueMutex);
- // Walk the event queue in fifo order, processing the events, then clear the queue.
- for(int i=0; i < fullEventQueue.size(); i++)
- {
- Game->processEvent(fullEventQueue[i]);
- dFree(fullEventQueue[i]);
- }
- fullEventQueue.clear();
- }
- void GameInterface::journalProcess()
- {
- #ifdef TORQUE_ALLOW_JOURNALING
- if(mJournalMode == JournalPlay)
- {
- ReadEvent journalReadEvent;
- // used to be:
- // if(gJournalStream.read(&journalReadEvent.type))
- // if(gJournalStream.read(&journalReadEvent.size))
- // for proper non-endian stream handling, the read-ins should match the write-out by using bytestreams read:
- if(gJournalStream.read(sizeof(Event), &journalReadEvent))
- {
- if(gJournalStream.read(journalReadEvent.size - sizeof(Event), &journalReadEvent.data))
- {
- if(gJournalStream.getPosition() == gJournalStream.getStreamSize() && mJournalBreak)
- Platform::debugBreak();
- processEvent(&journalReadEvent);
- return;
- }
- }
- // JournalBreak is used for debugging, so halt all game
- // events if we get this far.
- if(mJournalBreak)
- mRunning = false;
- else
- mJournalMode = JournalOff;
- }
- #endif //TORQUE_ALLOW_JOURNALING
- }
- void GameInterface::saveJournal(const char *fileName)
- {
- mJournalMode = JournalSave;
- gJournalStream.open(fileName, FileStream::Write);
- }
- void GameInterface::playJournal(const char *fileName,bool journalBreak)
- {
- mJournalMode = JournalPlay;
- mJournalBreak = journalBreak;
- gJournalStream.open(fileName, FileStream::Read);
- }
- FileStream *GameInterface::getJournalStream( void )
- {
- return &gJournalStream;
- }
- void GameInterface::journalRead(U32 *val)
- {
- gJournalStream.read(val);
- }
- void GameInterface::journalWrite(U32 val)
- {
- gJournalStream.write(val);
- }
- void GameInterface::journalRead(U32 size, void *buffer)
- {
- gJournalStream.read(size, buffer);
- }
- void GameInterface::journalWrite(U32 size, const void *buffer)
- {
- gJournalStream.write(size, buffer);
- }
|