Example #1
0
void RChannelFifoNBWriter::
    StartSupplier(RChannelBufferPrefetchInfo* prefetchCookie)
{
    ChannelUnitList unblockedList;

    {
        AutoCriticalSection acs(&m_baseDR);

        LogAssert(m_supplierState == SS_Stopped);

        LogAssert(m_writerState != WS_Closed);
        LogAssert(m_outstandingUnits == 0);

        BOOL bRet = ::ResetEvent(m_supplierDrainEvent);
        LogAssert(bRet != 0);

        m_supplierState = SS_Running;

        while (m_blockedList.IsEmpty() == false)
        {
            ++m_outstandingUnits;

            RChannelFifoUnit* blockedUnit =
                m_blockedList.CastOut(m_blockedList.GetHead());

            unblockedList.TransitionToTail(unblockedList.
                                           CastIn(blockedUnit));
        }

        m_sendLatch.AcceptList(&unblockedList);
    }

    SendUnits(&unblockedList);
}
Example #2
0
void RChannelFifoWriter::AcceptReturningUnit(RChannelFifoUnit* unit)
{
    ChannelUnitList unblockedList;
    ChannelFifoUnitList returnList;
    bool wakeUpWriterDrain = false;
    bool wakeUpSupplierDrain = false;

    {
        AutoCriticalSection acs(&m_baseDR);

        LogAssert(m_outstandingUnits > 0);
        --m_outstandingUnits;

        if (unit == m_terminationUnit)
        {
            LogAssert(m_outstandingUnits == 0);
            LogAssert(m_blockedList.IsEmpty());
            m_terminationUnit = NULL;

            if (m_writerState == WS_Draining)
            {
                wakeUpWriterDrain = true;
            }
        }

        returnList.InsertAsTail(returnList.CastIn(unit));
        unit = NULL;

        if (m_supplierState == SS_Draining)
        {
            /* the supplier has requested a drain */
            if (m_outstandingUnits == 0)
            {
                /* we have been building up written items in the
                   blocked list while waiting for the outstanding
                   units to be returned. We can send them all back
                   now. */
                LogAssert(m_readerTerminationItem != NULL);
                RChannelItemType drainType =
                    m_readerTerminationItem->GetType();
                wakeUpWriterDrain =
                    ReWriteBlockedListForEarlyReturn(drainType) ||
                    wakeUpWriterDrain;
                returnList.TransitionToTail(&m_blockedList);
                m_supplierState = SS_Stopped;
                ++m_supplierEpoch;
                wakeUpSupplierDrain = true;
            }

            LogAssert(m_availableUnits == 0);
        }
        else if (m_supplierState != SS_Interrupted)
        {
            LogAssert(m_supplierState == SS_Running);

            if (m_blockedList.IsEmpty())
            {
                if (m_writerTerminationItem == NULL)
                {
                    /* there's nothing blocked, so just add a unit to
                       the available list and return without doing
                       anything else */
                    ++m_availableUnits;
                }
            }
            else
            {
                /* there was a blocked request waiting to be sent to
                   the FIFO: put it in now that we have a space
                   available. */
                LogAssert(m_supplierState == SS_Running);

                RChannelFifoUnit* blockedUnit =
                    m_blockedList.CastOut(m_blockedList.GetHead());

                unblockedList.TransitionToTail(unblockedList.
                                               CastIn(blockedUnit));
                ++m_outstandingUnits;

                m_sendLatch.AcceptList(&unblockedList);
            }
        }

        m_returnLatch.AcceptList(&returnList);
    }

    if (wakeUpWriterDrain)
    {
        LogAssert(unblockedList.IsEmpty());
        BOOL bRet = ::SetEvent(m_writerDrainEvent);
        LogAssert(bRet != 0);
    }
    else
    {
        SendUnits(&unblockedList);
    }

    ReturnHandlers(&returnList);

    if (wakeUpSupplierDrain)
    {
        BOOL bRet = ::SetEvent(m_supplierDrainEvent);
        LogAssert(bRet != 0);
    }
}
Example #3
0
void RChannelFifoWriter::
    EnqueueItemArray(RChannelItemArrayRef& itemArrayIn,
                     RChannelItemArrayWriterHandler* handler,
                     SyncHandler* syncHandler)
{
    ChannelUnitList sendList;
    ChannelFifoUnitList returnList;
    bool writerHasTerminated = false;
    RChannelFifoUnit* unit = new RChannelFifoUnit(this);

    RChannelItemArrayRef itemArray;
    /* ensure that the caller no longer holds a reference to this array */
    itemArray.TransferFrom(itemArrayIn);

    LogAssert(itemArray->GetNumberOfItems() > 0);

    {
        AutoCriticalSection acs(&m_baseDR);

        unit->SetPayload(itemArray, handler, RChannelItem_MarshalError);

        LogAssert(m_writerState != WS_Closed);

        writerHasTerminated = CheckForTerminationItem(unit);

        if (writerHasTerminated)
        {
            /* some previous invocation (perhaps is another thread)
               has already sent a termination item so signal that we
               aren't accepting any more items by just returning the
               handler immediately with this status code */
            unit->SetStatusCode(RChannelItem_EndOfStream);
        }
        else
        {
            LogAssert(m_writerState == WS_Running);

            if (m_supplierState == SS_Interrupted)
            {
                /* the writer has not terminated, but the reader is
                   about to request a drain. Queue up the handler to
                   be returned with the appropriate code once the
                   drain actually arrives.  */
                LogAssert(m_readerTerminationItem == NULL);
                LogAssert(m_availableUnits == 0);
                LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0);

                StartBlocking(unit, syncHandler);
                unit = NULL;
            }
            else if (m_supplierState == SS_Draining)
            {
                /* the writer has not terminated, but the reader has
                   requested a drain. */
                LogAssert(m_readerTerminationItem != NULL);
                RChannelItemType drainType =
                    m_readerTerminationItem->GetType();
                LogAssert(drainType != RChannelItem_MarshalError);
                LogAssert(m_availableUnits == 0);

                if (m_outstandingUnits > 0)
                {
                    /* queue up this item to be returned after the
                       in-flight items have come back. At that point
                       the extra item reference will be removed, so
                       leave it there for now. */
                    LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0);
                    StartBlocking(unit, syncHandler);
                    unit = NULL;
                }
                else
                {
                    /* if there are no in-flight items we should have
                       returned the handlers from any previous items
                       already so we can return this handler
                       immediately */
                    LogAssert(m_blockedList.IsEmpty());
                    unit->SetStatusCode(drainType);
                    unit->DiscardItems();

                    if (m_terminationUnit == unit)
                    {
                        m_terminationUnit = NULL;
                    }
                }
            }
            else if (m_supplierState == SS_Stopped)
            {
                LogAssert(m_availableUnits == 0);

                if (m_supplierEpoch == m_writerEpoch)
                {
                    /* the supplier hasn't yet been started so queue
                       up the unit for when it is */
                    unit->SetStatusCode(RChannelItem_Data);
                    LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0);

                    StartBlocking(unit, syncHandler);
                    unit = NULL;
                }
                else
                {
                    /* the supplier has already shut down so just
                       return this immediately */
                    LogAssert(m_supplierEpoch == m_writerEpoch+1);
                    LogAssert(m_readerTerminationItem != NULL);
                    RChannelItemType drainType =
                        m_readerTerminationItem->GetType();
                    LogAssert(drainType != RChannelItem_MarshalError);
                    LogAssert(m_blockedList.IsEmpty());
                    unit->DiscardItems();
                    unit->SetStatusCode(drainType);

                    if (m_terminationUnit == unit)
                    {
                        m_terminationUnit = NULL;
                    }
                }
            }
            else
            {
                LogAssert(m_supplierState == SS_Running);

                LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0);
                unit->SetStatusCode(RChannelItem_Data);

                if (m_availableUnits == 0)
                {
                    /* we have no spare slots in the FIFO so add the
                       item to the blocked list: this has the
                       side-effect of preventing the handler being
                       returned immediately. */
                    StartBlocking(unit, syncHandler);
                    unit = NULL;
                }
                else
                {
                    LogAssert(m_blockedList.IsEmpty());

                    /* we're ready to send this on to the reader: use
                       the send latch to ensure the ordering is
                       preserved. We will return the handler
                       immediately since the FIFO was not full and it
                       is OK to send more items. */

                    --m_availableUnits;

                    RChannelFifoUnit* sendUnit;
                    if (unit == m_terminationUnit)
                    {
                        /* always block on the termination item to
                           ensure its handler gets delivered last */
                        StartBlocking(unit, syncHandler);
                        unit = NULL;

                        /* cheat by stealing this back off the end of
                           the blocking queue and send it
                           immediately */
                        sendUnit = m_blockedList.CastOut(m_blockedList.
                                                         RemoveTail());

                        /* throw away any spare FIFO units since we
                           won't be writing any more items */
                        m_availableUnits = 0;
                    }
                    else
                    {
                        /* return the handler to the user immediately
                           while also forwarding the unit to the
                           reader */
                        sendUnit = DuplicateUnit(unit, itemArray);
                    }

                    sendList.InsertAsTail(sendList.CastIn(sendUnit));
                    m_sendLatch.AcceptList(&sendList);

                    ++m_outstandingUnits;
                }
            }
        }

        if (unit != NULL)
        {
            LogAssert(unit->GetStatusCode() != RChannelItem_MarshalError);
            returnList.InsertAsTail(returnList.CastIn(unit));
            m_returnLatch.AcceptList(&returnList);
            if (returnList.IsEmpty() && syncHandler != NULL)
            {
                /* another thread is returning the handler for us, so
                   we need to wait for its event */
                syncHandler->UseEvent(m_eventCache.GetEvent(true));
            }
        }
    }

    if (writerHasTerminated)
    {
        LogAssert(sendList.IsEmpty());
        LogAssert(unit != NULL);
    }

    SendUnits(&sendList);

    ReturnHandlers(&returnList);
}
Example #4
0
void RChannelFifoWriter::
    StartSupplier(RChannelBufferPrefetchInfo* prefetchCookie)
{
    ChannelUnitList unblockedList;

    {
        AutoCriticalSection acs(&m_baseDR);

        LogAssert(m_supplierState == SS_Stopped);

        LogAssert(m_writerState != WS_Closed);
        LogAssert(m_availableUnits == 0);
        LogAssert(m_outstandingUnits == 0);

        if (m_writerState == WS_Running)
        {
            m_availableUnits = m_fifoLength;
        }
        else
        {
            if (m_writerState == WS_Draining)
            {
                LogAssert(m_blockedList.IsEmpty() == false);
                m_availableUnits = m_fifoLength;
            }
            else
            {
                LogAssert(m_writerState == WS_Stopped);
                LogAssert(m_blockedList.IsEmpty());
            }
        }

        BOOL bRet = ::ResetEvent(m_supplierDrainEvent);
        LogAssert(bRet != 0);

        m_supplierState = SS_Running;

        while (m_availableUnits > 0 && m_blockedList.IsEmpty() == false)
        {
            --m_availableUnits;
            ++m_outstandingUnits;

            RChannelFifoUnit* blockedUnit =
                m_blockedList.CastOut(m_blockedList.GetHead());

            unblockedList.TransitionToTail(unblockedList.
                                           CastIn(blockedUnit));
        }

        if (m_writerTerminationItem != NULL)
        {
            if (m_terminationUnit == NULL)
            {
                LogAssert(m_writerState == WS_Stopped);
                LogAssert(m_writerEpoch == m_supplierEpoch);
            }
            m_availableUnits = 0;
        }

        m_sendLatch.AcceptList(&unblockedList);
    }

    SendUnits(&unblockedList);
}
Example #5
0
void RChannelFifoNBWriter::
    EnqueueItemArray(RChannelItemArrayRef& itemArrayIn,
                     RChannelItemArrayWriterHandler* handler,
                     SyncHandler* syncHandler)
{
    ChannelUnitList sendList;
    ChannelFifoUnitList returnList;
    bool writerHasTerminated = false;
    RChannelFifoUnit* unit = new RChannelFifoUnit(this);

    RChannelItemArrayRef itemArray;
    /* ensure that the caller no longer holds a reference to this array */
    itemArray.TransferFrom(itemArrayIn);

    LogAssert(itemArray->GetNumberOfItems() > 0);

    {
        AutoCriticalSection acs(&m_baseDR);

        unit->SetPayload(itemArray, handler, RChannelItem_MarshalError);

        LogAssert(m_writerState != WS_Closed);

        writerHasTerminated = CheckForTerminationItem(unit);

        if (writerHasTerminated)
        {
            /* some previous invocation (perhaps is another thread)
               has already sent a termination item so signal that we
               aren't accepting any more items by just returning the
               handler immediately with this status code */
            unit->SetStatusCode(RChannelItem_EndOfStream);
        }
        else
        {
            LogAssert(m_writerState == WS_Running);

            if (m_supplierState == SS_Stopped)
            {
                if (m_supplierEpoch == m_writerEpoch)
                {
                    /* the supplier hasn't started yet so return the
                       handler to the user and queue up the data */
                    unit->SetStatusCode(RChannelItem_Data);

                    RChannelFifoUnit* blockedUnit =
                        DuplicateUnit(unit, itemArray);
                    m_blockedList.
                        InsertAsTail(m_blockedList.CastIn(blockedUnit));
                }
                else
                {
                    /* the supplier has already shut down so just
                       return this immediately */
                    LogAssert(m_supplierEpoch == m_writerEpoch+1);
                    LogAssert(m_readerTerminationItem != NULL);
                    RChannelItemType drainType =
                        m_readerTerminationItem->GetType();
                    LogAssert(drainType != RChannelItem_MarshalError);
                    LogAssert(m_blockedList.IsEmpty());
                    unit->DiscardItems();
                    unit->SetStatusCode(drainType);
                }
            }
            else if (m_supplierState == SS_Draining)
            {
                /* the supplier has sent a drain item, so return the
                   handler to the user with the appropriate code and
                   throw the data away */
                LogAssert(m_supplierEpoch == m_writerEpoch);
                LogAssert(m_readerTerminationItem != NULL);
                RChannelItemType drainType =
                    m_readerTerminationItem->GetType();
                LogAssert(drainType != RChannelItem_MarshalError);
                LogAssert(m_blockedList.IsEmpty());
                unit->DiscardItems();
                unit->SetStatusCode(drainType);
            }
            else if (m_supplierState == SS_Interrupted)
            {
                /* the supplier wants to drain but hasn't yet, so just
                   return the handler to the user and throw the data
                   away */
                LogAssert(m_supplierEpoch == m_writerEpoch);
                LogAssert(m_readerTerminationItem == NULL);
                LogAssert(m_blockedList.IsEmpty());
                unit->DiscardItems();
                unit->SetStatusCode(RChannelItem_Data);
            }
            else
            {
                LogAssert(m_supplierState == SS_Running);

                unit->SetStatusCode(RChannelItem_Data);

                LogAssert(m_blockedList.IsEmpty());

                /* return the handler to the user immediately
                   while also forwarding the unit to the
                   reader */
                RChannelFifoUnit* sendUnit =
                    DuplicateUnit(unit, itemArray);
                sendList.InsertAsTail(sendList.CastIn(sendUnit));
                m_sendLatch.AcceptList(&sendList);

                ++m_outstandingUnits;
            }
        }

        LogAssert(unit->GetStatusCode() != RChannelItem_MarshalError);
        returnList.InsertAsTail(returnList.CastIn(unit));
        m_returnLatch.AcceptList(&returnList);
        if (returnList.IsEmpty() && syncHandler != NULL)
        {
            /* another thread is returning the handler for us, so
               we need to wait for its event */
            syncHandler->UseEvent(m_eventCache.GetEvent(true));
        }
    }

    SendUnits(&sendList);

    ReturnHandlers(&returnList);
}
Example #6
0
File: event.c Project: dawik/aok
void Event(SDL_Event* event)
{
	int mousePosition[2], selected_unit;
	static int keytaps = 0; // Något slags fulhax
    if(drawconsole){
        char legal[] = "abcdefghijklmnopqrstuvwxyzåäö1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ,.-;:_*^~!¤%&/()=?+\\<>|øæ ";
        if(event->type == SDL_KEYUP){
            if(event->key.keysym.sym == SDLK_RETURN){
                if(strlen(console)>0){
                    char buff[PACKETSIZE];
                    strncpy(buff, console ,PACKETSIZE);
                    cmdsend(1,0,client_id,console,NULL);
                }
                drawconsole = false;
                int i;
                for(i=0; i<MESSAGESIZE; i++) console[i] = '\0';
                keytaps=0;
                if(DEBUG) fprintf(stderr,"Chat toggle = FALSE\n");
            }
        } else if(event->type == SDL_KEYDOWN) {
            if(event->key.keysym.sym == SDLK_BACKSPACE){
                int len = strlen(console);
                if(keytaps>0) keytaps--;
                console[len-1 > 0 ? len-1 : 0] = '\0';
            } else {
                int i;
                if(strlen(console)+1 < MESSAGESIZE){
                    for(i=0; i<strlen(legal); i++){
                        if(legal[i] == event->key.keysym.unicode){
                            console[keytaps] = event->key.keysym.unicode;
                            keytaps++;
                            break;
                        }
                    }
                }
            }
        }
    }
    else if(mapmakerOpen) mmEvent(event);
    else if(menuOpen) menuEvent(event);
    else if(startMenuOpen) startMenuEvent(event);
    else //In-game
    {
        switch (event->type)
        {
            case SDL_QUIT:
                running = false;
                break;
            case SDL_KEYDOWN:
                switch (event->key.keysym.sym)
                {
                    case SDLK_ESCAPE:
                        running = false;
                        break;
                    case SDLK_q:
                        running = false;
                        break;
                    case SDLK_F10:
                        offsetflag[0] = 0;
                        offsetflag[1] = 0;
                        altDown = false;
                        tabDown = false;
                        menuOpen = true;
                        break;
                    case SDLK_CAPSLOCK:
                        capsActive = true;
                        break;
                    case SDLK_LEFT:
                        offsetflag[0]=-1;
                        break;
                    case SDLK_RIGHT:
                        offsetflag[0]=1;
                        break;
                    case SDLK_DOWN:
                        offsetflag[1]=1;
                        break;
                    case SDLK_UP:
                        offsetflag[1]=-1;
                        break;
                    case SDLK_m:
                        PlayGameSound(MUSIC);
                        break;
                    case SDLK_LSHIFT:
                    case SDLK_RSHIFT:
                        shiftDown = true;
                        if(DEBUG) fprintf(stderr,"Shift Down\n");
                        break;
                    case SDLK_LALT:
                        altDown = true;
                        if(DEBUG) fprintf(stderr,"Alt Down\n");
                        break;
                    case SDLK_LCTRL:
                    case SDLK_RCTRL:
                        ctrlDown = true;
                        if(DEBUG) fprintf(stderr,"Ctrl Down\n");
                        break;
                    case SDLK_TAB:
                        cmdsend(80,client_id,0," "," ");
                        tabDown = true;
                        if(DEBUG) fprintf(stderr,"TAB Down\n");
                        break;
                    case SDLK_0: //Handles control groups
                    case SDLK_1:
                    case SDLK_2:
                    case SDLK_3:
                    case SDLK_4:
                    case SDLK_5:
                    case SDLK_6:
                    case SDLK_7:
                    case SDLK_8:
                    case SDLK_9:
                        if(ctrlDown)
                        {
                            SetControlGroup(event->key.keysym.sym-48);
                            if(DEBUG)fprintf(stderr,"Setting control group: %i\n",event->key.keysym.sym-48);
                        }
                        else
                        {
                            GetControlGroup(event->key.keysym.sym-48);
                            if(DEBUG)fprintf(stderr,"Getting control group: %i\n",event->key.keysym.sym-48);
                        }
                        break;
                    default:
                        break;
                }
                break;
            case SDL_KEYUP:
                switch (event->key.keysym.sym)
                {
                    case SDLK_RETURN:
                        drawconsole = true;
                        fprintf(stderr, "Chat toggle = TRUE\n");
                        break;
                    case SDLK_LEFT:
                        if(offsetflag[0] == -1) offsetflag[0]=0;
                        break;
                    case SDLK_RIGHT:
                        if(offsetflag[0] == 1) offsetflag[0]=0;
                        break;
                    case SDLK_DOWN:
                        if(offsetflag[1] == 1) offsetflag[1]=0;
                        break;
                    case SDLK_UP:
                        if(offsetflag[1] == -1) offsetflag[1]=0;
                        break;
                    case SDLK_LSHIFT:
                    case SDLK_RSHIFT:
                        shiftDown = false;
                        if(DEBUG) fprintf(stderr,"Shift Up\n");
                        break;
                    case SDLK_LALT:
                        altDown = false;
                        if(DEBUG) fprintf(stderr,"Alt Up\n");
                        break;
                    case SDLK_LCTRL:
                    case SDLK_RCTRL:
                        ctrlDown = false;
                        if(DEBUG) fprintf(stderr,"Ctrl Up\n");
                        break;
                    case SDLK_TAB:
                        tabDown = false;
                        if(DEBUG) fprintf(stderr,"TAB Up\n");
                        break;
                    case SDLK_CAPSLOCK:
                        capsActive = false;
                        break;
                    default:
                        break;
                }
                break;
            case SDL_MOUSEMOTION:
                SDL_GetMouseState(&mousePosition[0],&mousePosition[1]);
                if(   mousePosition[0] < 5 || mousePosition[0] > WINDOWWIDTH-5 //Checks if mouse is close to the screen borders
                   || mousePosition[1] < 5 || mousePosition[1] > WINDOWHEIGHT-5)
                {
                    if(mousePosition[0] < 5) offsetflagmouse[0] = -1; //Sets offset flags according to mouse position
                    if(mousePosition[0] > WINDOWWIDTH-5) offsetflagmouse[0] = 1;
                    if(mousePosition[1] < 5) offsetflagmouse[1] = -1;
                    if(mousePosition[1] > WINDOWHEIGHT-5) offsetflagmouse[1] = 1;
                }
                else //Sets offset flags to 0 if mouse is not close to the borders
                {
                    offsetflagmouse[0] = 0;
                    offsetflagmouse[1] = 0;
                }
                if(scrollDown)
                {
                    SDL_GetMouseState(&mousePosition[0],&mousePosition[1]);
                    if(mousePosition[0] > scrollDownStart[0] + 10) offsetflagscroll[0] = 1;
                    if(mousePosition[0] < scrollDownStart[0] - 10) offsetflagscroll[0] = -1;
                    if(mousePosition[1] > scrollDownStart[1] + 10) offsetflagscroll[1] = 1;
                    if(mousePosition[1] < scrollDownStart[1] - 10) offsetflagscroll[1] = -1;
                }

                if(leftMouseDown)
                {
                    boxEnd[0] = mousePosition[0]+offset[0]*TILEDIAGONAL;
                    boxEnd[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2;
                }
                break;
            case SDL_MOUSEBUTTONDOWN:
                {
                    SDL_GetMouseState(&mousePosition[0],&mousePosition[1]);
                    switch (event->button.button)
                    {
                        case SDL_BUTTON_LEFT:
                            if(showEndgameStatus) showEndgameStatus = false;
                            lastSelectedGroup = -1;
                            if(mousePosition[1] < WINDOWHEIGHT-HUD_HEIGHT) //If the mouse is within the game area
                            {
                                SetSelected(mousePosition);
                                SDL_GetMouseState(&mousePosition[0],&mousePosition[1]);
                                boxStart[0] = mousePosition[0]+offset[0]*TILEDIAGONAL;
                                boxStart[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2;
                                boxEnd[0] = boxStart[0]; //Prevents graphical errors
                                boxEnd[1] = boxStart[1];
                                leftMouseDown = true;
                            }
                            else
                            {
                                hudClick = true;
                                ClickHUDButton(mousePosition);
                            }
                            break;
                        case SDL_BUTTON_RIGHT:
                            if(mousePosition[1] < WINDOWHEIGHT-HUD_HEIGHT) { //If the mouse is within the game area
                                //fprintf(stdout,"RIGHTCLICK\n");
                                selected_unit = SetTarget(mousePosition);
                                SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); //New mouse coordinates as SetTarget manipulates them
                                SendUnits(mousePosition,selected_unit);
/*                                if ( selected_unit == -1 )//Tries to set target
                                {
                                    if ( SetDestination(mousePosition) == true  ) //Only set destination if target set failed
                                    {
                                        if(DEBUG) fprintf(stdout,"Sending selected unit(s) to %i,%i\n",mousePosition[0],mousePosition[1]);
                                    }
                                }
                                else if (unit[selected_unit].owner == client_id) {
                                fprintf(stdout,"Following unit %i\n",selected_unit);
                                }
                                else if (unit[selected_unit].owner != client_id) {
                                fprintf(stdout,"Attacking unit %i\n",selected_unit);
                                }*/
                            }
                            break;
                        case SDL_BUTTON_WHEELUP:
                            zoomSchedueled += 1;
                            break;
                        case SDL_BUTTON_WHEELDOWN:
                            zoomSchedueled -= 1;
                            break;
                        case SDL_BUTTON_MIDDLE:
                            scrollDown = true;
                            SDL_GetMouseState(&scrollDownStart[0],&scrollDownStart[1]);
                            if(DEBUG) fprintf(stderr,"Middle mouse button Down\n");
                            break;
                    }
                }
                break;
            case SDL_MOUSEBUTTONUP:
                {
                    switch (event->button.button)
                    {
                        case SDL_BUTTON_LEFT:
                            if(hudClick)
                            {
                                hudClick = false;
                                break;
                            }
                            leftMouseDown = false;
                            int temp;
                            SDL_GetMouseState(&mousePosition[0],&mousePosition[1]);
                            boxEnd[0] = mousePosition[0]+offset[0]*TILEDIAGONAL;
                            boxEnd[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2;
                            boxDiff[0] = boxStart[0] - boxEnd[0];
                            boxDiff[1] = boxStart[1] - boxEnd[1];
                            if(boxDiff[0] < 0)
                            {
                                boxDiff[0] *= -1;
                            }
                            else
                            {
                                temp = boxStart[0];
                                boxStart[0] = boxEnd[0];
                                boxEnd[0] = temp;
                            }
                            if(boxDiff[1] < 0)
                            {
                                boxDiff[1] *= -1;
                            }
                            else
                            {
                                temp = boxStart[1];
                                boxStart[1] = boxEnd[1];
                                boxEnd[1] = temp;
                            }
                            if(boxDiff[0] > BOX_LIMIT || boxDiff[1] > BOX_LIMIT) SetSelectedGroup(); //Only use the SetSelectedGroup function if the box is large enough
                            break;
                        case SDL_BUTTON_MIDDLE:
                            scrollDown = false;
                            offsetflagscroll[0] = 0;
                            offsetflagscroll[1] = 0;
                            if(DEBUG) fprintf(stderr,"Middle mouse button Up\n");
                            break;
                    }
                }
                break;
            }
        }
}