Tiled2Unity – Using normal maps for your tiled projects

I needed to use normal maps to my Tiled project with Tiled2Unity and this was not support by default. So I did some script changes to make this happen. Below is the instruction how to use the new code changes.

How to use Ti led with Tiled2Unity to attach Normal Maps to your Tiled project:

  • Add a new map property named “UseNormalMap” and assign the value 1 to it. This will indicate to the script in unity that a normal map is to searched and applied to the project once exported from Tiled2Unity.

tiled2Unitynormalmapproperties

tiled2unityNormalMapProperty

  • Next add you normal map texture to the Tiled project, make sure that the normal map texture file has the following characters just before the file extension: _n, example: hyptosis_til-art-batch-2_n.png. This will tell the importer code which texture file is the normal map file. So it is the same file name as the original texture file but with the _n characters. Then add a new layer and name it “NormalMapLayer”. IMPORTANT: Add some tiles from the normal map texture to the layer. This is so that the normal map texture is exported to Unity. If this is not done the normal map texture is not exported by the tool Tiled2Unity.tiled2UnityNormalMapLayer
  • After this simply do what you would normally do to export your tiled project to Unity using Tiled2Unity. This of course implies that you have the code changes which support this new feature for normal maps.
  • NOTICE: There is a new shader called TextureTintSnapNormal which is used for normal mapping.

My changes to Tiled2Unity Scripts for Unity: https://github.com/lionadi/Tiled2Unity/tree/master/unity/Tiled2Unity/Scripts/Editor

And the custom shader: https://github.com/lionadi/Tiled2Unity/tree/master/unity/Tiled2Unity/Shaders

Original project: http://www.seanba.com/tiled2unity

Tiled project: http://www.mapeditor.org/

 

Normal tools for 2D art:

https://www.codeandweb.com/spriteilluminator

http://www.2deegameart.com/p/sprite-dlight.html

http://www.snakehillgames.com/spritelamp/

http://crazybump.com/

https://github.com/spritebuilder/NormalMixer

O365 CSOM – Client Side Object Model examples

Here are some examples on how to use CSOM with O365:

This is Microsofts’ link on the matter for more examples:

https://msdn.microsoft.com/en-us/library/ff798388.aspx

 

Remove SiteCollection


 var tenantAdminUri = new Uri(tenantAdminUrl);
 string realm = TokenHelper.GetRealmFromTargetUrl(tenantAdminUri);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, tenantAdminUri.Authority, realm).AccessToken;
 using (var tenantContext = TokenHelper.GetClientContextWithAccessToken(tenantAdminUri.ToString(), token))
 {
 // Set the time out as high as possible
 tenantContext.RequestTimeout = int.MaxValue;

 var tenant = new Tenant(tenantContext);

 //start the SPO operation to create the site
 SpoOperation op = tenant.RemoveSite(webUrl);
 tenantContext.Load(op, i => i.IsComplete);
 tenantContext.RequestTimeout = int.MaxValue;
 tenantContext.ExecuteQuery();

 while (!op.IsComplete)
 {
 Console.WriteLine("Waiting 30 seconds site to be provisioned");
 //wait 30seconds and try again
 System.Threading.Thread.Sleep(30000);
 op.RefreshLoad();
 tenantContext.ExecuteQuery();
 }
 }

 Updating a list item

</pre>
List list = ctx.Web.Lists.GetByTitle(ConfigurationManager.AppSettings["SiteCollectionRequests_List"]);
ListItem listItem = list.GetItemById(id);
ctx.Load(listItem);
ctx.ExecuteQuery();

statusMessage += "Your message";
listItem["StatusMessage"] = statusMessage;
listItem.Update();
list.Update();
ctx.Web.Update();
ctx.ExecuteQuery();
<pre>

Adding a new item to a list


List list = ctx.Web.Lists.GetByTitle(ConfigurationManager.AppSettings["SiteCollectionRequests_LogList"]);

 ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
 ListItem newItem = list.AddItem(itemCreateInfo);
 newItem["Title"] = title;
 newItem["url"] = workspaceURL;

 XmlSerializer xs = new XmlSerializer(typeof(WorkspacePrivileges));
 StringWriter sww = new StringWriter();
 XmlWriter writer = XmlWriter.Create(sww);
 xs.Serialize(writer, workspacePrivileges);
 String aaa = sww.ToString();

 newItem["my text field"] = sww.ToString();
 newItem.Update();
 ctx.ExecuteQuery();

