Search Unity

Map Magic World Generator - a node based procedural and infinite game map tool

Discussion in 'Assets and Asset Store' started by Wright, Mar 10, 2016.

  1. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Thanks for the reply. I have the script and that seems to be working fine. It was more syncing the Microsplat texture array with the Map Magic Texture node.
     
  2. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Can't promise it soon, but I will look into MicroSplat integration since there's pretty much demand for it.
     
    kepesh, Flurgle, mmaclaurin and 2 others like this.
  3. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Thanks, much appreciated. :)
     
  4. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    I use mircosplat just fine. It's been a while, but I think one of the changes I had to make was to force textures to be the same and in the same order for every terrain. If I remember correctly MM cuts out any textures that aren't actually showing up on a terrain, for example if there are no beaches it won't both to add the sand texture to it. This confuses MicroSplat though as it wants them to be the same at all times.

    I commented out these lines at around 500 in OutputGenerators.cs:
    Code (CSharp):
    1.             /*
    2.             //optimizing matrices list if they are not used
    3.             for (int i = matrices.Count - 1; i >= 0; i--)
    4.                 if (opacities[i] < 0.001f || matrices[i].IsEmpty() || (biomeMasks[i] != null && biomeMasks[i].IsEmpty()))
    5.                 { prototypesList.RemoveAt(i); opacities.RemoveAt(i); matrices.RemoveAt(i); biomeMasks.RemoveAt(i); }
    6.             */
    That's really just to ensure that the right number is on there though and that they are in the right order. I don't think MicroSplat actual uses the textures on the terrain, nor from the MM output textures. Setting up the MM output node is step 1, but it's just for design purposes. Step 2 is to import to MS from a terrain to create a prototype or whatever they are called. Then you only need to assign that to your terrains in runtime with the script. I don't think it actually looks at the textures, it just assumes an order for example 1-4. So long as MM isn't mixing up that order and your MS assignment script is working properly it should work.
     
  5. ftejada

    ftejada

    Joined:
    Jul 1, 2015
    Posts:
    695
    Hi @Wright !!!
    The Integration with MegaSplat was already?

    Regards
     
  6. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Thanks for the reply. That's pretty much the workflow I have in place at the moment. It gets hard to maintain, especially if you have multiple terrains, multiple biomes and 32 textures and you're prototyping with a lot of changes. Looking forward to a seamless integration. :)

    @Wright On that, it would be nice to be able to accommodate the Texture Clusters, Advanced Details and Global Texturing modules in the integration in some way. I may be asking too much. ;)
     
  7. Hazkin

    Hazkin

    Joined:
    Sep 11, 2012
    Posts:
    3
    I had the same issue. This will reproduce only on .Net 4.x and non-US locales, like German, Ukrainian etc. and I make some solution to fix that, maybe this will help someone.

    Main wail in a coma separator

    *EDIT: Source code taken from MM 1.9.4

    CustomSerialization:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Reflection;
    5. using System.Xml.Serialization;
    6. using System.IO;
    7. using System;
    8. using System.Globalization;
    9.  
    10. namespace MapMagic
    11. {
    12.  
    13.     public static class CustomSerialization
    14.     {
    15.         public const char Separator = ';';
    16.         public interface IStruct
    17.         {
    18.             string Encode ();
    19.             void Decode (string[] lineMembers);
    20.         }
    21.  
    22.         public interface IStructLink
    23.         {
    24.             string Encode (Func<object,int> writeClass);
    25.             void Decode (string[] lineMembers, System.Func<int,object> readClass);
    26.         }
    27.  
    28.         public static Type GetStandardAssembliesType (string s)
    29.         {
    30.             if (s.StartsWith("Plugins.")) s = s.Replace("Plugins", typeof(CustomSerialization).Namespace);
    31.             Type type = Type.GetType(s);
    32.             if (type == null) type = Type.GetType(s + ", UnityEngine");
    33.             if (type == null) type = Type.GetType(s + ", Assembly-CSharp-Editor"); //trying to load from editor assembly
    34.             if (type == null) type = Type.GetType(s + ", Assembly-CSharp"); //or from non-editor
    35.  
    36.             if (type == null) //lastly trying to load type from plugins
    37.             {
    38.                 if (s.StartsWith("MapMagic")) s = s.Replace("MapMagic", "Plugins");
    39.                 if (s.StartsWith("Voxeland")) s = s.Replace("Voxeland", "Plugins");
    40.              
    41.                 type = Type.GetType(s);
    42.                 if (type == null) type = Type.GetType(s + ", UnityEngine");
    43.                 if (type == null) type = Type.GetType(s + ", Assembly-CSharp-Editor"); //trying to load from editor assembly
    44.                 if (type == null) type = Type.GetType(s + ", Assembly-CSharp"); //or from non-editor
    45.             }
    46.  
    47.             return type;
    48.         }
    49.  
    50.  
    51.         private struct Value
    52.         {
    53.             public string name;
    54.             public Type type;
    55.             public object obj;
    56.         }
    57.  
    58.         private static IEnumerable<Value> Values (object obj)
    59.         {
    60.             Type objType = obj.GetType();
    61.  
    62.             if (objType.IsArray)
    63.             {
    64.                 Type elementType = objType.GetElementType();
    65.                 Array array = (Array)obj;
    66.  
    67.                 //simple array
    68.                 if (elementType.IsPrimitive)
    69.                     yield return new Value() { name="items", type=objType, obj=array };
    70.  
    71.                 //class array
    72.         //        else if (elementType.IsClass && !elementType.IsValueType)
    73.         //            yield return new Value() { name="links", type=objType, obj=array, classArray=true };
    74.              
    75.                 //other arrays
    76.                 else
    77.                     for (int i=0; i<array.Length; i++) yield return new Value() { name="item"+i, type=elementType, obj=array.GetValue(i) };
    78.             }
    79.  
    80.             else if (objType.IsSubclassOf(typeof(UnityEngine.Object)))
    81.             {
    82.                 yield return new Value { name="Object", type=objType, obj=obj };
    83.             }
    84.  
    85.             else
    86.             {
    87.                 foreach (FieldInfo field in objType.UsableFields(includeStatic:true))
    88.                     yield return new Value { name=field.Name, type=field.FieldType, obj=field.GetValue(obj) };
    89.  
    90.                 foreach (PropertyInfo prop in objType.UsableProperties())
    91.                     yield return new Value { name=prop.Name, type=prop.PropertyType, obj=prop.GetValue(obj,null) };
    92.             }
    93.         }
    94.  
    95.  
    96.         public static int WriteClass (object obj, List<string> classes, List<UnityEngine.Object> objects, List<float> floats, List<object> references)
    97.         {
    98.             //cheking if this object was already saved
    99.             if (references.Contains(obj)) return references.IndexOf(obj);
    100.  
    101.             //obj type
    102.             System.Type objType = obj.GetType();
    103.             System.Type elementType = objType.IsArray? objType.GetElementType() : null;
    104.             string objTypeName = objType.ToString();
    105.  
    106.             //reserving a place in array
    107.             int slotNum = classes.Count;
    108.             classes.Add(null);
    109.  
    110.             //adding to references
    111.             for (int i=references.Count; i<classes.Count; i++) references.Add(null); //references count should be equal to classes length
    112.             references[slotNum] = obj;
    113.      
    114.             //writing
    115.             StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
    116.  
    117.             //header
    118.             writer.Write("<" + objTypeName);
    119.             if (objType.IsArray) writer.Write(" length=" + ((Array)obj).Length);
    120.             writer.WriteLine(">");
    121.  
    122.             //values
    123.             foreach (Value val in Values(obj))
    124.             {
    125.                 //primitive
    126.                 if (val.type.IsPrimitive)
    127.                 {
    128.                     if (val.type == typeof(float))
    129.                     {
    130.                         var f = (float)val.obj;
    131.                         var fValue = InvariantFloat(f);
    132.                         var line = string.Format("\t<{0} type={1} value={2}/>" ,val.name, val.type, fValue);
    133.                         writer.WriteLine(line);
    134.                     }
    135.                     else if (val.type == typeof(double))
    136.                     {
    137.                         var d = (double)val.obj;
    138.                         var dValue = InvariantDouble(d);
    139.                         var line = string.Format("\t<{0} type={1} value={2}/>", val.name, val.type, dValue);
    140.                         writer.WriteLine(line);
    141.                     }
    142.                     else
    143.                     {
    144.                         writer.WriteLine("\t<" + val.name + " type=" + val.type + " value=" + val.obj + "/>");
    145.                     }
    146.                 }
    147.  
    148.                 //null
    149.                 else if (val.obj == null)
    150.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " null/>");
    151.  
    152.                 //string
    153.                 else if (val.type==typeof(string))
    154.                 {
    155.                     string str = (string)val.obj;
    156.                     str = str.Replace("\n", "\\n");
    157.                     str = str.Replace(" ", "\\_");
    158.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " value=" + str + "/>"); //same as primitive, but after null
    159.                 }
    160.  
    161.                 //custom struct
    162.                 else if (typeof(IStruct).IsAssignableFrom(val.type))
    163.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " " + ((IStruct)val.obj).Encode() + "/>");
    164.  
    165.                 //custom struct with links
    166.                 else if (typeof(IStructLink).IsAssignableFrom(val.type))
    167.                 {
    168.                     Func<object, int> getLinkFn = delegate(object linkObj) { return WriteClass(linkObj, classes, objects, floats, references); };
    169.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " " + ((IStructLink)val.obj).Encode( getLinkFn ) + "/>");
    170.                 }
    171.  
    172.                 //float array
    173.                 else if (objType == typeof(float[])) //note that obj should be used here, not val.obj
    174.                 {
    175.                     float[] array = (float[])obj;
    176.                     writer.WriteLine("\t<items type=" + val.type + " start=" + floats.Count + " length=" + array.Length + "/>");
    177.                     floats.AddRange(array);
    178.                 }
    179.  
    180.                 //other primitive array
    181.                 else if (objType.IsArray && elementType.IsPrimitive)
    182.                 {
    183.                     writer.Write("\t<items type=" + val.type + " values=");
    184.  
    185.                     Array array = (Array)obj;
    186.                     for (int i=0; i<array.Length; i++)
    187.                     {
    188.                         writer.Write(array.GetValue(i));
    189.                         if (i!=array.Length-1) writer.Write(Separator);
    190.                     }
    191.  
    192.                     writer.WriteLine("/>");
    193.                 }
    194.  
    195.                 //class array
    196.                 /*else if (val.classArray)
    197.                 {
    198.                     writer.Write( string.Format("\t<items type=" +  + " links=", val.type) );
    199.  
    200.                     Array array = (Array)obj;
    201.                     for (int i=0; i<array.Length; i++)
    202.                     {
    203.                         writer.Write( WriteClass(val.obj, ref classes, ref objects, references) );
    204.                         if (i!=array.Length-1) writer.Write(Separator);
    205.                     }
    206.  
    207.                     writer.Write("/>\n");
    208.                 }*///doesnt deal with null and not tested properly.
    209.  
    210.                 //unity object
    211.                 else if (val.type.IsSubclassOf(typeof(UnityEngine.Object)))
    212.                 {
    213.                     //not a big deal if the object will be added to array twice
    214.                     writer.WriteLine("\t<" +  val.name + " type=" + val.type + " object=" + objects.Count + "/>");
    215.                     objects.Add((UnityEngine.Object)val.obj);
    216.                 }
    217.  
    218.                 //null
    219.                 else if (val.obj == null)
    220.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " link=-1/>");
    221.  
    222.                 //class
    223.                 else if (val.type.IsClass && !val.type.IsValueType)
    224.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " link=" + WriteClass(val.obj, classes, objects, floats, references) + "/>");
    225.  
    226.                 //Vector2
    227.                 else if (val.type == typeof(Vector2))
    228.                 {
    229.                     Vector2 v2 = (Vector2)val.obj;
    230.                     var x = InvariantFloat(v2.x);
    231.                     var y = InvariantFloat(v2.y);
    232.                     var line = string.Format("\t<{0} type={1} x={2} y={3}/>",val.name, val.type, x, y);
    233.                     writer.WriteLine(line);
    234.  
    235.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " x=" + v2.x + " y=" + v2.y + "/>");
    236.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " val=" + floats.Count + "/>");
    237.                     //floats.Add(v2.x); floats.Add(v2.y);
    238.                 }
    239.  
    240.                 //Vector3
    241.                 else if (val.type == typeof(Vector3))
    242.                 {
    243.                     Vector3 v3 = (Vector3)val.obj;
    244.                     var x = InvariantFloat(v3.x);
    245.                     var y = InvariantFloat(v3.y);
    246.                     var z = InvariantFloat(v3.z);
    247.                     var line = string.Format("\t<{0} type={1} x={2} y={3} z={4}/>",val.name, val.type, x,y,z);
    248.                     writer.WriteLine(line);
    249.  
    250.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " x=" + v3.x + " y=" + v3.y + " z=" + v3.z + "/>");
    251.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " val=" + floats.Count + "/>");
    252.                     //floats.Add(v3.x); floats.Add(v3.y); floats.Add(v3.z);
    253.                 }
    254.  
    255.                 //Rect
    256.                 else if (val.type == typeof(Rect))
    257.                 {
    258.                     Rect rect = (Rect)val.obj;
    259.                  
    260.                     var x = InvariantFloat(rect.x);
    261.                     var y = InvariantFloat(rect.y);
    262.                     var width = InvariantFloat(rect.width);
    263.                     var height = InvariantFloat(rect.height);
    264.  
    265.                     var line = string.Format("\t<{0} type={1} x={2} y={3} width={4} height={5}/>",val.name, val.type, x, y, width, height);
    266.                     writer.WriteLine(line);
    267.                     //("\t<" + val.name + " type=" + val.type + " x=" + rect.x + " y=" + rect.y + " width=" + rect.width + " height=" + rect.height + "/>");
    268.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " val=" + floats.Count + "/>");
    269.                     //floats.Add(rect.x); floats.Add(rect.y); floats.Add(rect.width); floats.Add(rect.height);
    270.                 }
    271.  
    272.                 //Color
    273.                 else if (val.type == typeof(Color))
    274.                 {
    275.                     Color c = (Color)val.obj;
    276.                     var r = InvariantFloat(c.r);
    277.                     var g = InvariantFloat(c.g);
    278.                     var b = InvariantFloat(c.b);
    279.                     var a = InvariantFloat(c.a);
    280.                     var line = string.Format("\t<{0} type={1} r={2} g={3} b={4} a={5}/>",val.name, val.type, r,g,b,a);
    281.                     writer.WriteLine(line);
    282.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " r=" + c.r + " g=" + c.g + " b=" + c.b + " a=" + c.a + "/>");
    283.                 }
    284.  
    285.                 //Vector4
    286.                 else if (val.type == typeof(Vector4))
    287.                 {
    288.                     Vector4 v4 = (Vector4)val.obj;
    289.                     var x = InvariantFloat(v4.x);
    290.                     var y = InvariantFloat(v4.y);
    291.                     var z = InvariantFloat(v4.z);
    292.                     var w = InvariantFloat(v4.w);
    293.                     var line = string.Format("\t<{0} type={1} x={2} y={3} z={4} w={5}/>",val.name, val.type, x,y,z,w);
    294.                     writer.WriteLine(line);
    295.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " x=" + v4.x + " y=" + v4.y + " z=" + v4.z + " w=" + v4.w + "/>");
    296.                 }
    297.  
    298.                 //Quaternion
    299.                 else if (val.type == typeof(Quaternion))
    300.                 {
    301.                     Quaternion q = (Quaternion)val.obj;
    302.                     var x = InvariantFloat(q.x);
    303.                     var y = InvariantFloat(q.y);
    304.                     var z = InvariantFloat(q.z);
    305.                     var w = InvariantFloat(q.w);
    306.                     var line = string.Format("\t<{0} type={1} x={2} y={3} z={4} w={5}/>",val.name, val.type, x,y,z,w);
    307.                     writer.WriteLine(line);
    308.                     //writer.WriteLine("\t<" + val.name + " type=" + val.type + " x=" + q.x + " y=" + q.y + " z=" + q.z + " w=" + q.w + "/>");
    309.                 }
    310.  
    311.                 //enum
    312.                 else if (val.type.IsEnum)
    313.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " value=" + (int)val.obj + "/>");
    314.  
    315.                 //keyframe
    316.                 else if (val.type == typeof(Keyframe))
    317.                 {
    318.                     Keyframe k = (Keyframe)val.obj;
    319.  
    320.                     var time = InvariantFloat(k.time);
    321.                     var value = InvariantFloat(k.value);
    322.                     var inTan = InvariantFloat(k.inTangent);
    323.                     var outTan = InvariantFloat(k.outTangent);
    324.  
    325. #if UNITY_2018_2_OR_NEWER
    326.                     var inWeight = InvariantFloat(k.inWeight);
    327.                     var outWeight = InvariantFloat(k.outWeight);
    328.  
    329.                     var line = string.Format("\t<{0} type={1} time={2} value={3} in={4} out={5} mode={6} inWeight={7} outWeight={8}/>",
    330.                         val.name, val.type, time, value, inTan, outTan, 0, inWeight, outWeight);
    331.                     writer.WriteLine(line);
    332. #else
    333.                     var mode = InvariantFloat(k.tangentMode);
    334.                     var line = string.Format("\t<{0} type={1} time={2} value={3} in={4} out={5} mode={6}/>",val.name, val.type, time, value, inTan, outTan, mode);
    335.                     writer.WriteLine(line);
    336. #endif
    337.                 }
    338.  
    339.                 //any other struct (same as class)
    340.                 else
    341.                     writer.WriteLine("\t<" + val.name + " type=" + val.type + " link=" +  WriteClass(val.obj, classes, objects, floats, references) + "/>");
    342.             }
    343.  
    344.             //footer
    345.             writer.WriteLine("</" + objTypeName + ">");
    346.  
    347.             //writing obj
    348.             writer.Close();
    349.             classes[slotNum] = writer.ToString();
    350.  
    351.             return slotNum;
    352.         }
    353.  
    354.         private static string InvariantFloat(float value)
    355.         {
    356.             return value.ToString(CultureInfo.InvariantCulture.NumberFormat);
    357.         }
    358.  
    359.         private static string InvariantDouble(double value)
    360.         {
    361.             return value.ToString(CultureInfo.InvariantCulture.NumberFormat);
    362.         }
    363.  
    364.         public static object ReadClass (int slotNum, List<string> classes, List<UnityEngine.Object> objects, List<float> floats, List<object> references)
    365.         {
    366.             //cheking if this object was already loaded
    367.             for (int i=references.Count; i<classes.Count; i++) references.Add(null); //references count should be equal to classes length
    368.             if (references[slotNum]!=null) return references[slotNum];
    369.  
    370.             object obj = null;
    371.  
    372.             StringReader reader = new StringReader(classes[slotNum]);
    373.  
    374.             //reading header
    375.             string header = reader.ReadLine();
    376.             header = header.Substring(1,header.Length-2);
    377.  
    378.             //getting the array length
    379.             int arrayLength = 0;
    380.             if (header.Contains(" length="))
    381.             {
    382.                 string[] headerMembers = header.Split(' ');
    383.                 arrayLength = (int)headerMembers[1].Parse(typeof(int));
    384.                 header = headerMembers[0];
    385.             }
    386.  
    387.             //finding object type
    388.             System.Type objType = GetStandardAssembliesType(header);
    389.             if (objType == null) { Debug.Log("Could not load " + header + " as this type does not exists anymore"); return null; }
    390.             System.Type elementType = objType.IsArray? objType.GetElementType() : null;
    391.  
    392.             //creating object
    393.             if (objType.IsArray) obj = Activator.CreateInstance(objType, arrayLength);
    394.             else obj = Activator.CreateInstance(objType);
    395.             references[slotNum] = obj;
    396.  
    397.             //reading values
    398.             List<Value> values = new List<Value>();
    399.             while (true)
    400.             {
    401.                 string line = reader.ReadLine();
    402.                 if (line==null || line.StartsWith("</")) break;
    403.  
    404.                 //if (line.StartsWith("\t")) line = line.Remove(0,1); //removing tab if any
    405.                 line = line.Substring(2,line.Length-4); //removing < and />
    406.                 string[] lineMembers = line.Split(' ', Separator);
    407.  
    408.                 Value val = new Value();
    409.          
    410.                 //name
    411.                 val.name = lineMembers[0];
    412.          
    413.                 //type
    414.                 string typeName = lineMembers[1].Remove(0,5);
    415.                 val.type = GetStandardAssembliesType(typeName);
    416.                 if (val.type == null) { Debug.Log("Could not load " + typeName + " as this type does not exists anymore"); continue; }
    417.  
    418.                 //object: quick array
    419.                 if (val.type.IsArray && val.name=="items")
    420.                 {
    421.                     if (val.type == typeof(float[]))
    422.                     {
    423.                         int start = (int)lineMembers[2].Parse(typeof(int));
    424.                         for (int i=start; i<start+arrayLength; i++)
    425.                             values.Add( new Value() { name="item", type=elementType, obj=floats[i] } );
    426.                     }
    427.  
    428.                  
    429.                     //class
    430.                     /*if (lineMembers[2].StartsWith("link"))
    431.                     {
    432.                         for (int i=2; i<lineMembers.Length; i++)
    433.                             values.Add( new Value() { name="item", type=elementType, obj=ReadClass( (int)lineMembers[i].Parse(typeof(int)), classes, objects, floats, references) } );
    434.                     }*/
    435.  
    436.                     //primitives
    437.                     else
    438.                     {
    439.                         for (int i=2; i<lineMembers.Length; i++)
    440.                             values.Add( new Value() { name="item", type=elementType, obj=lineMembers[i].Parse(elementType) } );
    441.                     }
    442.                 }
    443.  
    444.                 //object: other
    445.                 else
    446.                 {
    447.                     //null
    448.                     if (lineMembers[2]=="null") val.obj = null;
    449.  
    450.                     //custom struct
    451.                     else if (typeof(IStruct).IsAssignableFrom(val.type))
    452.                     {
    453.                         val.obj = Activator.CreateInstance(val.type);
    454.                         ((IStruct)val.obj).Decode(lineMembers);
    455.                     }
    456.  
    457.                     //custom struct with links
    458.                     else if (typeof(IStructLink).IsAssignableFrom(val.type))
    459.                     {
    460.                         Func<int, object> readClassFn = delegate(int link) { return ReadClass(link, classes, objects, floats, references); };
    461.                         val.obj = Activator.CreateInstance(val.type);
    462.                         ((IStructLink)val.obj).Decode(lineMembers, readClassFn);
    463.                     }
    464.              
    465.                     //class
    466.                     else if (lineMembers[2].StartsWith("link"))
    467.                     {
    468.                         //val.obj = int.Parse(lineMembers[2].Remove(0,5)); //postporning reading the class until the object is created, storing link
    469.                         val.obj = ReadClass(int.Parse(lineMembers[2].Remove(0,5)), classes, objects, floats, references);
    470.                     }
    471.  
    472.                     //primitive
    473.                     else if (val.type.IsPrimitive)
    474.                         val.obj = lineMembers[2].Parse(val.type);
    475.  
    476.                     //unity Object
    477.                     else if (val.type.IsSubclassOf(typeof(UnityEngine.Object)))
    478.                     {
    479.                         val.obj = objects[ (int)lineMembers[2].Parse(typeof(int)) ];
    480.                     }
    481.  
    482.                     //string
    483.                     else if (val.type==typeof(string))
    484.                     {
    485.                         string str = (string)lineMembers[2].Parse(val.type);
    486.                         str = str.Replace("\\n", "\n");
    487.                         str = str.Replace("\\_", " ");
    488.                         val.obj = str;
    489.                     }
    490.  
    491.                     //Vector2
    492.                     else if (val.type == typeof(Vector2))
    493.                         val.obj = new Vector2( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)) );
    494.                     //{
    495.                     //    int n = (int)lineMembers[2].Parse(typeof(int));
    496.                     //    val.obj = new Vector2(floats[n], floats[n+1]);
    497.                     //}
    498.  
    499.                     //Vector3
    500.                     else if (val.type == typeof(Vector3))
    501.                         val.obj = new Vector3( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)) );
    502.                     //{
    503.                     //    int n = (int)lineMembers[2].Parse(typeof(int));
    504.                     //    val.obj = new Vector3(floats[n], floats[n+1], floats[n+2]);
    505.                     //}
    506.  
    507.                     //Rect
    508.                     else if (val.type == typeof(Rect))
    509.                         val.obj = new Rect( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)), (float)lineMembers[5].Parse(typeof(float)) );
    510.                     //{
    511.                     //    int n = (int)lineMembers[2].Parse(typeof(int));
    512.                     //    val.obj = new Rect(floats[n], floats[n+1], floats[n+2], floats[n+3]);
    513.                     //}
    514.  
    515.                     //Color
    516.                     else if (val.type == typeof(Color))
    517.                         val.obj = new Color( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)), (float)lineMembers[5].Parse(typeof(float)) );
    518.              
    519.                     //Vector4
    520.                     else if (val.type == typeof(Vector4))
    521.                         val.obj = new Vector4( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)), (float)lineMembers[5].Parse(typeof(float)) );
    522.              
    523.                     //Quaternion
    524.                     else if (val.type == typeof(Quaternion))
    525.                         val.obj = new Quaternion( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)), (float)lineMembers[5].Parse(typeof(float)) );
    526.                  
    527.                     //Keyframe
    528.                     else if (val.type == typeof(Keyframe))
    529.                     {
    530.                         Keyframe k = new Keyframe( (float)lineMembers[2].Parse(typeof(float)), (float)lineMembers[3].Parse(typeof(float)), (float)lineMembers[4].Parse(typeof(float)), (float)lineMembers[5].Parse(typeof(float)) );
    531.  
    532.                         #if UNITY_2018_2_OR_NEWER
    533.                         if (lineMembers.Length > 7)
    534.                         {
    535.                             k.inWeight = (float)lineMembers[7].Parse(typeof(float));
    536.                             k.outWeight = (float)lineMembers[8].Parse(typeof(float));
    537.                         }
    538.                         else
    539.                             k.tangentMode = (int)lineMembers[6].Parse(typeof(int));
    540.                         #else
    541.                         k.tangentMode = (int)lineMembers[6].Parse(typeof(int));
    542.                         #endif
    543.  
    544.                         val.obj = k;
    545.                     }
    546.              
    547.                     //enum
    548.                     else if (val.type.IsEnum)
    549.                         val.obj = Enum.ToObject(val.type, (int)lineMembers[2].Parse(typeof(int)));
    550.  
    551.                     values.Add(val);
    552.                 }
    553.             }
    554.  
    555.             //filling object
    556.             int valuesCount = values.Count;
    557.             if (objType.IsArray)
    558.             {
    559.                 Array array = (Array)obj;
    560.                 for (int i=0; i<array.Length; i++) array.SetValue(values[i].obj, i);
    561.             }
    562.             else
    563.             {
    564.                 //TODO: inline code here
    565.                 //TODO: use attributes
    566.                 foreach (FieldInfo field in objType.UsableFields(includeStatic:true))
    567.                 {
    568.                     string fieldName = field.Name;
    569.                     Type fieldType = field.FieldType;
    570.  
    571.                     for (int i=0; i<valuesCount; i++)
    572.                         try {
    573.                         if (values[i].name == fieldName  &&  values[i].type == fieldType) field.SetValue(obj, values[i].obj); }
    574.                         catch {}
    575.                 }
    576.                 foreach (PropertyInfo prop in objType.UsableProperties())
    577.                 {
    578.                     string propName = prop.Name;
    579.                     Type propType = prop.PropertyType;
    580.  
    581.                     for (int i=0; i<valuesCount; i++)
    582.                         if (values[i].name == propName  &&  values[i].type == propType) prop.SetValue(obj, values[i].obj, null);
    583.                 }
    584.             }
    585.  
    586.  
    587.             return obj;
    588.         }
    589.  
    590.  
    591.         public static object DeepCopy (object src)
    592.         {
    593.             List<string> classes = new List<string>();
    594.             List<UnityEngine.Object> objects = new List<UnityEngine.Object>();
    595.             List<float> floats = new List<float>();
    596.             List<object> saveReferences = new List<object>();
    597.             List<object> loadReferences = new List<object>();
    598.  
    599.             int num = CustomSerialization.WriteClass(src, classes, objects, floats, saveReferences);
    600.             return CustomSerialization.ReadClass(num, classes, objects, floats, loadReferences);
    601.         }
    602.  
    603.         public static string ExportXML (List<string> classes, List<UnityEngine.Object> objects, List<float> floats)
    604.         {
    605.             StringWriter writer = new StringWriter();
    606.  
    607.             for (int i=0; i<classes.Count; i++)
    608.                 writer.Write(classes[i]);
    609.  
    610.             #if UNITY_EDITOR
    611.             for (int i=0; i<objects.Count; i++)
    612.             {
    613.                 string path = UnityEditor.AssetDatabase.GetAssetPath(objects[i]);
    614.                 path = path.Replace(" ","*");
    615.                 writer.WriteLine("<Object type=" + objects[i].GetType() + " path=" + path + "/>");
    616.             }
    617.             #endif
    618.  
    619.             writer.Write("<Floats values=");
    620.             int floatsCount = floats.Count;
    621.             for (int i=0; i<floatsCount; i++)
    622.             {
    623.                  writer.Write(floats[i].ToString());
    624.                  if (i != floatsCount-1) writer.Write(Separator);
    625.             }
    626.             writer.WriteLine("/>");
    627.  
    628.             writer.Close();
    629.             return writer.ToString();
    630.         }
    631.  
    632.         public static void ImportXML (string xml, out List<string> classes, out List<UnityEngine.Object> objects, out List<float> floats)
    633.         {
    634.             StringReader reader = new StringReader(xml);
    635.          
    636.             classes = new List<string>();
    637.             objects = new List<UnityEngine.Object>();
    638.             floats = new List<float>();
    639.  
    640.             StringWriter writer = null;
    641.             while (true)
    642.             {
    643.                 string line = reader.ReadLine();
    644.                 if (line==null) break;
    645.  
    646.                 //objects
    647.                 if (line.StartsWith("<Object"))
    648.                 {
    649.                     #if UNITY_EDITOR
    650.                     line = line.Replace("/>","");
    651.                     string[] lineMemebers = line.Split(' ');
    652.  
    653.                     string path = lineMemebers[2].Replace("path=","");
    654.                     path = path.Replace("*", " ");
    655.                     objects.Add(UnityEditor.AssetDatabase.LoadMainAssetAtPath(path));
    656.  
    657.                     Type type = GetStandardAssembliesType( lineMemebers[1].Replace("type=","") );
    658.                     if (type==typeof(Transform) && objects[objects.Count-1]!=null) objects[objects.Count-1] = ((GameObject)objects[objects.Count-1]).transform; //converting to transform instead of gameobject
    659.                     #endif
    660.  
    661.                     continue;
    662.                 }
    663.  
    664.                 //floats
    665.                 if (line.StartsWith("<Floats"))
    666.                 {
    667.                     line = line.Replace("<Floats values=","");
    668.                     line = line.Replace("/>","");
    669.                     if (line.Length==0) continue;
    670.  
    671.                     string[] lineMemebers = line.Split(Separator);
    672.                     for (int i=0; i<lineMemebers.Length; i++) floats.Add(float.Parse(lineMemebers[i]));
    673.  
    674.                     continue;
    675.                 }
    676.  
    677.                 //classes
    678.                 if (!line.Contains("/>") && !line.Contains("</")) //class started
    679.                 {
    680.                     if (writer!=null) classes.Add(writer.ToString());
    681.                     writer = new StringWriter();
    682.                 }
    683.  
    684.                 writer.WriteLine(line);
    685.             }
    686.             classes.Add(writer.ToString()); //writing down what's left in writer
    687.         }
    688.     }
    689.  
    690. }
    691.  
    Extensions:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Reflection; //to copy properties
    6. using System.Globalization;
    7.  
    8. namespace MapMagic
    9. {
    10.     public interface IFactory
    11.     {
    12.         void OnConstruct ();
    13.         void OnDeconstruct ();
    14.     }
    15.  
    16.     static public class Extensions
    17.     {
    18.         public enum VersionState { branch, alpha, beta, candidate, release };
    19.         public static string ToVersionString (this VersionState state)
    20.         {
    21.             switch (state)
    22.             {
    23.                 case VersionState.branch: return "special edition";
    24.                 case VersionState.alpha: return "development";
    25.                 case VersionState.beta: return "beta";
    26.                 case VersionState.candidate: return "release candidate";
    27.                 default: return "";
    28.             }
    29.         }
    30.         public static string ToVersionString (this int ver)
    31.         {
    32.             int val1 = ver/100;
    33.             int val2 = (ver - val1*100) / 10;
    34.             int val3 = ver - val1*100 - val2*10;
    35.             return ""+val1+"."+val2+"."+val3;
    36.         }
    37.  
    38.         public static bool InRange (this Rect rect, Vector2 pos)
    39.         {
    40.             return (rect.center - pos).sqrMagnitude < (rect.width/2f)*(rect.width/2f);
    41.             //return rect.Contains(pos);
    42.         }
    43.  
    44.         public static Vector3 ToDir (this float angle) { return new Vector3( Mathf.Sin(angle*Mathf.Deg2Rad), 0, Mathf.Cos(angle*Mathf.Deg2Rad) ); }
    45.         public static float ToAngle (this Vector3 dir) { return Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg; }
    46.  
    47.         public static Vector3 V3 (this Vector2 v2) { return new Vector3(v2.x, 0, v2.y); }
    48.         public static Vector2 V2 (this Vector3 v3) { return new Vector2(v3.x, v3.z); }
    49.         public static Vector3 ToV3 (this float f) { return new Vector3(f,f, f); }
    50.  
    51.         public static Quaternion EulerToQuat (this Vector3 v) { Quaternion rotation = Quaternion.identity; rotation.eulerAngles = v; return rotation; }
    52.         public static Quaternion EulerToQuat (this float f) { Quaternion rotation = Quaternion.identity; rotation.eulerAngles = new Vector3(0,f,0); return rotation; }
    53.  
    54.         public static Vector3 Direction (this float angle) { return new Vector3( Mathf.Sin(angle*Mathf.Deg2Rad), 0, Mathf.Cos(angle*Mathf.Deg2Rad) ); }
    55.         public static float Angle (this Vector3 dir) { return Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg; }
    56.  
    57.         public static Rect Clamp (this Rect r, float p) { return new Rect(r.x, r.y, r.width*p, r.height); }
    58.         public static Rect ClampFromLeft (this Rect r, float p) { return new Rect(r.x+r.width*(1f-p), r.y, r.width*p, r.height); }
    59.         public static Rect Clamp (this Rect r, int p) { return new Rect(r.x, r.y, p, r.height); }
    60.         public static Rect ClampFromLeft (this Rect r, int p) { return new Rect(r.x+(r.width-p), r.y, p, r.height); }
    61.  
    62.         public static Rect ToRect(this Vector3 center, float range) { return new Rect(center.x-range, center.z-range, range*2, range*2); }
    63.  
    64.         public static Vector3 Average (this Vector3[] vecs) { Vector3 result = Vector3.zero; for (int i=0; i<vecs.Length; i++) result+=vecs[i]; return result / vecs.Length; }
    65.  
    66.         public static bool Intersects (this Rect r1, Rect r2)
    67.         {
    68.             Vector2 r1min = r1.min; Vector2 r1max = r1.max;
    69.             Vector2 r2min = r2.min; Vector2 r2max = r2.max;
    70.             if (r2max.x < r1min.x || r2min.x > r1max.x || r2max.y < r1min.y || r2min.y > r1max.y) return false;
    71.             else return true;
    72.         }
    73.         public static bool Intersects (this Rect r1, Rect[] rects)
    74.         {
    75.             for (int i=0; i<rects.Length; i++)
    76.                 if (r1.Intersects(rects[i])) return true; //todo: remove fn call, use r1 min max
    77.             return false;
    78.         }
    79.  
    80.         public static bool Contains (this Rect r1, Rect r2)
    81.         {
    82.             Vector2 r1min = r1.min; Vector2 r1max = r1.max;
    83.             Vector2 r2min = r2.min; Vector2 r2max = r2.max;
    84.             if (r2min.x > r1min.x && r2max.x < r1max.x && r2min.y > r1min.y && r2max.y < r1max.y) return true;
    85.             else return false;
    86.         }
    87.  
    88.         public static Rect Extend (this Rect r, float f) { return new Rect(r.x-f, r.y-f, r.width+f*2, r.height+f*2); }
    89.  
    90.         public static float DistToRectCenter (this Vector3 pos, float offsetX, float offsetZ, float size)
    91.         {
    92.             //TODO: evaluating distance to center, should evaluate distance to rect edges isntead
    93.             //float posX = pos.x; float posZ = pos.z;
    94.             float deltaX = pos.x - (offsetX+size/2); float deltaZ = pos.z - (offsetZ+size/2); float dist = deltaX*deltaX + deltaZ*deltaZ;
    95.  
    96.             /*float deltaBX = pos.x - offsetX; float deltaBZ = pos.z - offsetZ; float distB = deltaBX*deltaBX + deltaBZ*deltaBZ;
    97.             float deltaCX = pos.x - (offsetX+size); float deltaCZ = pos.z - (offsetZ+size); float distC = deltaCX*deltaCX + deltaCZ*deltaCZ;
    98.             float deltaDX = pos.x - (offsetX+size); float deltaDZ = pos.z - (offsetZ+size); float distD = deltaDX*deltaDX + deltaDZ*deltaDZ;
    99.  
    100.             //zero dist if pos inside rect
    101.             if (deltaAX>0 && deltaAZ>0 &&
    102.  
    103.             float minAB = distA<distB? distA : distB;
    104.             float minCD = distC<distD? distC : distD;
    105.             float minABCD = minAB<minCD? minAB : minCD;*/
    106.  
    107.             return Mathf.Sqrt(dist);
    108.         }
    109.  
    110.         public static float DistToRectAxisAligned (this Vector3 pos, float offsetX, float offsetZ, float size) //not manhattan dist. offset and size are instead of UnityEngine.Rect
    111.         {
    112.             //finding x distance
    113.             float distPosX = offsetX - pos.x;
    114.             float distNegX = pos.x - offsetX - size;
    115.          
    116.             float distX;
    117.             if (distPosX >= 0) distX = distPosX;
    118.             else if (distNegX >= 0) distX = distNegX;
    119.             else distX = 0;
    120.  
    121.             //finding z distance
    122.             float distPosZ = offsetZ - pos.z;
    123.             float distNegZ = pos.z - offsetZ - size;
    124.          
    125.             float distZ;
    126.             if (distPosZ >= 0) distZ = distPosZ;
    127.             else if (distNegZ >= 0) distZ = distNegZ;
    128.             else distZ = 0;
    129.  
    130.             //returning the maximum(!) distance
    131.             if (distX > distZ) return distX;
    132.             else return distZ;
    133.         }
    134.  
    135.         public static float DistToRectCenter (this Vector3[] poses, float offsetX, float offsetZ, float size)
    136.         {
    137.             float minDist = 200000000;
    138.             for (int p=0; p<poses.Length; p++)
    139.             {
    140.                 float dist = poses[p].DistToRectCenter(offsetX, offsetZ, size);
    141.                 if (dist < minDist) minDist = dist;
    142.             }
    143.             return minDist;
    144.         }
    145.  
    146.         public static float DistToRectAxisAligned (this Vector3[] poses, float offsetX, float offsetZ, float size)
    147.         {
    148.             float minDist = 200000000;
    149.             for (int p=0; p<poses.Length; p++)
    150.             {
    151.                 float dist = poses[p].DistToRectAxisAligned(offsetX, offsetZ, size);
    152.                 if (dist < minDist) minDist = dist;
    153.             }
    154.             return minDist;
    155.         }
    156.  
    157.         public static float DistAxisAligned (this Vector3 center, Vector3 pos)
    158.         {
    159.             float distX = center.x - pos.x; if (distX<0) distX = -distX;
    160.             float distZ = center.z - pos.z; if (distZ<0) distZ = -distZ;
    161.  
    162.             //returning the maximum(!) distance
    163.             if (distX > distZ) return distX;
    164.             else return distZ;
    165.         }
    166.  
    167.  
    168.  
    169.         /*public static Coord ToCoord (this Vector3 pos, float cellSize, bool ceil=false) //to use in object grid
    170.         {
    171.             if (!ceil) return new Coord(
    172.                 Mathf.FloorToInt((pos.x) / cellSize),
    173.                 Mathf.FloorToInt((pos.z) / cellSize) );
    174.             else return new Coord(
    175.                 Mathf.CeilToInt((pos.x) / cellSize),
    176.                 Mathf.CeilToInt((pos.z) / cellSize) );
    177.         }*/
    178.  
    179.         public static Coord RoundToCoord (this Vector2 pos) //to use in spatial hash (when sphash and matrix sizes are equal)
    180.         {
    181.             int posX = (int)(pos.x + 0.5f); if (pos.x < 0) posX--; //snippet for RoundToInt
    182.             int posZ = (int)(pos.y + 0.5f); if (pos.y < 0) posZ--;
    183.             return new Coord(posX, posZ);
    184.         }
    185.  
    186.         public static Coord FloorToCoord (this Vector3 pos, float cellSize) { return new Coord( Mathf.FloorToInt(pos.x / cellSize),        Mathf.FloorToInt(pos.z / cellSize)  ); }
    187.         public static Coord CeilToCoord (this Vector3 pos, float cellSize) { return new Coord( Mathf.CeilToInt(pos.x / cellSize),        Mathf.CeilToInt(pos.z / cellSize)  ); }
    188.         public static Coord RoundToCoord (this Vector3 pos, float cellSize) { return new Coord( Mathf.RoundToInt(pos.x / cellSize),        Mathf.RoundToInt(pos.z / cellSize)  ); }
    189.         public static CoordRect ToCoordRect (this Vector3 pos, float range, float cellSize) //this one works with Terrain Sculptor
    190.         {
    191.             Coord min = new Coord( Mathf.FloorToInt((pos.x-range)/cellSize),    Mathf.FloorToInt((pos.z-range)/cellSize)  );
    192.             Coord max = new Coord( Mathf.FloorToInt((pos.x+range)/cellSize),    Mathf.FloorToInt((pos.z+range)/cellSize)  )  +  1;
    193.             return new CoordRect(min, max-min);
    194.         }
    195.  
    196.         public static CoordRect ToFixedSizeCoordRect (this Vector3 pos, float range, float cellSize)
    197.         {
    198.             Coord size = (Vector3.one*range*2).CeilToCoord(cellSize) + 1;
    199.             Coord offset = pos.RoundToCoord(cellSize) - size/2;
    200.             return new CoordRect (offset, size);
    201.         }
    202.  
    203.         public static CoordRect GetHeightRect (this Terrain terrain)
    204.         {
    205.             float pixelSize = terrain.terrainData.size.x / terrain.terrainData.heightmapResolution;
    206.  
    207.             int posX = (int)(terrain.transform.localPosition.x/pixelSize + 0.5f); if (terrain.transform.localPosition.x < 0) posX--;
    208.             int posZ = (int)(terrain.transform.localPosition.z/pixelSize + 0.5f); if (terrain.transform.localPosition.z < 0) posZ--;
    209.  
    210.             return new CoordRect(posX, posZ, terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution);
    211.         }
    212.  
    213.         public static CoordRect GetSplatRect (this Terrain terrain)
    214.         {
    215.             float pixelSize = terrain.terrainData.size.x / terrain.terrainData.alphamapResolution;
    216.  
    217.             int posX = (int)(terrain.transform.localPosition.x/pixelSize + 0.5f); if (terrain.transform.localPosition.x < 0) posX--;
    218.             int posZ = (int)(terrain.transform.localPosition.z/pixelSize + 0.5f); if (terrain.transform.localPosition.z < 0) posZ--;
    219.  
    220.             return new CoordRect(posX, posZ, terrain.terrainData.alphamapResolution, terrain.terrainData.alphamapResolution);
    221.         }
    222.  
    223.         public static float[,] SafeGetHeights (this TerrainData data, int offsetX, int offsetZ, int sizeX, int sizeZ)
    224.         {
    225.             if (offsetX<0) { sizeX += offsetX; offsetX=0; } if (offsetZ<0) { sizeZ += offsetZ; offsetZ=0; } //Not Tested!
    226.             int res = data.heightmapResolution;
    227.             if (sizeX+offsetX > res) sizeX = res-offsetX; if (sizeZ+offsetZ > res) sizeZ = res-offsetZ;
    228.             return data.GetHeights(offsetX, offsetZ, sizeX, sizeZ);
    229.         }
    230.  
    231.         public static float[,,] SafeGetAlphamaps (this TerrainData data, int offsetX, int offsetZ, int sizeX, int sizeZ)
    232.         {
    233.             if (offsetX<0) { sizeX += offsetX; offsetX=0; } if (offsetZ<0) { sizeZ += offsetZ; offsetZ=0; } //Not Tested!
    234.             int res = data.alphamapResolution;
    235.             if (sizeX+offsetX > res) sizeX = res-offsetX; if (sizeZ+offsetZ > res) sizeZ = res-offsetZ;
    236.             return data.GetAlphamaps(offsetX, offsetZ, sizeX, sizeZ);
    237.         }
    238.  
    239.         public static Texture2D ColorTexture (int width, int height, Color color)
    240.         {
    241.             Texture2D result = new Texture2D(width, height);
    242.             Color[] pixels = result.GetPixels(0,0,width,height);
    243.             for (int i=0;i<pixels.Length;i++) pixels[i] = color;
    244.             result.SetPixels(0,0,width,height, pixels);
    245.             result.Apply();
    246.             return result;
    247.         }
    248.  
    249.         public static bool Equal (Vector3 v1, Vector3 v2)
    250.         {
    251.             return Mathf.Approximately(v1.x, v2.x) &&
    252.                     Mathf.Approximately(v1.y, v2.y) &&
    253.                     Mathf.Approximately(v1.z, v2.z);
    254.         }
    255.      
    256.         public static bool Equal (Ray r1, Ray r2)
    257.         {
    258.             return Equal(r1.origin, r2.origin) && Equal(r1.direction, r2.direction);
    259.         }
    260.  
    261.         public static void RemoveChildren (this Transform tfm)
    262.         {
    263.             for (int i=tfm.childCount-1; i>=0; i--)
    264.             {
    265.                 Transform child = tfm.GetChild(i);
    266.                 GameObject.DestroyImmediate(child.gameObject);
    267.             }
    268.         }
    269.  
    270.         public static Transform FindChildRecursive (this Transform tfm, string name)
    271.         {
    272.             int numChildren = tfm.childCount;
    273.  
    274.             for (int i=0; i<numChildren; i++)
    275.                 if (tfm.GetChild(i).name == name) return tfm.GetChild(i);
    276.  
    277.             for (int i=0; i<numChildren; i++)
    278.             {
    279.                 Transform result = tfm.GetChild(i).FindChildRecursive(name);
    280.                 if (result != null) return result;
    281.             }
    282.  
    283.             return null;
    284.         }
    285.  
    286.         public static Vector3[] InverseTransformPoint (this Transform tfm, Vector3[] points)
    287.         {
    288.             for (int c=0; c<points.Length; c++) points[c] = tfm.InverseTransformPoint(points[c]);
    289.             return points;
    290.         }
    291.  
    292.         public static Vector3 GetCenter (this Vector3[] poses)
    293.         {
    294.             if (poses.Length == 0) return new Vector3();
    295.             if (poses.Length == 1) return poses[0];
    296.  
    297.             float x=0; float y=0; float z=0;
    298.             for (int i=0; i<poses.Length; i++)
    299.             {
    300.                 x+=poses[i].x;
    301.                 y+=poses[i].y;
    302.                 z+=poses[i].z;
    303.             }
    304.             return new Vector3(x/poses.Length, y/poses.Length, z/poses.Length);
    305.         }
    306.  
    307.         public static void ToggleDisplayWireframe (this Transform tfm, bool show)
    308.         {
    309.             #if UNITY_EDITOR
    310.             #if !UNITY_5_5_OR_NEWER
    311.                 UnityEditor.EditorUtility.SetSelectedWireframeHidden(tfm.GetComponent<Renderer>(), !show);
    312.                 int childCount = tfm.childCount;
    313.                 for (int c=0; c<childCount; c++) tfm.GetChild(c).ToggleDisplayWireframe(show);
    314.             #else
    315.                 UnityEditor.EditorUtility.SetSelectedRenderState(tfm.GetComponent<Renderer>(), show? UnityEditor.EditorSelectedRenderState.Highlight : UnityEditor.EditorSelectedRenderState.Hidden);
    316.                 int childCount = tfm.childCount;
    317.                 for (int c=0; c<childCount; c++) tfm.GetChild(c).ToggleDisplayWireframe(show);
    318.             #endif
    319.             #endif
    320.         }
    321.  
    322.         public static int ToInt (this Coord coord)
    323.         {
    324.             int absX = coord.x<0? -coord.x : coord.x;
    325.             int absZ = coord.z<0? -coord.z : coord.z;
    326.  
    327.             return ((coord.z<0? 1000000000 : 0) + absX*30000 + absZ) * (coord.x<0? -1 : 1);
    328.         }
    329.  
    330.         public static Coord ToCoord (this int hash)
    331.         {
    332.             int absHash = hash<0? -hash : hash;
    333.             int sign = (absHash/1000000000)*1000000000;
    334.  
    335.             int absX = (absHash - sign)/30000;
    336.             int absZ = absHash - sign - absX*30000;
    337.  
    338.             return new Coord(hash<0? -absX : absX, sign==0? absZ : -absZ);
    339.         }
    340.  
    341.         public static void CheckAdd<TKey,TValue> (this Dictionary<TKey,TValue> dict, TKey key, TValue value, bool replace=true)
    342.         {
    343.             if (dict.ContainsKey(key))
    344.                 { if (replace) dict[key] = value; }
    345.             else dict.Add(key, value);
    346.         }
    347.         public static void CheckRemove<TKey,TValue> (this Dictionary<TKey,TValue> dict, TKey key) { if (dict.ContainsKey(key)) dict.Remove(key); }
    348.         public static TValue CheckGet<TKey,TValue> (this Dictionary<TKey,TValue> dict, TKey key)
    349.         {
    350.             if (dict.ContainsKey(key)) return dict[key];
    351.             else return default(TValue);
    352.         }
    353.         public static TKey AnyKey<TKey,TValue> (this Dictionary<TKey,TValue> dict)
    354.         {
    355.             foreach (KeyValuePair<TKey,TValue> kvp in dict)
    356.                 return kvp.Key;
    357.             return default(TKey);
    358.         }
    359.         public static TValue AnyValue<TKey,TValue> (this Dictionary<TKey,TValue> dict)
    360.         {
    361.             foreach (KeyValuePair<TKey,TValue> kvp in dict)
    362.                 return kvp.Value;
    363.             return default(TValue);
    364.         }
    365.         public static T Any<T> (this HashSet<T> hashSet)
    366.         {
    367.             foreach (T val in hashSet)
    368.                 return val;
    369.             return default(T);
    370.         }
    371.  
    372.         public static void CheckAdd<T> (this HashSet<T> set, T obj) { if (!set.Contains(obj)) set.Add(obj); }
    373.         public static void CheckRemove<T> (this HashSet<T> set, T obj) { if (set.Contains(obj)) set.Remove(obj); }
    374.         public static void SetState<T> (this HashSet<T> set, T obj, bool state)
    375.         {
    376.             if (state && !set.Contains(obj)) set.Add(obj);
    377.             if (!state && set.Contains(obj)) set.Remove(obj);
    378.         }
    379.  
    380.         public static void Normalize (this float[,,] array, int pinnedLayer)
    381.         {
    382.             int maxX = array.GetLength(0); int maxZ = array.GetLength(1); int numLayers = array.GetLength(2);
    383.             for (int x=0; x<maxX; x++)
    384.                 for (int z=0; z<maxZ; z++)
    385.             {
    386.                 float othersSum = 0;
    387.  
    388.                 for (int i=0; i<numLayers; i++)
    389.                 {
    390.                     if (i==pinnedLayer) continue;
    391.                     othersSum += array[x,z,i];
    392.                 }
    393.  
    394.                 float pinnedValue = array[x,z,pinnedLayer];
    395.                 if (pinnedValue > 1) { pinnedValue = 1; array[x,z,pinnedLayer] = 1; }
    396.                 if (pinnedValue < 0) { pinnedValue = 0; array[x,z,pinnedLayer] = 0; }
    397.  
    398.                 float othersTargetSum = 1 - pinnedValue;
    399.                 float factor = othersSum>0? othersTargetSum / othersSum : 0;
    400.  
    401.                 for (int i=0; i<numLayers; i++)
    402.                 {
    403.                     if (i==pinnedLayer) continue;
    404.                      array[x,z,i] *= factor;
    405.                 }
    406.             }
    407.  
    408.         }
    409.  
    410.         public static void DrawDebug (this Vector3 pos, float range=1, Color color=new Color())
    411.         {
    412.             if (color.a<0.001f) color = Color.white;
    413.             Debug.DrawLine(pos + new Vector3(-1,0,1)*range, pos + new Vector3(1,0,1)*range, color);
    414.             Debug.DrawLine(pos + new Vector3(1,0,1)*range, pos + new Vector3(1,0,-1)*range, color);
    415.             Debug.DrawLine(pos + new Vector3(1,0,-1)*range, pos + new Vector3(-1,0,-1)*range, color);
    416.             Debug.DrawLine(pos + new Vector3(-1,0,-1)*range, pos + new Vector3(-1,0,1)*range, color);
    417.         }
    418.  
    419.         public static void DrawDebug (this Rect rect, Color color=new Color())
    420.         {
    421.             if (color.a<0.001f) color = Color.white;
    422.             Debug.DrawLine(    new Vector3(rect.x,0,rect.y),                            new Vector3(rect.x+rect.width,0,rect.y),                color);
    423.             Debug.DrawLine(    new Vector3(rect.x+rect.width,0,rect.y),                new Vector3(rect.x+rect.width,0,rect.y+rect.height),    color);
    424.             Debug.DrawLine(    new Vector3(rect.x+rect.width,0,rect.y+rect.height),    new Vector3(rect.x,0,rect.y+rect.height),                color);
    425.             Debug.DrawLine(    new Vector3(rect.x,0,rect.y+rect.height),                new Vector3(rect.x,0,rect.y),                            color);
    426.         }
    427.  
    428.         public static void Resize (this Terrain terrain, int resolution, Vector3 size)
    429.         {
    430.             //setting resolution and THEN terrain size is too laggy
    431.             //so making this trick to resize terrain or change res
    432.             if ((terrain.terrainData.size-size).sqrMagnitude > 0.01f || terrain.terrainData.heightmapResolution != resolution)
    433.             {
    434.                 if (resolution <= 64) //brute force
    435.                 {
    436.                     terrain.terrainData.heightmapResolution = resolution;
    437.                     terrain.terrainData.size = new Vector3(size.x, size.y, size.z);
    438.                 }
    439.  
    440.                 else //setting res 64, re-scaling to 1/64, and then changing res
    441.                 {
    442.                     terrain.terrainData.heightmapResolution = 65;
    443.                     terrain.Flush(); //otherwise unity crushes without an error
    444.                     int resFactor = (resolution-1) / 64;
    445.                     terrain.terrainData.size = new Vector3(size.x/resFactor, size.y, size.z/resFactor);
    446.                     terrain.terrainData.heightmapResolution = resolution;
    447.                 }
    448.             }
    449.         }
    450.  
    451.         public static Transform AddChild (this Transform tfm, string name="", Vector3 offset=new Vector3())
    452.         {
    453.             GameObject go = new GameObject();
    454.             go.name = name;
    455.             go.transform.parent = tfm;
    456.             go.transform.localPosition = offset;
    457.  
    458.             return go.transform;
    459.         }
    460.  
    461.         public static T CreateObjectWithComponent<T> (string name="", Transform parent=null, Vector3 offset=new Vector3()) where T : MonoBehaviour
    462.         {
    463.             GameObject go = new GameObject();
    464.             if (name != null)
    465.             if (parent != null) go.transform.parent = parent.transform;
    466.             go.transform.localPosition = offset;
    467.          
    468.             return go.AddComponent<T>();
    469.         }
    470.  
    471.         public static IEnumerable<Vector3> CircleAround (this Vector3 center, float radius, int numPoints, bool endWhereStart=false)
    472.         {
    473.             float radianStep = 2*Mathf.PI / numPoints;
    474.             if (endWhereStart) numPoints++;
    475.             for (int i=0; i<numPoints; i++)
    476.             {
    477.                 float angle = i*radianStep;
    478.                 Vector3 dir = new Vector3( Mathf.Sin(angle), 0, Mathf.Cos(angle) );
    479.                 yield return center + dir*radius;
    480.             }
    481.         }
    482.  
    483.         public static float EvaluateMultithreaded (this AnimationCurve curve, float time)
    484.         {
    485.             int keyCount = curve.keys.Length;
    486.          
    487.             if (time <= curve.keys[0].time) return curve.keys[0].value;
    488.             if (time >= curve.keys[keyCount-1].time) return curve.keys[keyCount-1].value;
    489.  
    490.             int keyNum = 0;
    491.             for (int k=0; k<keyCount-1; k++)
    492.             {
    493.                 if (curve.keys[keyNum+1].time > time) break;
    494.                 keyNum++;
    495.             }
    496.          
    497.             float delta = curve.keys[keyNum+1].time - curve.keys[keyNum].time;
    498.             float relativeTime = (time - curve.keys[keyNum].time) / delta;
    499.  
    500.             float timeSq = relativeTime * relativeTime;
    501.             float timeCu = timeSq * relativeTime;
    502.    
    503.             float a = 2*timeCu - 3*timeSq + 1;
    504.             float b = timeCu - 2*timeSq + relativeTime;
    505.             float c = timeCu - timeSq;
    506.             float d = -2*timeCu + 3*timeSq;
    507.  
    508.             return a*curve.keys[keyNum].value + b*curve.keys[keyNum].outTangent*delta + c*curve.keys[keyNum+1].inTangent*delta + d*curve.keys[keyNum+1].value;
    509.         }
    510.  
    511.         public static bool IdenticalTo (this AnimationCurve c1, AnimationCurve c2)
    512.         {
    513.             if (c1==null || c2==null) return false;
    514.             if (c1.keys.Length != c2.keys.Length) return false;
    515.          
    516.             int numKeys = c1.keys.Length;
    517.             for (int k=0; k<numKeys; k++)
    518.             {
    519.                 if (c1.keys[k].time != c2.keys[k].time ||
    520.                     c1.keys[k].value != c2.keys[k].value ||
    521.                     c1.keys[k].inTangent != c2.keys[k].inTangent ||
    522.                     c1.keys[k].outTangent != c2.keys[k].outTangent)
    523.                         return false;
    524.             }
    525.  
    526.             return true;
    527.         }
    528.  
    529.         public static Keyframe[] Copy (this Keyframe[] src)
    530.         {
    531.             Keyframe[] dst = new Keyframe[src.Length];
    532.             for (int k=0; k<src.Length; k++)
    533.             {
    534.                 dst[k].value = src[k].value;
    535.                 dst[k].time = src[k].time;
    536.                 dst[k].inTangent = src[k].inTangent;
    537.                 dst[k].outTangent = src[k].outTangent;
    538.             }
    539.             return dst;
    540.         }
    541.  
    542.         public static AnimationCurve Copy (this AnimationCurve src)
    543.         {
    544.             AnimationCurve dst = new AnimationCurve();
    545.             dst.keys = src.keys.Copy();
    546.             return dst;
    547.         }
    548.  
    549.  
    550.         public static object CallStaticMethodFrom (string assembly, string type, string method, object[] parameters)
    551.         {
    552.             // editor assembly is Assembly-CSharp-Editor
    553.             // main is Assembly-CSharp
    554.  
    555.             Assembly a = Assembly.Load(assembly);
    556.             Type t = a.GetType(type);
    557.             return t.GetMethod(method).Invoke(null, parameters);
    558.         }
    559.  
    560.         public static void GetPropertiesFrom<T1,T2> (this T1 dst, T2 src) where T1:class where T2:class
    561.         {
    562.             PropertyInfo[] srcProps = src.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
    563.             PropertyInfo[] dstProps = src.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty);
    564.        
    565.             for (int sp=0; sp<srcProps.Length; sp++)
    566.                 for (int dp=0; dp<dstProps.Length; dp++)
    567.             {
    568.                 if (srcProps[sp].Name==dstProps[dp].Name && dstProps[dp].CanWrite)
    569.                     dstProps[dp].SetValue(dst, srcProps[sp].GetValue(src, null), null);
    570.             }
    571.          }
    572.  
    573.  
    574.         public static IEnumerable<FieldInfo> UsableFields (this Type type, bool nonPublic=false, bool includeStatic=false)
    575.         {
    576.             BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
    577.             if (nonPublic) flags = flags | BindingFlags.NonPublic;
    578.             if (includeStatic) flags = flags | BindingFlags.Static;
    579.  
    580.             FieldInfo[] fields = type.GetFields(flags);
    581.             for (int i=0; i<fields.Length; i++)
    582.             {
    583.                 FieldInfo field = fields[i];
    584.                 if (field.IsLiteral) continue; //leaving constant fields blank
    585.                 if (field.FieldType.IsPointer) continue; //skipping pointers (they make unity crash. Maybe require unsafe)
    586.                 if (field.IsNotSerialized) continue;
    587.  
    588.                 yield return field;
    589.             }
    590.         }
    591.  
    592.         public static IEnumerable<PropertyInfo> UsableProperties (this Type type, bool nonPublic=false, bool skipItems=true)
    593.         {
    594.             BindingFlags flags;
    595.             if (nonPublic) flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
    596.             else flags = BindingFlags.Public | BindingFlags.Instance;
    597.  
    598.             PropertyInfo[] properties = type.GetProperties(flags);
    599.             for (int i=0;i<properties.Length;i++)
    600.             {
    601.                 PropertyInfo prop = properties[i];
    602.                 if (!prop.CanWrite) continue;
    603.                 if (skipItems && prop.Name=="Item") continue; //ignoring this[x]
    604.  
    605.                 yield return prop;
    606.             }
    607.         }
    608.  
    609.         public static IEnumerable<MemberInfo> UsableMembers (this Type type, bool nonPublic=false, bool skipItems=true)
    610.         {
    611.             BindingFlags flags;
    612.             if (nonPublic) flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
    613.             else flags = BindingFlags.Public | BindingFlags.Instance;
    614.  
    615.             FieldInfo[] fields = type.GetFields(flags);
    616.             for (int i=0; i<fields.Length; i++)
    617.             {
    618.                 FieldInfo field = fields[i];
    619.                 if (field.IsLiteral) continue; //leaving constant fields blank
    620.                 if (field.FieldType.IsPointer) continue; //skipping pointers (they make unity crash. Maybe require unsafe)
    621.                 if (field.IsNotSerialized) continue;
    622.  
    623.                 yield return field;
    624.             }
    625.  
    626.             PropertyInfo[] properties = type.GetProperties(flags);
    627.             for (int i=0;i<properties.Length;i++)
    628.             {
    629.                 PropertyInfo prop = properties[i];
    630.                 if (!prop.CanWrite) continue;
    631.                 if (skipItems && prop.Name=="Item") continue; //ignoring this[x]
    632.  
    633.                 yield return prop;
    634.             }
    635.         }
    636.  
    637.         public static Component CopyComponent (Component src, GameObject go)
    638.         {
    639.             System.Type type = src.GetType();
    640.          
    641.             Component dst = go.GetComponent(src.GetType());
    642.             if (dst==null) dst = go.AddComponent(type);
    643.  
    644.             foreach (FieldInfo field in type.UsableFields(nonPublic:true)) field.SetValue(dst, field.GetValue(src));
    645.             foreach (PropertyInfo prop in type.UsableProperties(nonPublic:true))
    646.             {
    647.                 if (prop.Name == "name") continue;
    648.                 try {prop.SetValue(dst, prop.GetValue(src, null), null); }
    649.                 catch { }
    650.             }
    651.  
    652.             return dst;
    653.         }
    654.  
    655.         /*public static List<Type> GetAllChildTypes (this Type type)
    656.         {
    657.             List<Type> result = new List<Type>();
    658.      
    659.             Assembly assembly = Assembly.GetAssembly(type);
    660.             Type[] allTypes = assembly.GetTypes();
    661.             for (int i=0; i<allTypes.Length; i++)
    662.                 if (allTypes[i].IsSubclassOf(type)) result.Add(allTypes[i]); //nb: IsAssignableFrom will return derived classes
    663.  
    664.             return result;
    665.         }*/
    666.  
    667.         public static IEnumerable<Type> Subtypes (this Type parent)
    668.         {
    669.             Assembly assembly = Assembly.GetAssembly(parent);  //Assembly[] assembleys = AppDomain.CurrentDomain.GetAssemblies();
    670.             Type[] types = assembly.GetTypes();
    671.             for (int t=0; t<types.Length; t++)
    672.             {
    673.                 Type type = types[t];
    674.                 if (type.IsSubclassOf(parent) && !type.IsInterface && !type.IsAbstract) yield return type;
    675.             }
    676.         }
    677.  
    678.         public static T GetAddComponent<T> (this GameObject go) where T:Component
    679.         {
    680.             T c = go.GetComponent<T>();
    681.             if (c==null) c = go.AddComponent<T>();
    682.             return c;
    683.         }
    684.  
    685.         public static void ReflectionReset<T> (this T obj)
    686.         {
    687.             Type type = obj.GetType();
    688.             T empty = (T)Activator.CreateInstance(type);
    689.          
    690.             foreach (FieldInfo field in type.UsableFields(nonPublic:true)) field.SetValue(obj, field.GetValue(empty));
    691.             foreach (PropertyInfo prop in type.UsableProperties(nonPublic:true)) prop.SetValue(obj, prop.GetValue(empty,null), null);
    692.         }
    693.  
    694.         public static T ReflectionCopy<T> (this T obj)
    695.         {
    696.             Type type = obj.GetType();
    697.             T copy = (T)Activator.CreateInstance(type);
    698.  
    699.             foreach (FieldInfo field in type.UsableFields(nonPublic:true)) field.SetValue(copy, field.GetValue(obj));
    700.             foreach (PropertyInfo prop in type.UsableProperties(nonPublic:true)) prop.SetValue(copy, prop.GetValue(obj,null), null);
    701.  
    702.             return copy;
    703.         }
    704.  
    705.         public static void ReflectionCopyFrom<T> (this T dst, object src)
    706.         {
    707.             Type dstType = dst.GetType();
    708.             Type srcType = src.GetType();
    709.  
    710.             foreach (FieldInfo dstField in dstType.UsableFields(nonPublic:true))
    711.             {
    712.                 FieldInfo srcField = srcType.GetField(dstField.Name);
    713.                 if (srcField != null && srcField.FieldType == dstField.FieldType) dstField.SetValue(dst, srcField.GetValue(src));
    714.             }
    715.  
    716.  
    717.             //foreach (PropertyInfo prop in type.UsableProperties(nonPublic:true)) prop.SetValue(copy, prop.GetValue(obj,null), null);
    718.         }
    719.  
    720.  
    721.         public static object Parse (this string s, Type t)
    722.         {
    723.             //better than creating xml serializer each time. Reverse to "ToString" function
    724.  
    725.             if (s.Contains("=")) s = s.Remove(0, s.IndexOf('=')+1); //removing everything before =
    726.  
    727.             object r = null;
    728.             try
    729.             {
    730.                 if (t == typeof(float))
    731.                 {
    732.                     float f;
    733.                     if (float.TryParse(s, NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out f))
    734.                     {
    735.                         r = f;
    736.                     }
    737.                     else if (float.TryParse(s, out f))
    738.                     {
    739.                         r = f;
    740.                     }
    741.                     else if (float.TryParse(s, NumberStyles.Float, System.Globalization.CultureInfo.CurrentCulture.NumberFormat, out f))
    742.                     {
    743.                         r = f;
    744.                     }
    745.                 }
    746.                 else if (t == typeof(int))
    747.                 {
    748.                     r = int.Parse(s);
    749.                 }
    750.             else if (t == typeof(bool)) r = bool.Parse(s);
    751.             else if (t == typeof(string)) r = s;
    752.             else if (t == typeof(byte)) r = byte.Parse(s);
    753.             else if (t == typeof(short)) r = short.Parse(s);
    754.             else if (t == typeof(long)) r = long.Parse(s);
    755.             else if (t == typeof(double)) r = double.Parse(s);
    756.             else if (t == typeof(char)) r = char.Parse(s);
    757.             else if (t == typeof(decimal)) r = decimal.Parse(s);
    758.             else if (t == typeof(sbyte)) r = sbyte.Parse(s);
    759.             else if (t == typeof(uint)) r = uint.Parse(s);
    760.             else if (t == typeof(ulong)) r = ulong.Parse(s);
    761.             else return null;
    762.             }
    763.             catch(Exception x)
    764.             {
    765.                 Debug.LogError(x + ": " + s);
    766.             }
    767.             return r;
    768.         }
    769.  
    770.         public static float GetInterpolated (this float[,] array, float x, float z)
    771.         {
    772.             int sizeX = array.GetLength(0);
    773.             int sizeY = array.GetLength(1);
    774.          
    775.             int px = (int)x;
    776.             int nx = px+1; if (nx >= sizeX) nx = sizeX-1;
    777.  
    778.             int py = (int)z;
    779.             int ny = py+1; if (ny >= sizeY) ny = sizeY-1;
    780.  
    781.             float percentX = x-px;
    782.             float percentZ = z-py;
    783.  
    784.             float val_fy = array[px,py]*(1-percentX) + array[nx,py]*percentX;
    785.             float val_cy = array[px,ny]*(1-percentX) + array[nx,ny]*percentX;
    786.             float val = val_fy*(1-percentZ) + val_cy*percentZ;
    787.  
    788.             return val;
    789.         }
    790.  
    791.         public static bool isPlaying
    792.         {get{
    793.             #if UNITY_EDITOR
    794.                 return UnityEditor.EditorApplication.isPlaying; //if not playing
    795.             #else
    796.                 return true;
    797.             #endif
    798.         }}
    799.  
    800.         public static bool IsEditor ()
    801.         {
    802.             #if UNITY_EDITOR
    803.                 return
    804.                     !UnityEditor.EditorApplication.isPlaying; //if not playing
    805.                     //(UnityEditor.EditorWindow.focusedWindow != null && UnityEditor.EditorWindow.focusedWindow.GetType() == System.Type.GetType("UnityEditor.GameView,UnityEditor")) //if game view is focused
    806.                     //UnityEditor.SceneView.lastActiveSceneView == UnityEditor.EditorWindow.focusedWindow; //if scene view is focused
    807.             #else
    808.                 return false;
    809.             #endif
    810.         }
    811.  
    812.         public static bool IsSelected (Transform transform)
    813.         {
    814.             #if UNITY_EDITOR
    815.                 return UnityEditor.Selection.activeTransform == transform;
    816.             #else
    817.                 return false;
    818.             #endif
    819.         }
    820.  
    821.         public static Camera GetMainCamera ()
    822.         {
    823.             if (IsEditor())
    824.             {
    825.                 #if UNITY_EDITOR
    826.                 if (UnityEditor.SceneView.lastActiveSceneView==null) return null;
    827.                 else return UnityEditor.SceneView.lastActiveSceneView.camera;
    828.                 #else
    829.                 return null;
    830.                 #endif
    831.             }
    832.             else
    833.             {
    834.                 Camera mainCam = Camera.main;
    835.                 if (mainCam==null) mainCam = GameObject.FindObjectOfType<Camera>(); //in case it was destroyed or something
    836.                 return mainCam;
    837.             }
    838.         }
    839.  
    840.         public static Vector3[] GetCamPoses (bool genAroundMainCam=true, string genAroundTag=null, Vector3[] camPoses=null)
    841.         {
    842.             if (IsEditor())
    843.             {
    844.                 #if UNITY_EDITOR
    845.                 if (UnityEditor.SceneView.lastActiveSceneView==null || UnityEditor.SceneView.lastActiveSceneView.camera==null) return new Vector3[0]; //this happens right after script compile
    846.                 if (camPoses==null || camPoses.Length!=1) camPoses = new Vector3[1];
    847.                 camPoses[0] = UnityEditor.SceneView.lastActiveSceneView.camera.transform.position;
    848.                 #else
    849.                 camPoses = new Vector3[1];
    850.                 #endif
    851.             }
    852.             else
    853.             {
    854.                 //finding objects with tag
    855.                 GameObject[] taggedObjects = null;
    856.                 if (genAroundTag!=null && genAroundTag.Length!=0) taggedObjects = GameObject.FindGameObjectsWithTag(genAroundTag);
    857.  
    858.                 //calculating cams array length and rescaling it
    859.                 int camPosesLength = 0;
    860.                 if (genAroundMainCam) camPosesLength++;
    861.                 if (taggedObjects !=null) camPosesLength += taggedObjects.Length;
    862.              
    863.                 if (camPosesLength == 0) { Debug.LogError("No Main Camera to deploy"); return new Vector3[0]; }
    864.                 if (camPoses == null || camPosesLength != camPoses.Length) camPoses = new Vector3[camPosesLength];
    865.              
    866.                 //filling cams array
    867.                 int counter = 0;
    868.                 if (genAroundMainCam)
    869.                 {
    870.                     Camera mainCam = Camera.main;
    871.                     if (mainCam==null) mainCam = GameObject.FindObjectOfType<Camera>(); //in case it was destroyed or something
    872.                     camPoses[0] = mainCam.transform.position;
    873.                     counter++;
    874.                 }
    875.                 if (taggedObjects != null)
    876.                     for (int i=0; i<taggedObjects.Length; i++) camPoses[i+counter] = taggedObjects[i].transform.position;
    877.             }
    878.  
    879.             return camPoses;      
    880.         }
    881.  
    882.         public static Vector2 GetMousePosition ()
    883.         {
    884.             if (IsEditor())
    885.             {
    886.                 #if UNITY_EDITOR
    887.                 UnityEditor.SceneView sceneview = UnityEditor.SceneView.lastActiveSceneView;
    888.                 if (sceneview==null || sceneview.camera==null || Event.current==null) return Vector2.zero;
    889.                 Vector2 mousePos = Event.current.mousePosition;
    890.                 mousePos = new Vector2(mousePos.x/sceneview.camera.pixelWidth, mousePos.y/sceneview.camera.pixelHeight);
    891.                 #if UNITY_5_4_OR_NEWER  
    892.                 mousePos *= UnityEditor.EditorGUIUtility.pixelsPerPoint;
    893.                 #endif
    894.                 mousePos.y = 1 - mousePos.y;
    895.                 return mousePos;
    896.                 #else
    897.                 return Input.mousePosition;
    898.                 #endif
    899.             }
    900.             else return Input.mousePosition;
    901.         }
    902.  
    903.         public static void GizmosDrawFrame (Vector3 center, Vector3 size, int resolution, float level = 30)
    904.         {
    905.             Vector3 offset = center-size/2;
    906.          
    907.             Vector3 prevP1=Vector3.zero; Vector3 prevP2=Vector3.zero;
    908.             for (float x=0; x < size.x+0.0001f; x += 1f*size.x/resolution)
    909.             {
    910.                 RaycastHit hit = new RaycastHit();
    911.  
    912.                 Vector3 p1 = new Vector3(offset.x+x, 10000, offset.z);
    913.                 if (Physics.Raycast(new Ray(p1, Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    914.                 else if (Physics.Raycast(new Ray(p1+new Vector3(1,0,0), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    915.                 else if (Physics.Raycast(new Ray(p1+new Vector3(-1,0,0), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    916.                 else if (Physics.Raycast(new Ray(p1+new Vector3(0,0,1), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    917.                 else if (Physics.Raycast(new Ray(p1+new Vector3(0,0,-1), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    918.                 else p1.y = level;
    919.                 if (x>0.0001f) Gizmos.DrawLine(prevP1, p1);
    920.                 prevP1 = p1;
    921.  
    922.                 Vector3 p2 = new Vector3(offset.x+x, 10000, offset.z+size.z);
    923.                 if (Physics.Raycast(new Ray(p2, Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    924.                 else if (Physics.Raycast(new Ray(p2+new Vector3(1,0,0), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    925.                 else if (Physics.Raycast(new Ray(p2+new Vector3(-1,0,0), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    926.                 else if (Physics.Raycast(new Ray(p2+new Vector3(0,0,1), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    927.                 else if (Physics.Raycast(new Ray(p2+new Vector3(0,0,-1), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    928.                 else p2.y = level;
    929.                 if (x>0.0001f) Gizmos.DrawLine(prevP2, p2);
    930.                 prevP2 = p2;
    931.             }
    932.  
    933.             for (float z=0; z < size.z+0.0001f; z += 1f*size.z/resolution)
    934.             {
    935.                 RaycastHit hit = new RaycastHit();
    936.  
    937.                 Vector3 p1 = new Vector3(offset.x, 10000, offset.z+z);
    938.                 if (Physics.Raycast(new Ray(p1, Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    939.                 else if (Physics.Raycast(new Ray(p1+new Vector3(1,0,0), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    940.                 else if (Physics.Raycast(new Ray(p1+new Vector3(-1,0,0), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    941.                 else if (Physics.Raycast(new Ray(p1+new Vector3(0,0,1), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    942.                 else if (Physics.Raycast(new Ray(p1+new Vector3(0,0,-1), Vector3.down*20000), out hit, 20000)) p1.y = hit.point.y;
    943.                 else p1.y = level;
    944.                 if (z>0.0001f) Gizmos.DrawLine(prevP1, p1);
    945.                 prevP1 = p1;
    946.  
    947.                 Vector3 p2 = new Vector3(offset.x+size.x, 10000, offset.z+z);
    948.                 if (Physics.Raycast(new Ray(p2, Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    949.                 else if (Physics.Raycast(new Ray(p2+new Vector3(1,0,0), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    950.                 else if (Physics.Raycast(new Ray(p2+new Vector3(-1,0,0), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    951.                 else if (Physics.Raycast(new Ray(p2+new Vector3(0,0,1), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    952.                 else if (Physics.Raycast(new Ray(p2+new Vector3(0,0,-1), Vector3.down*20000), out hit, 20000)) p2.y = hit.point.y;
    953.                 else p2.y = level;
    954.                 if (z>0.0001f) Gizmos.DrawLine(prevP2, p2);
    955.                 prevP2 = p2;
    956.             }
    957.         }
    958.  
    959.         public static void Planar (this Mesh mesh, float size, int resolution)
    960.         {
    961.             float step = size / resolution;
    962.  
    963.             Vector3[] verts = new Vector3[(resolution+1)*(resolution+1)];
    964.             Vector2[] uvs = new Vector2[verts.Length];
    965.             int[] tris = new int[resolution*resolution*2*3];
    966.  
    967.             int vertCounter = 0;
    968.             int triCounter = 0;
    969.             for (float x=0; x<size+0.001f; x+=step) //including max
    970.                 for (float z=0; z<size+0.001f; z+=step)
    971.             {
    972.                 verts[vertCounter] = new Vector3(x,0,z);
    973.                 uvs[vertCounter] = new Vector2(x/size, z/size);
    974.  
    975.                 if (x>0.001f && z>0.001f)
    976.                 {
    977.                     tris[triCounter] = vertCounter-(resolution+1);        tris[triCounter+1] = vertCounter-1;                    tris[triCounter+2] = vertCounter-resolution-2;
    978.                     tris[triCounter+3] = vertCounter-1;                    tris[triCounter+4] = vertCounter-(resolution+1);    tris[triCounter+5] = vertCounter;
    979.                     triCounter += 6;
    980.                 }
    981.  
    982.                 vertCounter++;
    983.             }
    984.  
    985.             mesh.Clear();
    986.             mesh.vertices = verts;
    987.             mesh.uv = uvs;
    988.             mesh.triangles = tris;
    989.         }
    990.  
    991.  
    992.         public static T Save<T> (this T data, string label="Save Data as Unity Asset", string fileName="Data.asset", UnityEngine.Object undoObj=null, string undoName="Save Data") where T : ScriptableObject, ICloneable
    993.         {
    994.             #if UNITY_EDITOR
    995.             //finding path
    996.             string path= UnityEditor.EditorUtility.SaveFilePanel(label, "Assets", fileName, "asset");
    997.             if (path==null || path.Length==0) return data;
    998.  
    999.             //releasing data on re-save
    1000.             T newData = data;
    1001.             if (UnityEditor.AssetDatabase.Contains(data)) newData = (T)data.Clone();
    1002.  
    1003.             //saving
    1004.             path = path.Replace(Application.dataPath, "Assets");
    1005.             if (undoObj != null) UnityEditor.Undo.RecordObject(undoObj, undoName); //TODO: undo is actually not recordered because the new data is not assigned
    1006.             //undoObj.setDirty = !undoObj.setDirty;
    1007.             UnityEditor.AssetDatabase.CreateAsset(newData, path);
    1008.             if (undoObj != null) UnityEditor.EditorUtility.SetDirty(undoObj);
    1009.  
    1010.             return newData;
    1011.             #else
    1012.             return data;
    1013.             #endif
    1014.         }
    1015.  
    1016.         /*public static object Invoke (object target, string methodName, params object[] paramArray)
    1017.         {
    1018.             Type type = target.GetType();
    1019.             MethodInfo methodInfo = type.GetMethod(methodName);
    1020.             return methodInfo.Invoke(target, paramArray);
    1021.         }
    1022.  
    1023.         public static object StaticInvoke (string className, string methodName, params object[] paramArray)
    1024.         {
    1025.             Type type = Type.GetType(className);
    1026.             MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
    1027.             return methodInfo.Invoke(null, new object[] { paramArray });
    1028.         }*/
    1029.  
    1030.         public static string LogBinary (this int src)
    1031.         {
    1032.             string result = "";
    1033.             for (int i=0; i<32; i++)
    1034.             {
    1035.                 if (i%4==0) result=" "+result;
    1036.                 result = (src & 0x1) + result;
    1037.              
    1038.  
    1039.                 src = src >> 1;
    1040.             }
    1041.             return result;
    1042.         }
    1043.  
    1044.         public static string ToStringArray<T> (this T[] array)
    1045.         {
    1046.             string result = "";
    1047.             for (int i=0; i<array.Length; i++)
    1048.             {
    1049.                 result += array[i].ToString();
    1050.                 if (i!=array.Length-1) result += CustomSerialization.Separator;
    1051.             }
    1052.             return result;
    1053.         }
    1054.  
    1055.         public static Color[] ToColors (this Vector4[] src)
    1056.         {
    1057.             Color[] dst = new Color[src.Length];
    1058.             for (int i=0; i<src.Length; i++)
    1059.                 dst[i] = src[i];
    1060.             return dst;
    1061.         }
    1062.  
    1063.     }//extensions
    1064. }//namespace
    1065.  
     

    Attached Files:

    Funkeys likes this.
  8. Hazkin

    Hazkin

    Joined:
    Sep 11, 2012
    Posts:
    3
    Maybe my solution helps you (prev post)
     
  9. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Thanks for sharing your code! I've adopted some of the changes that should fix comma issues. I really appreciate that!
     
    Funkeys and Hazkin like this.
  10. Nunez-Torrijos

    Nunez-Torrijos

    Joined:
    Mar 3, 2016
    Posts:
    33
    I managed to generate nice and huge size mountain ranges by combining 3 layers of perlin noise with different scales each and a bit of softened masking. The biggest scale was around 1.5 kms in size, as far as i remember. I don't recall the exact recipe at the moment, and it depends on your world size ambitions, and overall player-in-space experience.

    Regarding multitile rivers, I also agree in the need to pre-generate the whole multitile basin. With that in mind, you would need to find a suitable source(s) of the river. Given this, you could generate the rest asuming the following:
    1) flow sense will always be related to terrain slope, water will not flow upwards. Water will flow even with very low slopes. (shader look, path)
    2) the river will always find the least resistance path (no obstacles, more downward slope). (path).
    3) if the river finds itself in a point with no contiguous downward slope, it will fill the depression (rising level and expanding, perhaps even forming a lake), and it will again try to find the path of least resistance with falling slope as level rises, until it can finally flow.
    4) Carve a basin
    5) generate water mesh and assign a shader. (I already bought R.A.M.)
    This over simplification omits ramifications, multiple sources, canyon formation and so on. Yet I don't know how computation intensive it would be. Perhaps too much. And I know this is not easy at all. However, I believe this would yield more credible results than putting nodes here and there randomly to form a spline.

    A generating approach could be to let a low friction ball to fall from the origin, record its falling path and see where it leads. Or perhaps much more simply, follow the slopes. A little bit like the falling object placement, but instead of so many objects, only very few, but with a lot more iterations. Expand and rise level when there is no path forward. End when you reach the sea.

    I've always considered this tool essential to give the player replayability value. At least my plan is avoiding the creation of every chunk of terrain "on the fly" during playtime, as much as possible. I could create everytthing or a great deal on the first load, at the beginning, and then store it. Hence, I won't need to generate it again, I just load chunks on demand. Then, if needed or wanted, I could load new batches of rather far away terrain chunks every once in a while, or I could generate more terrain continuously if needed, but very slowly and on a single thread to avoid affecting gameplay, and storing it immediately. With approaches such as these, It wouldnt hurt to make rivers depending on several chunks.
    Hell, if needed, I could also generate lots of (huge) maps on my own, and then let the player download among a set of thousands of them. To me, it is far more important to have rivers and lakes than to be able to generate everything on the fly.
    I've even considered buying Cascade or EasyRoads3D but i doubt they will work with multi-tile fully-procedural settings such as the ones Mapmagic makes possible.
     
    Last edited: Dec 2, 2018
  11. C_p_H

    C_p_H

    Joined:
    Nov 24, 2014
    Posts:
    153
    @Wright

    Hello, attempting to test MM Demo but got this error in Unity 2018.2.18f1 macOS Metal...
    Code (CSharp):
    1. Assets/MapMagic/Generators/CTSOutputGenerator.cs(257,8): error CS0122: `CTS.CompleteTerrainShader.UpdateShader()' is inaccessible due to its protection level
    Can't launch MapMagic as a result. Need your help ASAP please. Thanks!

    Edit: Archived the CTSOutputGenerator.cs & MM launched so I can resume my evaluation. Just a temporary bypass because I do have CTS in my project so will need a fix when I decide to purchase MM (later today maybe).
     
    Last edited: Dec 3, 2018
  12. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    For now I have two ideas of how this could be made:
    - using the "bake output". The base graph will generate and store it's results in an asset, and then real-time graphs will use this asset as a base map on several chunks similarly to using the RAW Input. But unlike the RAW map, it will store several maps, object and splines.
    - use the "base biome", a kind of biome node that will generate only once, and all of the chunks will use this generated result. This sounds nice, but I'm afraid it would be counter-intuitive to use it: why would the base map is in biome rather than the detail ones?

    Thanks for reporting the issue, I will update the evaluation version tomorrow!
     
  13. ANUBISKONG

    ANUBISKONG

    Joined:
    Nov 16, 2016
    Posts:
    47
    Hi, @Wright
    I want to make a lowpoly style terrain(or just mesh as land), how can I do it with Map Magic only?
    If there is no short way to do this, how can I get noise data from Map Magic so that I can generate mesh by my own code?
     
  14. chingwa

    chingwa

    Joined:
    Dec 4, 2009
    Posts:
    3,790
    My main interest is in creating real-world terrains, and I've been using MapMagic to import and refine an existing RAW height data file. What I would like to be able to do is get to a certain point using these tools and then save out to a terrain object once I'm happy with the height results. All this is fine and I have no trouble, however what I would like to do next is to use that existing terrain as a source input and to apply textures/grass/trees to that terrain using a different map magic editor graph...

    so my question: Is there an input node similar to the 'raw input' node, but instead of getting height from a file I'm loading it directly off an existing terrain object?
     
  15. shedworksdigital

    shedworksdigital

    Joined:
    Nov 7, 2016
    Posts:
    40
    I finally managed to track this one down. It was happening when one of the Unity Objects in the objects list of the generators asset was null. I solved this by wrapping the call to prop.SetValue in a try-catch block, which I noticed you were doing a few lines earlier for the call to field.SetValue. I stopped getting the exception, and my assets are now deserializing properly.
     
  16. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    Maybe you can output the final terrain's height data into a raw file from the first mapmagic and import that raw into the next one?
     
  17. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    Hi, I've got this issue on some of my player's PC:

    FormatException: Input string was not in a correct format.
    at System.Number.ParseSingle (System.String value, System.Globalization.NumberStyles options, System.Globalization.NumberFormatInfo numfmt) [0x00083] in <f2e6809acb14476a81f399aeb800f8f2>:0
    at System.Single.Parse (System.String s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info) [0x00000] in <f2e6809acb14476a81f399aeb800f8f2>:0
    at System.Single.Parse (System.String s) [0x0000b] in <f2e6809acb14476a81f399aeb800f8f2>:0
    at MapMagic.Extensions.Parse (System.String s, System.Type t) [0x0003a] in <e62782007a9443f9a276bcbef0c34d46>:0
    at MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) [0x00869] in <e62782007a9443f9a276bcbef0c34d46>:0
    at MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) [0x00417] in <e62782007a9443f9a276bcbef0c34d46>:0
    at MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) [0x00417] in <e62782007a9443f9a276bcbef0c34d46>:0
    at MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) [0x00417] in <e62782007a9443f9a276bcbef0c34d46>:0
    at MapMagic.GeneratorsAsset.OnAfterDeserialize () [0x000d5] in <e62782007a9443f9a276bcbef0c34d46>:0

    It seems this issue can appear when the window's regional settings set to Ukrainian or Russian.
    Any ideas what may caused this and how to fix it?
     
  18. Deleted User

    Deleted User

    Guest

    Hello there, i got 1 question, can i use a raw or png heigtmap as input terrain, then use mapmagic to had erosion and noise ?
     
  19. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Yes, you can use the Raw Input Node to add 16bit raw heightmap. PNG isn't supported. Watching this video will explain everything. Map Magic Tutorial.
    You can also use the Blend node to add several raw files as tiles if required.
     
  20. Deleted User

    Deleted User

    Guest

    Thank you, i got it now, and i have to use Gaia scanner to convert my png into raw but thats another story

    So main problem, i have this wired texture heatmap


    Its the Ciff preview

    Its on the cliff and sedimentation not anywhere else

     
    Last edited by a moderator: Dec 7, 2018
  21. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Strange you should mention that, because I'm just now getting an issue with seams in textures across tiles with Megasplat! Given it seems to be on cliff and sediment, is it something to do with the erosion node? Heat map makes it a bit clearer. Playing with safe borders on the erosion node doesn't seem to help. Unity 2018.2.15f1 and MM 1.9.4
    Oh, and are the texture previews from the Megasplat texture arrays supposed to appear in the Custom Shader node, because they don't.

    Node.png

    Seam.png

    Heat.png
     
    Last edited: Dec 7, 2018
  22. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Unfortunately it's the matter of the terrain shader, not the terrain generator. You need the other type of asset to do that.

    Not yet, but it's planned for MM2. Here you will be able to import any terrain height, splat, objects, trees and grass data.

    Try updating MM from the Asset Store. This issue was fixed recently (no version change, so you could get no notification).

    A Texture import node could be used. It reads a texture in any format Unity supports, including the PNG.

    It's the way MM1 works - each chunk isn't aware of what's happening in the neighbor one. So generators like blur or erosion, that require access to other pixels create seams at the borders. Try masking these seams with "Safe Border" value - it will make them smoother (but wider) so they could be less noticeable.
    MM2 however is generating margins around each chunk so that the seam effect is almost invisible.
     
    Deleted User and AthrunVLokiz like this.
  23. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    But is that 16bit greyscale? Can it be used as a height map?
     
  24. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    You can try using RGBA Half texture format, but I'm not sure if it will be converted properly. So it's better use RAW in this case, they are 16-bit by default.
     
  25. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    My apologies. You can use a 16bit PNG as a height map :) You don't know how many possibilities this opens up for me. Very happy. Below is an 8192 16bit greyscale PNG as a heightmap. Don't worry about the terracing below sea level, that is me adding depth below the SRTM 0 line. Photoshop is not a great HDR editor.

    EDIT: Sadly there is still some terracing, Unity must convert the image to 8bit :(

    EDIT: RGBA32 works. Will try other formats. RGBA Half works but all the levels are changed. Still it's promising.

    PNG.png

    RGBA 32

    PNG2.png
     
    Last edited: Dec 7, 2018
    protopop and Lars-Steenhoff like this.
  26. Deleted User

    Deleted User

    Guest

    I have better results using the gaia scanner, then stamp, then export, then reimport in mapmagik


     
  27. ANUBISKONG

    ANUBISKONG

    Joined:
    Nov 16, 2016
    Posts:
    47
    Hi, @Wright,
    How can I get the noise data or from Map Magic?
    I tried Matrix.GetInterpolatedValue, but it cause "Array index is out of range" error.
    I tried make a custom OutputGenerator to save height2D value in Process func, but sometimes I got null from it.
     
  28. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Hi All, Is anyone using Megasplat and the Custom Shader node? I have it all working fine but was curious about a couple of things. Is the single Background Texture required? Is that the Control Texture? I ask because it might useful in one biome but not another. I was thinking of just putting a white texture in there. Or can I use a node per biome with different textures from the array? How would they blend at the edges?
    Also in the tutorial it says to turn on 2 layer mode. How is that handled? Is that simply that if 2 textures overlap, the one higher in the list is considered Top and the lower Bottom? And the blending is the global values from the material? Thanks in advance.
     
    Last edited: Dec 8, 2018
  29. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Don't get it quite clear what is the single Background Texture. Is that the bottom layer in the output that has no input? The thing is that the layers are blended like in Photoshop or any other image editor. If all of the layers cannot fill some pixel for 100% then the background is displayed - or image is transparent if there's no background. You can't make the terrain transparent by the standard means, so this layer is mandatory. Yes, you can fill it with white or black - happily MegaSplat supports 256 types at the same speed, so I don't think it will affect performance or limit terrain splats diversity.

    Think of matrix like of a 2D array with an offset, so that pixel coordinates are continuous. For instance, if you have a terrain with a resolution of 512 stored at the zero position use the range 0-511 to get it's values. Matrix[255,255] will return it's center. But if it's a neighbor terrain, next by the X axis use the range 512-1023 to get x values. The center will be matrix[767,255]. You can use the negative coordinate to get values from the terrains with negative positions.
     
  30. Deleted User

    Deleted User

    Guest

    I just made this 300km terrain with map magic, using all my ram, its composed of 10x10 1k resolution heightmap, its incredible smooth.

    But when i try to add CTS, or VS or show heightmap, it crash, possible due to the size of the map
     

    Attached Files:

  31. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Possibly it's worth trying not to 'pin' it all at once, but let it generate on-the-go?
     
    Deleted User likes this.
  32. Deleted User

    Deleted User

    Guest

    It worked, thank, but all the tree are underground, at the flat bottom

    Also i was able to put CTS on the Whole terrain without crash

    I have check the relative height box, but maybe im missing terrain data
     
    Last edited by a moderator: Dec 9, 2018
  33. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    Thanks for the reply! For I've made some modifications to MapMagic's code, updating can be very time consuming(remake these changes), can you point out where should I change in the code so I can just fix it myself withou refresh the whole asset?
     
  34. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    And I've met a rare issue with some of the players that can meet this error when generating terrains:

    Error generating chunk: MapMagic.Coord x:-1 z:-1: System.IndexOutOfRangeException: Index was outside the bounds of the array.
    at MapMagic.ArrayTools.Order (System.Int32[] array, System.Int32[] order, System.Int32 max, System.Int32 steps, System.Int32[] stepsArray) [0x0003a] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\ArrayTools.cs:294
    at MapMagic.Erosion.ErosionIteration (MapMagic.Matrix heights, MapMagic.Matrix erosion, MapMagic.Matrix sedimentSum, MapMagic.CoordRect area, System.Single erosionDurability, System.Single erosionAmount, System.Single sedimentAmount, System.Int32 erosionFluidityIterations, System.Single ruffle, MapMagic.Matrix torrents, MapMagic.Matrix sediments, System.Int32[] stepsArray, System.Int32[] heightsInt, System.Int32[] order) [0x00093] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\Erosion.cs:342
    at MapMagic.ErosionGenerator.Generate (MapMagic.CoordRect rect, MapMagic.Chunk+Results results, MapMagic.Chunk+Size terrainSize, System.Int32 seed, System.Func`2[T,TResult] stop) [0x0019d] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Generators\MatrixGenerators.cs:1492
    at MapMagic.GeneratorsAsset.GenerateWithPriors (MapMagic.Generator gen, MapMagic.CoordRect rect, MapMagic.Chunk+Results results, MapMagic.Chunk+Size terrainSize, System.Int32 seed, System.Func`2[T,TResult] stop) [0x000b2] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\GeneratorsAsset.cs:678
    at MapMagic.GeneratorsAsset.GenerateWithPriors (MapMagic.Generator gen, MapMagic.CoordRect rect, MapMagic.Chunk+Results results, MapMagic.Chunk+Size terrainSize, System.Int32 seed, System.Func`2[T,TResult] stop) [0x00057] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\GeneratorsAsset.cs:666
    at MapMagic.GeneratorsAsset.Generate (MapMagic.CoordRect rect, MapMagic.Chunk+Results results, MapMagic.Chunk+Size terrainSize, System.Int32 seed, System.Collections.Generic.HashSet`1[System.Type]& changedTypes, System.Func`2[T,TResult] stop) [0x00183] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\GeneratorsAsset.cs:320
    at MapMagic.GeneratorsAsset.Calculate (MapMagic.CoordRect rect, MapMagic.Chunk+Results results, MapMagic.Chunk+Size terrainSize, System.Int32 seed, System.Func`2[T,TResult] stop) [0x00011] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\GeneratorsAsset.cs:235
    at MapMagic.Chunk.ThreadFn () [0x0005b] in G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\Chunk.cs:236
    UnityEngine.DebugLogHandler:Internal_Log()
    UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
    UnityEngine.Logger:Log(LogType, Object)
    UnityEngine.Debug:LogError(Object)
    MapMagic.Chunk:ThreadFn() (at G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\Chunk.cs:239)
    MapMagic.ThreadWorker:ThreadFn() (at G:\Work\Project Survisland\Project\Survisland2018\Assets\MapMagic\Runtime\Main\ThreadWorker.cs:533)
    System.Threading.ThreadHelper:ThreadStart_Context(Object)
    System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)
    System.Threading.ExecutionContext:Run(ExecutionContext, ContextCallback, Object, Boolean)
    System.Threading.ExecutionContext:Run(ExecutionContext, ContextCallback, Object)
    System.Threading.ThreadHelper:ThreadStart()

    (Filename: G:/Work/Project Survisland/Project/Survisland2018/Assets/MapMagic/Runtime/Main/Chunk.cs Line: 239)

    But some other players don't have this issue, any ideas?
     
  35. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    By updating Mapmagic to the latest version, I got this error in editor:

    IndexOutOfRangeException: Index was outside the bounds of the array.
    MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) (at Assets/MapMagic/Main/CustomSerialization.cs:468)
    MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) (at Assets/MapMagic/Main/CustomSerialization.cs:398)
    MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) (at Assets/MapMagic/Main/CustomSerialization.cs:398)
    MapMagic.CustomSerialization.ReadClass (System.Int32 slotNum, System.Collections.Generic.List`1[T] classes, System.Collections.Generic.List`1[T] objects, System.Collections.Generic.List`1[T] floats, System.Collections.Generic.List`1[T] references) (at Assets/MapMagic/Main/CustomSerialization.cs:398)
    MapMagic.GeneratorsAsset.OnAfterDeserialize () (at Assets/MapMagic/Main/GeneratorsAsset.cs:1148)

    And all my saved node graphs are not able to be shown in the editor
     
    Last edited: Dec 11, 2018
  36. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    Could you please email me the data so I could look into it? The most important thing is not to overwrite it accidentally with an empty one.

    And speaking of the previous error - is there any way to reproduce it? When does it happen? Does it occur all the time for some players, or it happens sporadically for all the players?
     
  37. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    It does happen everytime for some players, I've got one player in France meet this issue everytime when mapmagic start to generate terrains, and the output_log file is full of this error message. Some other players does not seem to have this issue. We only know it happens on build because we don't have this issue either on build or in editor. It all worked fine before in unity 5.6 and mapmagic 1.9.2.
    I've reverted back to previous mapmagic 1.9.4 version for the new version flushed out all of my graphs.

    Just sent you an email with the output_log and my graphs
     
    Last edited: Dec 11, 2018
  38. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    Hi All, I help a little help. I'm using MegaSplat and I need to assign a Macro Texture and Normal map to the instance of the MegaSplat material on each chunk as it is generated. So the question is, on which MM Event would it be best to do this? And if anyone can point me in the direction of some code that shows how to access the properties of a custom Terrain Material, it would be appreciated.
    Is it possible to apply a height map for each chunk on a MM event? Thanks.
     
    Last edited: Dec 11, 2018
  39. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    I'm finding an inability to go past 269,000km any ideas? =D
    That's at 1024 size, 128 res, by the way.

    add:
    It seems to be caused by line 322 of SpatialHash.cs. The index is going over by one for some reason. I added a check and it works, tested up to 1,019,000 kilometers at 1024 size/128 res
    Code (CSharp):
    1.                     if (cellNum > cells.Length - 1) { continue; }
    2.                     else if (cellNum < 0) { continue; }
    3.                     Cell cell = cells[cellNum];
    Not sure, but it might be related to the Scatter node?
     
    Last edited: Dec 13, 2018
  40. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    One million kilometers? Really? Not units?

    Spatial Hash is the positions object, like map/matrix, the green one. I guess it's a floating point limitation - if the object spawns at the chunk edge it could be "rounded" so that it will be placed out of the chunk area. It doesn't allow spawning objects closer than 1 unit to the edge by design, but I guess at these ranges rounding takes more than one unit.

    If you are unsure then use OnApplyCompleted. This is the one that called after all is done, and it is called in main thread.

    Obviously, it's mapMagic.customTerrainMaterial. But keep in mind that it's just a template that is used to clone materials assigned to terrains. In order to change the real materials applied to chunks use terran.materialTemplate directly.

    In OnApplyCompleted you can read the terrain data and change it the way you like. Actually, terrain welding works this way.
     
  41. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    that makes sense, I thought it was something like that. And yes I went to 1,019,000,000 units or 1,019,000km to check. I have two players that made it to 269,000km and found the world generating flat XD

    2018.3 now released says it supports multiple physics scenes =o I'm hoping that means we can define multiple locales and be gone with floating point problems!
     
  42. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    An issue with 2018.3.0f2 and terrain instancing. If I preview a texture on the terrain without instancing on, it works fine (see screenshot 1). If I turn instancing on it goes crazy (Screenshot 2). Empty project, just Map Magic. Same thing happens in an empty project with just MegaSplat installed also.

    MM2.png MM1.png
     
  43. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    That would be very cool. :)
     
  44. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    https://forum.unity.com/threads/separating-physics-scenes.597697/#post-3996724
    it doesn't necessarily do that, I wasn't sure what it meant at all really. I got it to work today though, in the above thread. What it does is separates the physics of a loaded scene into a completely separate system if you tell it to. I'm going to use this to track multiple players on a headless server (no graphics) by keeping as many different PhysicsScenes as I need to keep the players from bumping into each other while still allowing them to be thousands of kilometers apart on their own machines using MM WorldShift.

    So it doesn't let you define a new origin/locale, which would be really cool, but it still obviously has a lot of uses. You could reuse physics layers unlimited so long as each scene doesn't have to interact with one another, or even sync transform across scenes if you needed to. Great to have new tools! Not sure if this benefits MM in any way though XD
     
  45. Wright

    Wright

    Joined:
    Feb 26, 2013
    Posts:
    2,276
    That was a pretty long journey :)

    Thanks for reporting an issue. I will look into it, hopefully it could be solved with a shader. Otherwise previewed terrains should automatically turn off instancing, that seems not an elegant solution for me.
     
  46. Bodyclock

    Bodyclock

    Joined:
    May 8, 2018
    Posts:
    172
    I suspect it's related to this issue. I have the same problem when I preview when using Megasplat. On that I have a couple of questions on the Custom Shader node for Megasplat.
    You say in the tutorial that you can use MaterialPropertyBlock by uncommenting the code. I don't intend to have pinned terrains at runtime, so this would be a better option for me?
    I notice in the code that blocks for Megasplat wetness and puddles are commented out. I don't need dynamic flow or anything that would require painting on the terrain. Is there a problem uncommenting and using them?
     
  47. kepesh

    kepesh

    Joined:
    Dec 29, 2017
    Posts:
    92
    I'm about to switch to Map Magic from Terrain Composer 2 (because TC2 doesn't update it anymore). But now I saw that you're working on Map Magic 2. When are you planning on releasing Map Magic 2?
     
    ftejada likes this.
  48. SSL7

    SSL7

    Joined:
    Mar 23, 2016
    Posts:
    349
    keep in mind that mapmagic 2 will be a free update, so you can start messing around with current version :)
     
  49. Ancient76

    Ancient76

    Joined:
    Nov 12, 2018
    Posts:
    19
    Hi,

    Ok, Map Magic or World Streamer or Sectr, or someting else?

    Size of the terrain will be around 8x8km.
     
  50. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    MapMagic is very different from WorldStream and Sectr. Those two are primarily streaming assets and won't help you create terrains at all, where MM is an environment creation package with built-in enabling/disabling of distant terrains.