UnityWebRequest metadata


We could grab things like file size, last-modified timestamp etc, even before downloading the the file.

HTTP Header reference

//We could grab things like file size, last-modified timestamp etc, even before downloading the the file. 
#if UNITY_2017_1_OR_NEWER
 UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
#else
 UnityWebRequest request = UnityWebRequest.GetTexture(url);
#endif
 request.method = "HEAD";
 yield return request.Send();
 bool requestHadError;

#if UNITY_2017_1_OR_NEWER
 requestHadError = request.isNetworkError;
#else
 requestHadError = request.isError;
#endif
if (!requestHadError)
{
 double uploadedTimeStamp = MoreAppsUtils.GetUnixTimestamp(request.GetResponseHeader("Last-Modified"));
}
request.Dispose();
request = null;

Upload File to a PHP server using C#

 <?php
//check whether the folder the exists
if(!(file_exists('Data')))
{
  //create the folder
  mkdir('Data');
  //give permission to the folder
  chmod('Data', 0777);
}

//check whether the file exists
if (file_exists('Data/'. $_FILES["file"]["name"]))
{
   echo $_FILES["file"]["name"] . " is success ";
   move_uploaded_file($_FILES["file"]["tmp_name"],'Data/'. $_FILES["file"]["name"]);
}
?>

//Server.cs
public static void UploadToCloud(string filename = book.xml)
{
    WebClient myWebClient = new WebClient();
    
    try
    {
        byte[] responseArray = myWebClient.UploadFile( Constants.XML_SERVER_PATH + "fileupload.php", "POST", filename);
        
        // Decode and display the response.
        Console.WriteLine("\nResponse Received.The contents of the file uploaded is:\n{0}",
            System.Text.Encoding.ASCII.GetString(responseArray));
    }
    catch (Exception e)
    {
        Console.WriteLine("{0} Exception", e);
    }        
}

Xml Encryption/Dycryption

public class SimpleEncryption
{
    #region Constructor
    public SimpleEncryption(string password)
    {
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        byte[] saltValueBytes = Encoding.UTF8.GetBytes(SaltValue);

        _DeriveBytes = new Rfc2898DeriveBytes(passwordBytes, saltValueBytes, PasswordIterations);
        _InitVectorBytes = Encoding.UTF8.GetBytes(InitVector);
        _KeyBytes = _DeriveBytes.GetBytes(32);
    }
    #endregion

    #region Private Fields
    private readonly Rfc2898DeriveBytes _DeriveBytes;
    private readonly byte[] _InitVectorBytes;
    private readonly byte[] _KeyBytes;
    #endregion

    private const string InitVector = "T=A4rAzu94ez-dra";
    private const int PasswordIterations = 1000; //2;
    private const string SaltValue = "d=?ustAF=UstenAr3B@pRu8=ner5sW&h59_Xe9P2za-eFr2fa&ePHE@ras!a+uc@";

    public string Decrypt(string encryptedText)
    {
        byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
        string plainText;

        RijndaelManaged rijndaelManaged = new RijndaelManaged { Mode = CipherMode.CBC };

        try
        {
            using (ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(_KeyBytes, _InitVectorBytes))
            {
                using (MemoryStream memoryStream = new MemoryStream(encryptedTextBytes))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        //TODO: Need to look into this more. Assuming encrypted text is longer than plain but there is probably a better way
                        byte[] plainTextBytes = new byte[encryptedTextBytes.Length];

                        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                        plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                    }
                }
            }
        }
        catch (CryptographicException exception)
        {
            plainText = string.Empty; // Assume the error is caused by an invalid password
        }

        return plainText;
    }

    public string Encrypt(string plainText)
    {
        string encryptedText;
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        RijndaelManaged rijndaelManaged = new RijndaelManaged {Mode = CipherMode.CBC};

        using (ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor(_KeyBytes, _InitVectorBytes))
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();

                    byte[] cipherTextBytes = memoryStream.ToArray();
                    encryptedText = Convert.ToBase64String(cipherTextBytes);
                }
            }
        }

        return encryptedText;
    }
}

Simple XML Parsing c#

using System.Xml;
using System.Xml.Linq;