Change Workspace Privileges To Read Only


Uri siteUrl = new Uri(workspaceURL);
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUrl);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUrl.Authority, realm).AccessToken;
 using (var ctxWorkspace = TokenHelper.GetClientContextWithAccessToken(siteUrl.ToString(), token))
 {
 Web currentWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(currentWeb);

 UserCollection webUsers = currentWeb.SiteUsers;
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();
 List<String> usersToAddReadOnlyRights = new List<string>();

 foreach(User user in webUsers)
 {
 if (user.LoginName.ToLowerInvariant().Contains("membership"))
 {
 if (!user.IsSiteAdmin)
 {
 webUsers.RemoveById(user.Id);
 usersToAddReadOnlyRights.Add(user.LoginName);
 }
 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();

 Group visitorGroup = ctxWorkspace.Web.SiteGroups.GetByName(ctxWorkspace.Web.Title + ConfigurationManager.AppSettings["WorkspaceVisitors"]);
 ctxWorkspace.Load(currentWeb);
 ctxWorkspace.Load(visitorGroup);
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();
 foreach (String user in usersToAddReadOnlyRights)
 {
 String[] userLoginNameArray = user.Split('|');
 if(userLoginNameArray != null && userLoginNameArray.Length > 1)
 {
 UserCreationInformation userInfo = new UserCreationInformation();
 userInfo.LoginName = userLoginNameArray[2];
 currentWeb.AddUserToGroup(visitorGroup, userLoginNameArray[2]);

 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();

Remove Workspace users privileges And deny Search Indexing on lists


Uri siteUrl = new Uri(workspaceURL);
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUrl);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUrl.Authority, realm).AccessToken;
 using (var ctxWorkspace = TokenHelper.GetClientContextWithAccessToken(siteUrl.ToString(), token))
 {

 Web currentWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(currentWeb);
 ListCollection lists = ctxWorkspace.Web.Lists;
 ctxWorkspace.Load(lists);
 UserCollection webUsers = currentWeb.SiteUsers;
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();

 foreach (List list in lists)
 {
 list.NoCrawl = true;
 list.Update();
 }

 foreach (User user in webUsers)
 {
 if (user.LoginName.ToLowerInvariant().Contains("membership"))
 {
 if (!user.IsSiteAdmin)
 {
 webUsers.RemoveById(user.Id);
 }
 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();

Office 365( O365 ) – Client application registration, authentication and authorization

OK,

I am currently working on a client side application (console app) that needs to connect to a O365 site and do some stuff with CSOM.

In this post I will write some basic things you need to do in order to achieve a connection to an O365 site. In my case I am working with a console app but this can be a powershell app also.

At first I recommend you look at this piece of code which you need to use to achieve the communication and authentication with O365:

https://github.com/OfficeDev/SharePoint-Power-Hour-Code-Samples/blob/master/SP.SiteCreatorWeb/TokenHelper.cs

https://github.com/OfficeDev/SharePoint-Power-Hour-Code-Samples

A basic C# code to connecto O365 and do get a list and its items would look like this:


Uri siteUri = new Uri(ConfigurationManager.AppSettings["SiteCollectionRequests_SiteUrl"]);

 //Get the realm for the URL
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);

 //Get the access token for the URL.
 //Requires this app to be registered with the tenant
 string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUri.Authority, realm).AccessToken;

 //Get client context with access token
 using (var ctx = TokenHelper.GetClientContextWithAccessToken(siteUri.ToString(), accessToken))
 {

 // Set the time out as high as possible
 ctx.RequestTimeout = int.MaxValue;

 List list = ctx.Web.Lists.GetByTitle(ConfigurationManager.AppSettings["SiteCollectionRequests_List"]);
 CamlQuery camlQuery = new CamlQuery();
 camlQuery.ViewXml = "your CAML query here";
 ListItemCollection listItems = list.GetItems(camlQuery);
 ctx.Load(listItems);
 ctx.ExecuteQuery();

 var itemsCount = listItems.Count;

So before you can use your code you need to do two things in your target site:

  1. Register you client side app. This basically means that in your app config you need to set a clientID and a client secret. Without these values no proper authentication and authorization can done.
    1. Register you app in O365 by using the following URL and replacing the hostname and adding your target site: http://<SharePointWebsite>/_layouts/15/AppRegNew.aspx
  2. After you register the app you need to need to specify in a target site what kind of privileges the app has. In the code sample above you would need to specify at least read rights.
    1. To provide privileges the following url: http://<SharePointWebsite>/_layouts/15/AppInv.aspx
    2. Notice that for this step you need to provide a XML describing the privileges request. The simples way for me was to start up Visual Studio, create an app and define the rights request through the GUI and copy & pasting the XML from the AppMenifest.xml. It would look something like this:
      1. <AppPermissionRequests AllowAppOnlyPolicy=”true”>
        <AppPermissionRequest Scope=”http://sharepoint/content/sitecollection/web/list&#8221; Right=”FullControl” />
        </AppPermissionRequests>

Also the last thing which you need to check is to have a proper configurations in the app.config(if you are using an console app):


<appSettings>
 <add key="ClientId" value="client id obtained after registration" />
 <add key="ClientSecret" value="client secrect after registration" />
 <add key="SiteCollectionRequests_SiteUrl" value="yoursiteurl"/>
 <add key="SiteCollectionRequests_List" value="listname" />

 </appSettings>

Also notice that the ClientId and the ClientSecret have to be provided in the app.config for the TokenHelper.cs class to work. The class will search for these settings values automatically.

Additional help here: http://blog.vgrem.com/2015/01/27/consuming-the-sharepoint-online-rest-api-from-powershell-part-2/

https://msdn.microsoft.com/en-US/library/fp142383.aspx

https://msdn.microsoft.com/library/fp179892(office.15).aspx

https://msdn.microsoft.com/en-us/library/office/fp179912.aspx#BasicOps_SPListItemTasks

Record center problems with document library forms with custom content types and redirection rules

The problem is as follows to make it happen:

  1. You are having a custom document library created
  2. You are using a feature to assign a custom content type
  3. The library where the feature is assigning the content type has a redirection rule

If the above are true then what happened in my case was that the document library suddenly had in the New and Edit form content types which where not assigned to the document library but used in the redirection rules for the record center.

The only solution I found was to temporarily disable(delete) the redirection rules and re-activate my feature, well the library was a mess so I had to re-create it again.

SQLite Entity Data Model (EDMX) with Entity Framework – Guide

This was a bit tricky for me but these are the steps I took for Visual Studio 2013 Community Edition. Notice that the order is important, especially you should not create the Visual Studio project before the SQLite conenction in Server Explorer is established. For some reason existing VS project wont’t recognize the connection, well at least in my environement.

  1. Download the proper SQLite setup bundle based on your criteria in your environment: http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
    1. You Visual Studio version
    2. Your Visual Studio target CPU 32bit or 64bit
    3. Your .NET version which you wish to use
  2. Install the setup bundle
    1. Make sure to enable Visual Studio integration and GAC registration during installation.
  3. Once installed open Visual Studio and Server Explorer
  4. From here you should see a new data source named System.Data.SQLite Database File when you create a new connection
  5. In the next windows select your SQLite database file and press OK.
  6. After this your should have a valid connection to your SQLite database file
  7. Next create a new Visual Studio Project.
  8. Add new Nuget Packages
    1. Entity Framework
    2. System.Data.SQLite (x86/x64)
  9. You could build your project at this stage.
  10. After all these steps your should be able to generate an Entity Data Model on your SQLite database based on the Server Explorer connection

 

Other sources of information:

http://erikej.blogspot.fi/2014/11/using-sqlite-with-entity-framework-6.html

https://visualstudiogallery.msdn.microsoft.com/0e313dfd-be80-4afb-b5e9-6e74d369f7a1

Errors with SharePoint: SharePoint: urlOfFile Parameter name: Specified value is not supported for the urlOfFile parameter

This error around the web is defined as a missing document template. This is true but there is a more bizare situation in which I ran into.

According to SharePoint I had a proper document template assigned to the content type yet I got this error and it messed up my content hub workings. I could not publish updates of the content type to other locations.

The fix: I simply added a new document template to the content type, re-published to content type and it worked.