def readUdpPackets(udpSocket):
    print "--- reading UDP packets"

    # all received packet ids
    receivedIds = set();

    while udpKeepRunning:
        try:
            data, addr = udpSocket.recvfrom(2048)
        except:
            break

        print "--- read %d bytes from %s:%d" % (len(data), addr[0], addr[1])

        (packetType,) = struct.unpack_from('>B', data, 0)

        if packetType == packet.Packet.UDP_PONG:
            (oldTime,) = struct.unpack_from('>L', data, struct.calcsize('>B'))
            now = datetime.datetime.now()
            milliseconds = (now.day * 24 * 60 * 60 + now.second) * 1000 + now.microsecond / 1000
            print "--- pong received, time: %d ms" % (milliseconds - oldTime)

        elif packetType == packet.Packet.UDP_DATA_START_ACTION:
            print "--- start action, starting simulator"
            # create the simulator and start it
            global simulator
            simulator = Simulator( units, udpSocket, udpAddress )
            simulator.start()

        elif packetType == packet.Packet.UDP_DATA:
            (packetType, subPacketType, packetId,) = struct.unpack_from('>BBI', data, 0)
            offset = struct.calcsize('>BBL')
            print "--- UDP data type %d, packet id: %d, total bytes: %d" % (subPacketType, packetId, len(data))

            # already received this?
            if packetId in receivedIds:
                # skip this
                print "--- ignoring duplicate packet %d" % packetId
                continue

            receivedIds.add( packetId )

            if subPacketType == packet.Packet.UDP_DATA_MISSION:
                (unitCount,) = struct.unpack_from('>B', data, offset)
                offset += struct.calcsize('>B')
                print "--- mission data, %d units" % unitCount

                for count in range( unitCount ):
                    (unitId, missionType, ) = struct.unpack_from('>hB', data, offset)
                    offset += struct.calcsize('>hB')
                    print "--- unit %d, mission %d" % (unitId, missionType )

            elif subPacketType == packet.Packet.UDP_DATA_UNIT_STATS:
                (unitCount,) = struct.unpack_from('>B', data, offset)
                offset += struct.calcsize('>B')
                print "--- unit stats, %d units" % unitCount

                for count in range( unitCount ):
                    (unitId, men, mode, missionType, morale, fatigue, ammo, x, y, facing, ) = struct.unpack_from('>hBBBBBBhhh', data, offset)
                    offset += struct.calcsize('>hBBBBBBhhh')

                    # convert some data back
                    x /= 10
                    y /= 10
                    facing /= 10

                    print "--- unit %d, men: %d, mode: %d, mission %d, morale: %d, fatigue: %d, ammo: %d pos: %d,%d, facing: %d" \
                          % (unitId, men, mode, missionType, morale, fatigue, ammo, x, y, facing)

            elif subPacketType == packet.Packet.UDP_DATA_FIRE:
                (attackerId, x, y, ) = struct.unpack_from('>hhh', data, offset)
                offset += struct.calcsize('>hhh')
                x /= 10
                y /= 10

                # any targets left?
                if offset == len(data):
                    print "--- smoke, %d fires smoke at %d,%d" % (attackerId, x, y )
                else:
                    (targetCount, ) = struct.unpack_from('>B', data, offset)
                    offset += struct.calcsize('>B')
                    print "--- fire, %d fires at %d,%d, hitting %d units" % (attackerId, x, y, targetCount )

                    for count in range( targetCount ):
                        (targetId, casualties, type, targetMoraleChange ) = struct.unpack_from('>hBBh', data, offset)
                        offset += struct.calcsize('>hBBh')
                        targetMoraleChange /= 10.0
                        print "    target %d lost %d men, type: %d, target morale: %.1f" % (targetId, casualties, type, targetMoraleChange)
                        for unit in units:
                            if unit.id == targetId:
                                unit.men = max( 0, unit.men - casualties )
                                unit.morale = max( 0, unit.morale - targetMoraleChange )

            elif subPacketType == packet.Packet.UDP_DATA_MELEE:
                (attackerId, targetId, missionType, casualties, targetMoraleChange ) = struct.unpack_from('>hhBBh', data, offset)
                offset += struct.calcsize('>hhBBh')
                targetMoraleChange /= 10.0
                print "    %d melees with %d, target lost %d men, type: %d, target morale: %.1f" % (attackerId, targetId, casualties, type, targetMoraleChange)
                for unit in units:
                    if unit.id == targetId:
                        unit.mission = missionType
                        unit.morale = max( 0, unit.morale - targetMoraleChange )

            elif subPacketType == packet.Packet.UDP_DATA_SET_MISSION:
                (unitId, missionType ) = struct.unpack_from('>hB', data, offset)
                offset += struct.calcsize('>hB')
                print "    %d gets mission %d" % (unitId, missionType)
                for unit in units:
                    if unit.id == unitId:
                        unit.mission = missionType

            elif subPacketType == packet.Packet.UDP_DATA_PLAYER_PING:
                (ms, ) = struct.unpack_from('>L', data, offset)
                offset += struct.calcsize('>L')
                print "--- player ping, their time: %d, sending response" % ms
                udpSocket.sendto(packet.UdpPlayerPongPacket( ms, simulator.getPacketId()).message, udpAddress)

            elif subPacketType == packet.Packet.UDP_DATA_SMOKE:
                (smokeCount,  ) = struct.unpack_from('>h', data, offset)
                offset += struct.calcsize('>h')
                print "--- got data for %d smokes" % smokeCount
                for count in range( smokeCount ):
                    (x, y, opacity, ) = struct.unpack_from('>hhB', data, offset)
                    offset += struct.calcsize('>hhB')
                    x /= 10
                    y /= 10
                    print "--- smoke %d at %d,%d, opacity: %d" % (count, x, y, opacity)


    print "--- UDP handler stopped"