//Load string from xml into a list
private static void BuildScenes()
{

XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load("ios_scenes.xml");
  XmlNodeList sceneNode =  xmlDocument.SelectNodes("//Scenes/Scene");
  foreach(XmlNode node in sceneNode)
  {
   string sceneName = node.InnerText;
   levels.Add(sceneName);
   } 

}

//Sample Xml
<?xml version="1.0" encoding="us-ascii"?>
 <Scenes> 
   <Scene>Any data </Scene>
   <Scene>Any data </Scene>
   <Scene>Any data </Scene>
</Scenes>

MethodInfo Reflection to Create a Delegate

MethodInfo actionMethodInfo = typeof(AdvertisementHelper).GetMethod("AdResultCallback", BindingFlags.Static | BindingFlags.NonPublic);
Action<bool> AdResultCallback = (Action<bool>)Delegate.CreateDelegate(typeof(Action<bool>), actionMethodInfo);

Find installed Apps on Android and Start the intent

import android.content.pm.ResolveInfo;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;

Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> pkgAppsList = UnityPlayer.currentActivity.getPackageManager().queryIntentActivities( mainIntent, 0);

Log.d("Deeplink", String.valueOf(pkgAppsList.size()));
for(ResolveInfo info : pkgAppsList)
{
 ActivityInfo activity = info.activityInfo;
 Log.d("Deeplink", String.valueOf(activity.applicationInfo.packageName));
 if(activity.applicationInfo.packageName.contains("your app bundle id"))
 {
              ComponentName name = new ComponentName(activity.applicationInfo.packageName,activity.name);
  Intent i = new Intent(Intent.ACTION_MAIN);

  i.addCategory(Intent.CATEGORY_LAUNCHER);
  i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
  i.setComponent(name);

  UnityPlayer.currentActivity.startActivity(i);
  Log.d("Deeplink", "Launching Intent");
 }
}

Retrive data From a CSV using Python and insert into sql

def begin_import(request_type):
    print '[*] Begin import'
    csv_file = open(csv_file_name, "rb")
    table = csv.DictReader(csv_file)

    try:
        session = Session()
        session_row = FlurryAppMetric()
        for row in table:
            if request_type == "month":
                # Ignore time zone as the current table does not support it
                session_row.date = parse(row["dateTime"]).replace(tzinfo=None)
                session_row.api_key = row["app|apiKey"]
                session_row.country = row["country|iso"]
                session_row.active_users_month = row["activeDevices"]
               
            try:
                session.merge(session_row)
                session.commit()
            except SQLAlchemyError as e:
                print '[*] Failed to merge!' + str(e)
    except SQLAlchemyError as e:
        print '[*] SQLAlchemyError thrown: ' + str(e)
        session.rollback()
        session.close()
    finally:
        session.close()
        csv_file.close()

Truncate c# string

private static string TruncateString(string value, int maxLength)
{
   if (string.IsNullOrEmpty(value))
   {
     return value;
   }
 return value.Length <= maxLength ? value : value.Substring(0, maxLength);
}

Collect Unity Console logs - Used for Global exception catcher


Catch all the engine logs and send it to your native console or have a fancy Unity GUI console


Application.logMessageReceived += (output, stackTrace, logType) => {
            StringBuilder consoleLogs = new StringBuilder();
            consoleLogs.AppendLine("[*] Begin console log information");
            consoleLogs.AppendLine("LogMessage:" + output);
            consoleLogs.AppendLine("StackTrace:" + stackTrace);
            consoleLogs.AppendLine("LogType:" + logType.ToString());
            consoleLogs.AppendLine("[*] End console log information");
            Utils.SendLogsToConsole("Console Log", consoleLogs.ToString());
        };

Resume Orientaion on iOS

NSArray *supportedOrientations = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UISupportedInterfaceOrientations"];
for (NSString *orientation in supportedOrientations) {
    if ([orientation isEqualToString:@"UIInterfaceOrientationPortrait"] ||
        [orientation isEqualToString:@"UIInterfaceOrientationPortraitUpsideDown"]) {
        NSLog(@"Portrait mode!");
        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    } else if ([orientation isEqualToString:@"UIInterfaceOrientationLandscapeLeft"] ||
               [orientation isEqualToString:@"UIInterfaceOrientationLandscapeRight"]) {
        NSLog(@"Landscape mode!");
        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}

GetManagerFromContext: pointer to object of manager ‘(null)’ is NULL (table index 5)

UNITY3D FATAL ERROR ON STARTUP WORKAROUND
.entry-meta
.entry-header
This morning starting up Unity 5.1.0 greeted me with the following message and a blank project selection window (I have unity configured to ask me which project to load on startup)
Fatal error!
GetManagerFromContext: pointer to object of manager ‘(null)’ is NULL (table index 5)
Update
Confirmation from Unity that this is a bug in the updater and they have now disabled this server side checking for versions 5.1.0f3 – 5.1.1f1 so hopefully that’s the last we see of it!
Solution
Many thanks to @Rusty_Bolt on twitter who tweeted to suggest switching WiFi/Internet off which lead me to the following steps. Switching WiFi off would indeed allow unity to start, however after quitting and starting again if WiFi was on (usually is!) it would crash again.
  1. Switch your internet connection off
  2. Load Unity and select a project
  3. Switch your internet connection on
  4. Now within Unity load a new project via File->OpenProject
  5. Quit unity
Hopefully now when you start unity everything is back to normal!
Other things I tried
As part of trying to track this down I tried the following, none of which helped.

  • Delete all unity settings from ~/Library/Preferences
  • Delete my Unity license file from Library/Application Support/PACE Anti-Piracy/License Files see link
  • Moved all of my unity projects to a different location to ensure they were not involved
  • Deleted Unity
  • Installed Unity
Source: http://trusteddevelopments.com/2015/06/26/unity3d-fatal-error-on-startup-workaround/

Install homebrew on Mac OSX

xcode-select --install
 
After that: 
 
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 
Source : https://coolestguidesontheplanet.com/installing-homebrew-os-x-yosemite-10-10-package-manager-unix-apps/

Initialize SqlAlchemy database

def initialize_db(config):
    url = URL(
        config["driver"],
        config["username"],
        config["password"],
        config["hostname"],
        None,
        config["database"],
        {'charset': 'utf8'})

    # hack for sqlite databases
    url = str(url)
    engine = create_engine(url, encoding = config["encoding"], echo = config["echo"])
    return engine

def insert_into_database():
    db = initialize_db(settings.DATABASE_ENGINE)   
    db.echo = False 
    connection = db.connect()
    metadata = MetaData(db)


//Settings.py
//Add your credentials

DATABASE_ENGINE = {
    "driver": "",
    "hostname": "",
    "username": "",
    "password": "",
    "database": "",
    "encoding": "latin1",
    "echo": False
}

Send email using python Script

# pip intsall email
# Don't save the file as email.py, it will create a conflict with the built in system

from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
import smtplib


def send_mail(send_from, send_to, subject, text, files=None,
              server="smtp.gmail.com"):
    assert isinstance(send_to, list)

    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg.attach(MIMEText(text))

    smtp = smtplib.SMTP(server)
    smtp.ehlo()
    smtp.starttls()
    smtp.login("bbmaster@budgestudios.ca", "buildmachine")
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

Using SQL alchemy to create table

def begin_import():
    csv_data = csv.reader(codecs.open(csv_file, 'rb', 'utf-16'), delimiter='\t', quotechar='|')
    column_names = next(csv_data, None)
    try:
        session = Session()

        for row in csv_data:
            row.append(current_platform)
            session_row = ChartboostCampaignAppMetric()
      
            session_row.Date = datetime.datetime.strptime(row[0].strip('"'), "%Y-%m-%d").date()
            session_row.ToCampaignName = row[1]
            session_row.ToCampaignID = row[2]
            session_row.ToAppName = row[3]
            session_row.ToAppID = row[4]
            session_row.ToAppBundle = row[5]
            session_row.FromCampaignName = row[6]
            session_row.FromCampaignID = row[7]
            session_row.FromAppName = row[8]
            session_row.FromAppID = row[9]
            session_row.FromAppBundle = row[10]
            session_row.CampaignType = row[11]
            session_row.Role = row[12]
            session_row.AdType = row[13]
            session_row.Impressions = try_parse_int(row[14])
            session_row.Clicks = try_parse_int(row[15])
            session_row.Installs = try_parse_int(row[16])
            session_row.CTR = try_parse_float(row[17])
            session_row.IR = try_parse_float(row[18])
            session_row.MoneyEarned = try_parse_float(row[19])
            session_row.eCPMEarned = try_parse_float(row[20])
            session_row.MoneySpent = try_parse_float(row[21])
            session_row.eCPMSpent = try_parse_float(row[22])
            session_row.CompletedView = try_parse_int(row[23])
            session_row.Platform = row[24]

            try:
                session.merge(session_row)
           
            except SQLAlchemyError as e:
                log.exception("Failed to merge %s." % (e))

        session.commit()
    except:
        session.rollback()
        session.close()
        raise
    finally:
        session.close()


class ChartboostCampaignAppMetric(Base):
    __tablename__ = 'ChartboostCampaignByApps'

    Date = Column(DateTime, primary_key=True)
    ToCampaignName = Column(String(100))
    ToCampaignID =  Column(String(100), primary_key=True)
    ToAppName = Column(String(100))
    ToAppID =  Column(String(100),primary_key=True)
    ToAppBundle =  Column(String(100))
    FromCampaignName = Column(String(100))
    FromCampaignID =  Column(String(100),primary_key=True)
    FromAppName =  Column(String(100))
    FromAppID =  Column(String(100),primary_key=True)
    FromAppBundle =  Column(String(100))
    CampaignType =  Column(String(100),primary_key=True)
    Role =  Column(String(100),primary_key=True)
    AdType =  Column(String(100),primary_key=True)
    Impressions =  Column(BigInteger(),default = 0)
    Clicks =  Column(BigInteger(),default = 0)
    Installs =  Column(BigInteger(),default = 0)
    CTR =  Column(Numeric(18, 2),default = 0)
    IR =  Column(Numeric(18, 2),default = 0)
    MoneyEarned =  Column(Numeric(18, 2),default = 0)
    eCPMEarned =  Column(Numeric(18, 2),default = 0)
    MoneySpent =  Column(Numeric(18, 2),default = 0)
    eCPMSpent =  Column(Numeric(18, 2),default = 0)
    CompletedView =  Column(BigInteger(),default = 0)
    Platform =  Column(String(100),primary_key=True)

Python script to request url and download csv and parse using CSV reader

jobID_url = 'https://analytics.chartboost.com/v3/metrics/jobs/'
campaign_by_apps_url = 'https://analytics.chartboost.com/v3/metrics/campaign?'
csv_file = 'campaign_by_apps.csv'

def initialize_api_request(star_date, end_date, appid, api_token, platform):
    global current_platform
    current_platform = platform  

    platform = urllib.quote(platform)
    cleanup()
    print '[*] Initializing API request for chartboost campaign by apps for platform %s' % current_platform
    request_url = campaign_by_apps_url + 'dateMin='+ str(star_date) +'&dateMax=' + str(end_date) + '&groupBy=app&platform=' + platform + '&userId=' + appid +'&userSignature=' + api_token
    try:
        response = urllib2.urlopen(request_url)
    except urllib2.HTTPError as e:
        print '[*] Connection failed because of error code : ' + str(e.code) + ', Retrying Connection...'
        time.sleep(10)
        initialize_api_request(star_date, end_date, appid, api_token, current_platform)
    except urllib2.URLError as e:
        print '[*] Connection failed because of URLError : ' + str(e)
    else:
        response_json = json.loads(response.read())
        print '[*] Job ID successfully obtained!'
        jobID = response_json["jobId"]
        download_csv_file(jobID)

def download_csv_file(jobID):
    # It may take upto 1 minute for the file to be available
    print '[*] Starting download...'
    time.sleep(60)

    csv_dowload_url = jobID_url + jobID
    try:
        response = urllib2.urlopen(csv_dowload_url)
    except urllib2.HTTPError as e:
        print '[*] Download failed because of error code : ' + str(e.code) + ', Retrying download...'
        time.sleep(10)
        cleanup()
        download_csv_file(jobID)
    except urllib2.URLError as e:
        print '[*] Download failed because of URLError : ' + str(e)
    else:
        with open(csv_file, 'wb') as f:
            f.write(response.read())
        print '[*] Download successful!'
        with open(csv_file, 'rb') as csvfile:
            try:
                dialect = csv.Sniffer().sniff(csvfile.read(1024))
                csvfile.seek(0)
                csvfile.close()
                print '[*] CSV file is valid'
                begin_import()
            except Exception, e:   
                print '[*] CSV file is invalid because: ' + str(e) + ', Retrying download...'
                cleanup()
                download_csv_file(jobID)

def cleanup():
    print '[*] Begin cleanup'
    if os.path.isfile(csv_file):
        print '[*] CSV file exist, destroying it'
        os.remove(csv_file)
    else:
        print '[*] CSV not found, attempting to fetch a new one from the server'

def begin_import():
    csv_data = csv.reader(codecs.open(csv_file, 'rb', 'utf-16'), delimiter='\t', quotechar='|')
    column_names = next(csv_data, None) #skip the first row as they are heading
    for row in csv_data:
           # Add to database

Merge two SQL tables without duplicate

INSERT INTO BBB(id, timestamp, mycount, col1, col2, col3, etc.)
SELECT id, timestamp, mycount, col1, col2, col3, etc.
   FROM AAA
   WHERE
       NOT EXISTS(SELECT NULL FROM BBB oldb WHERE
          oldb.col1 = AAA.col1
          AND oldb.col2 = AAA.col2
          AND oldb.col3 = AAA.col3

       )

Add columns as needed to the NOT EXISTS clause.

Source: http://stackoverflow.com/questions/9747337/merging-content-of-two-tables-without-duplicating-content

Python Progress bar

import urllib2, sys

//Progress.py

def chunk_report(bytes_so_far, chunk_size, total_size):
   percent = float(bytes_so_far) / total_size
   percent = round(percent*100, 2)
   sys.stdout.write("Downloaded %d of %d bytes (%0.2f%%)\r" %
       (bytes_so_far, total_size, percent))

   if bytes_so_far >= total_size:
      sys.stdout.write('\n')

def chunk_read(response, chunk_size=8192, report_hook=None):
   total_size = response.info().getheader('Content-Length').strip()
   total_size = int(total_size)
   bytes_so_far = 0
   data = []

   while 1:
      chunk = response.read(chunk_size)
      bytes_so_far += len(chunk)

      if not chunk:
         break

      data += chunk
      if report_hook:
         report_hook(bytes_so_far, chunk_size, total_size)

   return "".join(data)

if __name__ == '__main__':
    site= "http://download.thinkbroadband.com/50MB.zip"
    hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'en-US,en;q=0.8',
       'Connection': 'keep-alive'}
    req = urllib2.Request(site, headers=hdr)
    response = urllib2.urlopen(req);
    chunk_read(response, report_hook=chunk_report)
    print "done"

Source : http://stackoverflow.com/questions/5783517/downloading-progress-bar-urllib2-python

Unity 3D Convert binary data to image using PHP - Upload using WWWForm

Photo.php:
<?php
if ((($_FILES["file"]["type"] == "image/png") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 20000000000)) { if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "
"; } else { echo "Upload: " . $_FILES["file"]["name"] . "
"; echo "Type: " . $_FILES["file"]["type"] . "
"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb
"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "
";
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
}
}
} else { echo "Invalid file"; }
?>
Source

Unity Side:
private IEnumerator UploadToPublicServer(byte[] data)
{
    WWWForm form = new WWWForm();
    form.AddBinaryData("file", data, "screenShot.png");

    WWW www = new WWW("http://localhost/PhotoTest/photo.php", form);
    yield return www;

    if (www.error == null)
    {
        Debug.Log("upload done :" + www.text);
    }
    else
    {
        Debug.Log("Error during upload: " + www.error);
    }
}

iOS UIbutton overlay

-(void) viewDidAppear:(BOOL)animated    {
   
    //*** Example***

    //UIButton *pauseImg;
    //pauseImg =[self drawImage:pauseIcon inImage:pauseImg];
      

}

-(UIImage*) drawImage:(UIImage*) fgImage
              inImage:(UIImage*) bgImage
{
    UIGraphicsBeginImageContextWithOptions(bgImage.size, FALSE, 0.0);
    [bgImage drawInRect:CGRectMake( 0, 0, bgImage.size.width, bgImage.size.height)];
    [fgImage drawInRect:CGRectMake( 0, 0, fgImage.size.width, fgImage.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}