Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

[Released]Terrain Slicing & Dynamic Loading Kit

Discussion in 'Assets and Asset Store' started by gilley033, Nov 5, 2013.

  1. gilley033


    Jul 10, 2012
    The smallest size of the slices you will be able to produce will depend on the resolution of your base terrain. If you can provide those, I can tell you what the smallest terrain you can produce is. I'll need the heightmap, basemap, control texture resolution, as well as the detail resolution and detail resolution per patch.

    The reason for this is that the slicing process divides your resolution based on the number of slices produced. So if you had a heightmap of 1025 on your base terrain and sliced it into a 4 x 4 grid, the resulting slices would have heightmaps of 257. There are minimum values for each resolution (33 for heightmaps, 16 for base and alphamap. The detail resolution minimum is calculated as current detail resolution divided by detail resolution per patch, as Unity will not allow you to have a terrain with a detail resolution smaller than the detail resolution per patch) that a terrain must have, so unfortunately this means the terrain can only be divided a certain number of times.

    As for your other questions, each slice is an individual terrain, yes, so you can manipulate it without affecting any other terrain. It will generate objects in the scene hierarchy if that is what you mean, although that could potentially cause issues since you will be producing an extremely large number of terrain. For this reason, the tool also has support for creating prefabs in your project hierarchy, and then you can skip adding the terrains to the current scene (although you could both add them to the scene and produce the prefabs, as I just noted, this could cause issues).

    Finally, the tool supports alternate naming conventions, which you may need to make use of if World Streamer requires the terrain slices to be named a certain way.

    Thanks for you interest!
  2. Ninlilizi


    Sep 19, 2016
    I'm trying to use this with Unity 5.5.1 to slice a terrain grid made with TC2 into smaller chunk.
    I'm having a problem where after creating the slicer configuration thing, and selecting terrain grid the bit where you enter the range to slice I'm unable to enter anything.
    The input boxes do not work, and do not allow me to enter anything.

  3. The-Britain


    Mar 31, 2015
    The problem I am running into is cutting a 100kmx100km chunk into 100mx100m chunks. The current tool I have will do this just fine, but I run out of memory at that scale. Here's the code for it, I swiped it from this guys Git. It works great and I can set the resolution and splat res for each individual new chunk, and chunk size, but when I am generating chunks from that large of a terrain, it consumes every bit of my 32GB of memory. From what I can tell, it stores all of them until the final generation, and then outputs them. I was hoping yours would AT LEAST have the tools present in this free solution, and also get past this memory barrier. Additionally, it also automatically names them in a way friendly to World Streamer:

    Code (csharp):
    2. using UnityEngine;
    3. using UnityEditor;
    5. public class SplitTerrain : EditorWindow
    6. {
    7.     [MenuItem("Split/Split Terrain")]
    8.     static void Init()
    9.     {
    10.         GetWindow<SplitTerrain>();
    11.     }
    13.     Transform transform;
    14.     int xLen = 3; // Match with TerrainManager if using
    15.     int zLen = 6;
    16.     // Must be power of two plus 1
    17.     int newHeightRes = 65; // Started with 513 in New Terrain
    18.     int newDetailRes = 256; // Started with 1024 in New Terrain
    19.     int newSplatRes = 128; // Started with 512 in New Terrain
    21.     public void OnGUI()
    22.     {
    23.         transform = (Transform)EditorGUILayout.ObjectField("Terrain to split", transform, typeof(Transform), true);
    24.         xLen = EditorGUILayout.IntField("Split x axis count", xLen);
    25.         zLen = EditorGUILayout.IntField("Split z axis count", zLen);
    26.         newHeightRes = EditorGUILayout.IntField("New heightmap res", newHeightRes);
    27.         newDetailRes = EditorGUILayout.IntField("New detail res", newDetailRes);
    28.         newSplatRes = EditorGUILayout.IntField("New splat res", newSplatRes);
    30.         if (GUILayout.Button("Split!"))
    31.         {
    32.             if (transform == null)
    33.             {
    34.                 Debug.LogWarning("No terrain found");
    35.                 return;
    36.             }
    38.             Terrain origTerrain = transform.GetComponent<Terrain>();
    39.             if (origTerrain == null)
    40.             {
    41.                 Debug.LogWarning("No terrain found on transform");
    42.                 return;
    43.             }
    45.             if (xLen < 1)
    46.                 xLen = 1;
    47.             if (zLen < 1)
    48.                 zLen = 1;
    49.             for (int x = 0; x < xLen; x++)
    50.             {
    51.                 for (int z = 0; z < zLen; z++)
    52.                 {
    53.                     EditorUtility.DisplayProgressBar("Splitting Terrain", "Copying heightmap, detail, splat, and trees", (float)((x * zLen) + z) / (xLen * zLen));
    54.                     float xMin = origTerrain.terrainData.size.x / xLen * x;
    55.                     float xMax = origTerrain.terrainData.size.x / xLen * (x + 1);
    56.                     float zMin = origTerrain.terrainData.size.z / zLen * z;
    57.                     float zMax = origTerrain.terrainData.size.z / zLen * (z + 1);
    58.                     copyTerrain(origTerrain, string.Format("{0}{1}_{2}",, x, z), xMin, xMax, zMin, zMax, newHeightRes, newDetailRes, newSplatRes);
    59.                 }
    60.             }
    61.             EditorUtility.ClearProgressBar();
    63.             for (int x = 0; x < xLen; x++)
    64.             {
    65.                 for (int z = 0; z < zLen; z++)
    66.                 {
    67.                     GameObject center = GameObject.Find(string.Format("{0}{1}_{2}",, x, z));
    68.                     GameObject left = GameObject.Find(string.Format("{0}{1}_{2}",, x - 1, z));
    69.                     GameObject top = GameObject.Find(string.Format("{0}{1}_{2}",, x, z + 1));
    70.                     stitchTerrain(center, left, top);
    71.                 }
    72.             }
    73.         }
    74.     }
    76.     void copyTerrain(Terrain origTerrain, string newName, float xMin, float xMax, float zMin, float zMax, int heightmapResolution, int detailResolution, int alphamapResolution)
    77.     {
    78.         if (heightmapResolution < 33 || heightmapResolution > 4097)
    79.         {
    80.             Debug.Log("Invalid heightmapResolution " + heightmapResolution);
    81.             return;
    82.         }
    83.         if (detailResolution < 0 || detailResolution > 4048)
    84.         {
    85.             Debug.Log("Invalid detailResolution " + detailResolution);
    86.             return;
    87.         }
    88.         if (alphamapResolution < 16 || alphamapResolution > 2048)
    89.         {
    90.             Debug.Log("Invalid alphamapResolution " + alphamapResolution);
    91.             return;
    92.         }
    94.         if (xMin < 0 || xMin > xMax || xMax > origTerrain.terrainData.size.x)
    95.         {
    96.             Debug.Log("Invalid xMin or xMax");
    97.             return;
    98.         }
    99.         if (zMin < 0 || zMin > zMax || zMax > origTerrain.terrainData.size.z)
    100.         {
    101.             Debug.Log("Invalid zMin or zMax");
    102.             return;
    103.         }
    105.         if (AssetDatabase.FindAssets(newName).Length != 0)
    106.         {
    107.             Debug.Log("Asset with name " + newName + " already exists");
    108.             return;
    109.         }
    111.         TerrainData td = new TerrainData();
    112.         GameObject gameObject = Terrain.CreateTerrainGameObject(td);
    113.         Terrain newTerrain = gameObject.GetComponent<Terrain>();
    115.         if (!AssetDatabase.IsValidFolder("Assets/Resources"))
    116.             AssetDatabase.CreateFolder("Assets", "Resources");
    117.         // Must do this before Splat
    118.         AssetDatabase.CreateAsset(td, "Assets/Resources/" + newName + ".asset");
    120.         // Copy over all vars
    121.         newTerrain.bakeLightProbesForTrees = origTerrain.bakeLightProbesForTrees;
    122.         newTerrain.basemapDistance = origTerrain.basemapDistance;
    123.         newTerrain.castShadows = origTerrain.castShadows;
    124.         newTerrain.collectDetailPatches = origTerrain.collectDetailPatches;
    125.         newTerrain.detailObjectDensity = origTerrain.detailObjectDensity;
    126.         newTerrain.detailObjectDistance = origTerrain.detailObjectDistance;
    127.         newTerrain.drawHeightmap = origTerrain.drawHeightmap;
    128.         newTerrain.drawTreesAndFoliage = origTerrain.drawTreesAndFoliage;
    129.         newTerrain.editorRenderFlags = origTerrain.editorRenderFlags;
    130.         newTerrain.heightmapMaximumLOD = origTerrain.heightmapMaximumLOD;
    131.         newTerrain.heightmapPixelError = origTerrain.heightmapPixelError;
    132.         newTerrain.legacyShininess = origTerrain.legacyShininess;
    133.         newTerrain.legacySpecular = origTerrain.legacySpecular;
    134.         newTerrain.lightmapIndex = origTerrain.lightmapIndex;
    135.         newTerrain.lightmapScaleOffset = origTerrain.lightmapScaleOffset;
    136.         newTerrain.materialTemplate = origTerrain.materialTemplate;
    137.         newTerrain.materialType = origTerrain.materialType;
    138.         newTerrain.realtimeLightmapIndex = origTerrain.realtimeLightmapIndex;
    139.         newTerrain.realtimeLightmapScaleOffset = origTerrain.realtimeLightmapScaleOffset;
    140.         newTerrain.reflectionProbeUsage = origTerrain.reflectionProbeUsage;
    141.         newTerrain.treeBillboardDistance = origTerrain.treeBillboardDistance;
    142.         newTerrain.treeCrossFadeLength = origTerrain.treeCrossFadeLength;
    143.         newTerrain.treeDistance = origTerrain.treeDistance;
    144.         newTerrain.treeMaximumFullLODCount = origTerrain.treeMaximumFullLODCount;
    146.         td.splatPrototypes = origTerrain.terrainData.splatPrototypes;
    147.         td.treePrototypes = origTerrain.terrainData.treePrototypes;
    148.         td.detailPrototypes = origTerrain.terrainData.detailPrototypes;
    150.         // Get percent of original
    151.         float xMinNorm = xMin / origTerrain.terrainData.size.x;
    152.         float xMaxNorm = xMax / origTerrain.terrainData.size.x;
    153.         float zMinNorm = zMin / origTerrain.terrainData.size.z;
    154.         float zMaxNorm = zMax / origTerrain.terrainData.size.z;
    155.         float dimRatio1, dimRatio2;
    157.         // Height
    158.         td.heightmapResolution = heightmapResolution;
    159.         float[,] heights = origTerrain.terrainData.GetHeights(
    160.             Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.heightmapWidth),
    161.             Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.heightmapHeight),
    162.             Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.heightmapWidth),
    163.             Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.heightmapHeight));
    164.         float[,] newHeights = new float[heightmapResolution, heightmapResolution];
    165.         dimRatio1 = (float)heights.GetLength(0) / heightmapResolution;
    166.         dimRatio2 = (float)heights.GetLength(1) / heightmapResolution;
    167.         for (int i = 0; i < newHeights.GetLength(0); i++)
    168.         {
    169.             for (int j = 0; j < newHeights.GetLength(1); j++)
    170.             {
    171.                 newHeights[i, j] = heights[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2)];
    172.             }
    173.         }
    174.         td.SetHeightsDelayLOD(0, 0, newHeights);
    176.         // Detail
    177.         td.SetDetailResolution(detailResolution, 8); // Default? Haven't messed with resolutionPerPatch
    178.         for (int layer = 0; layer < origTerrain.terrainData.detailPrototypes.Length; layer++)
    179.         {
    180.             int[,] detailLayer = origTerrain.terrainData.GetDetailLayer(
    181.                 Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.detailWidth),
    182.                 Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.detailHeight),
    183.                 Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.detailWidth),
    184.                 Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.detailHeight),
    185.                 layer);
    186.             int[,] newDetailLayer = new int[detailResolution, detailResolution];
    187.             dimRatio1 = (float)detailLayer.GetLength(0) / detailResolution;
    188.             dimRatio2 = (float)detailLayer.GetLength(1) / detailResolution;
    189.             for (int i = 0; i < newDetailLayer.GetLength(0); i++)
    190.             {
    191.                 for (int j = 0; j < newDetailLayer.GetLength(1); j++)
    192.                 {
    193.                     newDetailLayer[i, j] = detailLayer[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2)];
    194.                 }
    195.             }
    196.             td.SetDetailLayer(0, 0, layer, newDetailLayer);
    197.         }
    199.         // Splat
    200.         td.alphamapResolution = alphamapResolution;
    201.         float[,,] alphamaps = origTerrain.terrainData.GetAlphamaps(
    202.             Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.alphamapWidth),
    203.             Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.alphamapHeight),
    204.             Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.alphamapWidth),
    205.             Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.alphamapHeight));
    206.         // Last dim is always origTerrain.terrainData.splatPrototypes.Length so don't ratio
    207.         float[,,] newAlphamaps = new float[alphamapResolution, alphamapResolution, alphamaps.GetLength(2)];
    208.         dimRatio1 = (float)alphamaps.GetLength(0) / alphamapResolution;
    209.         dimRatio2 = (float)alphamaps.GetLength(1) / alphamapResolution;
    210.         for (int i = 0; i < newAlphamaps.GetLength(0); i++)
    211.         {
    212.             for (int j = 0; j < newAlphamaps.GetLength(1); j++)
    213.             {
    214.                 for (int k = 0; k < newAlphamaps.GetLength(2); k++)
    215.                 {
    216.                     newAlphamaps[i, j, k] = alphamaps[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2), k];
    217.                 }
    218.             }
    219.         }
    220.         td.SetAlphamaps(0, 0, newAlphamaps);
    222.         // Tree
    223.         for (int i = 0; i < origTerrain.terrainData.treeInstanceCount; i++)
    224.         {
    225.             TreeInstance ti = origTerrain.terrainData.treeInstances[i];
    226.             if (ti.position.x < xMinNorm || ti.position.x >= xMaxNorm)
    227.                 continue;
    228.             if (ti.position.z < zMinNorm || ti.position.z >= zMaxNorm)
    229.                 continue;
    230.             ti.position = new Vector3(((ti.position.x * origTerrain.terrainData.size.x) - xMin) / (xMax - xMin), ti.position.y, ((ti.position.z * origTerrain.terrainData.size.z) - zMin) / (zMax - zMin));
    231.             newTerrain.AddTreeInstance(ti);
    232.         }
    234.         gameObject.transform.position = new Vector3(origTerrain.transform.position.x + xMin, origTerrain.transform.position.y, origTerrain.transform.position.z + zMin);
    235. = newName;
    237.         // Must happen after setting heightmapResolution
    238.         td.size = new Vector3(xMax - xMin, origTerrain.terrainData.size.y, zMax - zMin);
    240.         AssetDatabase.SaveAssets();
    241.     }
    243.     void stitchTerrain(GameObject center, GameObject left, GameObject top)
    244.     {
    245.         if (center == null)
    246.             return;
    247.         Terrain centerTerrain = center.GetComponent<Terrain>();
    248.         float[,] centerHeights = centerTerrain.terrainData.GetHeights(0, 0, centerTerrain.terrainData.heightmapWidth, centerTerrain.terrainData.heightmapHeight);
    249.         if (top != null)
    250.         {
    251.             Terrain topTerrain = top.GetComponent<Terrain>();
    252.             float[,] topHeights = topTerrain.terrainData.GetHeights(0, 0, topTerrain.terrainData.heightmapWidth, topTerrain.terrainData.heightmapHeight);
    253.             if (topHeights.GetLength(0) != centerHeights.GetLength(0))
    254.             {
    255.                 Debug.Log("Terrain sizes must be equal");
    256.                 return;
    257.             }
    258.             for (int i = 0; i < centerHeights.GetLength(1); i++)
    259.             {
    260.                 centerHeights[centerHeights.GetLength(0) - 1, i] = topHeights[0, i];
    261.             }
    262.         }
    263.         if (left != null)
    264.         {
    265.             Terrain leftTerrain = left.GetComponent<Terrain>();
    266.             float[,] leftHeights = leftTerrain.terrainData.GetHeights(0, 0, leftTerrain.terrainData.heightmapWidth, leftTerrain.terrainData.heightmapHeight);
    267.             if (leftHeights.GetLength(0) != centerHeights.GetLength(0))
    268.             {
    269.                 Debug.Log("Terrain sizes must be equal");
    270.                 return;
    271.             }
    272.             for (int i = 0; i < centerHeights.GetLength(0); i++)
    273.             {
    274.                 centerHeights[i, 0] = leftHeights[i, leftHeights.GetLength(1) - 1];
    275.             }
    276.         }
    277.         centerTerrain.terrainData.SetHeights(0, 0, centerHeights);
    278.     }
    279. }
  4. gilley033


    Jul 10, 2012
    Hi Ninlilizi,

    I am sorry you are seeing this issue! It does appear that a bug slipped in with one of the most recent builds effecting the group slicing fields in the inspector. I will have this fixed ASAP, if you could send me your invoice number and an email address to send the updated package to, I will get the fix to you in short order (you can email, or simply start a private conversation with me with the information).

  5. gilley033


    Jul 10, 2012
    Hi Britain,

    Two things.

    First, the issue is not that the code is storing the terrain and then outputting all of them, but rather, there are simply too many terrains being generated for your scene to handle. As I indicated in my other posts, doing a slice of a 100km terrain and outputting 100m terrains will produce a grid of 1000 x 1000 (aka 1 million terrains). There is no way for Unity to handle that size. My tool gets around this issue by adding an option to produce prefabs and skip adding the terrains to the scene, though to be honest I doubt producing 1,000,000 terrains would not present other issues.

    Second, unless you are using a base terrain with a heightmap resolution of 32769 (which I'm fairly confident is impossible), there is no way that code will produce a 1000 x 1000 sliced grid of terrain. Can you explain why you say it works for you (my understanding is it is crashing every time you try)?

    To be clear, there is no code that can do what you want, at least if your aim is to create slices that match the portion of the original terrain exactly. You are going to have to settle for a larger slice size, which as I mentioned before, will depend on the resolution of your terrain.

    As an aside, you will also be able to produce terrains whose names match the convention required by World Streamer using my tool.
  6. infinitesunrise


    Mar 11, 2016
    Hi Kyle,

    Was working with your kit in my project last year but took a step back from it for a few seasons. Back at it again now and having a fun time setting up my new terrain with your tools (Seriously, the cool ideas and worlds this kit basically enables makes working with it fun, despite how long-winded and technical-sounding your component naming patterns may be :p )

    I've got a few questions about setting up ObjectGroups:

    1) Can you recommend any tools or scripts to make it easier to bulk-create my ObjectGroups? My current terrain is 256 slices, if almost every one of those is going to have at least one corresponding object group that's... A lot of setup. Is there any tool out there that is the equivalent of the terrain slicer, for objects? I could probably write one myself but it would be a pain and it would be much nicer to continue focusing on asset creation than tool creation.

    2) Is there any way to specify a custom ObjectGroup folder location? Seems like it's the only piece of the kit that still requires you to store them in Resources.

    And a related thought, not so much a question: It would be *really* fantastic if either the World or Object Group components allowed for editor-based loading and unloading of Object Group prefab previews in the scene, the same way that the World component is capable of loading / unloading in-place terrain previews. That would allow you to store the game's scenery outside of the scene, while still being able to pull it in to work on new pieces as necessary.
  7. gilley033


    Jul 10, 2012
    Thanks for the kind words; I take great pride in my abnormally long class names ;). On to your questions!

    I cannot recommend any tools, but it probably wouldn't be too hard to write one. I am planning on adding this functionality in the future. Basically, you would just need to examine every transform in the scene (or perhaps just children of a specific root object), and check what cell it's transform is in. Then either create a new root game object to serve as the object groups "cell" (ex: Decorations_1_1 represents the decorations located inside the bottom left most cell of the world grid) and parent children that fall within the cell to it, or assign the children to the existing cell. If you decide to do this yourself, you could use the prefab converter tool included with the kit to easily create prefabs out of the root cell objects (e.g. Decorations_1_1, Decorations_1_2, etc.), and then use a Scene Generation File to generate scenes using the prefabs.

    The issue with writing such a tool for the general public is most people utilize unique hierarchy structures within the scene, so it can be hard to know which transform identifies a specific objects position. If you have any ideas on how to approach this problem I'd be all ears!

    You are referring to the preview features ability to load objects from the object group, right? If so, then if your object groups are in the same folder as your main (probably terrain) prefabs, you should be able to uncheck the "Load From Resources Folder" and specify the folder manually. Or is this not what you mean (or not working for you?). This only works if you have a game object with the ObjectGroup script assigned to one of the Object Group slots on the World component, of course.

    When you load a preview for a cell, it should load the object groups in addition to the main prefab. Is this not working for you (after you have tried my suggestion for the previous question), or do you mean something else?

    One of the things at the top of my of improvements of the kit is a better editor workflow in terms of editing specific cells in your world. At the very least this would include better support for object groups, perhaps the ability to load only select object groups.

    Best Regards,
    Kyle Gillen
  8. gilley033


    Jul 10, 2012
    Hello again everyone. I wanted to take a moment to again ask for feedback regarding the package. What could be done better? Are there additions you'd like to see, changes to the workflow, etc.? You can post your feedback here or email me, whichever you prefer.
  9. AyeLuie


    Jul 18, 2016
    Hey man I've been thinking about buying this asset for a while now but haven't done so due to the fact that I still have some questions about it. The main one being, would it help improve the performance of my game? You see, I am currently working on a mobile hunting game with fairly large maps and, as of now, FPS is a bit low.
    Last edited: Sep 18, 2017
  10. gilley033


    Jul 10, 2012
    Generally speaking, no, it will not improve performance. This may change in the future with updates to the Unity Terrain system (by Unity), but for now this tool is mainly aimed at getting around memory issues associated with having multiple terrains or other game objects in the scene at once.

    If you can get a sample scene to me somehow I can test your particular project and give you a more definitive answer.

    Best Regards,
    Kyle Gillen
  11. mattis89


    Jan 10, 2017
    Hello! How is this build working in 5.6? I have a 8×8k terrain and i get a atkas default size error when i try to bake..maybe this tool will help me if it slices the terrain and gets smaller?
  12. gilley033


    Jul 10, 2012
    See email.
    mattis89 likes this.
  13. mattis89


    Jan 10, 2017
    Hey guys! Did you have ram problem before buying this asset? Did it reduce?

    I have a 8x8 square kilometer terrain generated with gaia... and eats alot of ram.. the editor is so slow..

    I have like total 25gb ram
    Now 2-3gb left... almost no other objects
  14. gilley033


    Jul 10, 2012
    I responded to this question via email and got mattis sorted out, but wanted to provide an answer to this question so others can see.

    Basically, as it stands now, there are rudimentary tools for editing your world that involve loading individual tile pieces. But only the base terrain or model piece is loaded in the editor, so it's not very useful.

    The next update to the kit will improve this by introducing a massive overhaul to the world editing tool set. Hopefully it will work as well as non Unity world editing software, like the Bethesday editor for The Elder Scrolls games.

    In addition, there are a great many more improvements coming. Here are some of the highlights:

    1. New LOD system, so you can set up lower quality terrain or meshes to be used at far distances from the player (looking into implementing a Terrain to mesh tool, but for now expect to have to use a third party tool for this).

    2. Cell Chunking, which will allow you to break your cells down into discrete loadable assets. This way, if you have a set of content (prefab, scene, asset bundle with multiple game objects) that is very resource intensive, you can split it up (assuming it can be split up) so that the per frame overhead of loading all the objects is reduced. Note that this will not work with terrain, though you could use it to load individual pieces of a larger mesh.

    3. New Grid Layer system, which will allow you to assign multiple World Grids to a single World. Each grid defines it's own set of cells with unique cell dimensions and loading behaviour, meaning you will have greater control over when specific objects in the scene should be loaded. For instance, perhaps you have large objects, such as your terrain, on one grid. It makes sense to load these objects even at a far distance, so the cell dimensions will be quite large.

      However, you also have small detail object such as houses, fences, and trees. You only want to load these objects when the player gets relatively close. The previous system of Object Groups could not handle this scenario, as all objects were connected to the same cell (small detail objects were loaded with terrain). Now, with grid layers, the sky is the limit!

      And of course, you will be able to define the dependencies between grid layers, so if you need one layer to only be loaded after another layer is loaded (so they don't fall through the world, for instance), you can.

    4. The previously mentioned new world editing tools!

    5. A new scene splitting tool, to allow you to easily slice up an existing scene for use with the Dynamic Loading Kit.

    6. New Loading Pattern asset type. This defines how the cells are loaded given the current player position. You can use a uniform pattern such as the current "Outer Ring Grid" or "Sectioned Grid" (or a uniform pattern which you define), which means each time the active grid shifts, the same pattern of cells will be loaded.

      Or, you can define the pattern for each individual cell manually. This will obviously take more time but gives you a tremendous level of control over the loading behaviour. For instance, perhaps you know that when the player is standing on cell 2_2, there is a mountain completely blocking (both physically and visually) cell 2_3, and so it does not make sense to load that cell. You can do that with the non uniform pattern.

      The pattern system is also what drives the LOD system, as it will allow you to define a set of non overlapping patterns for each LOD (i.e., if a cell is active in one LODs pattern, it cannot be active in any other LODs pattern).

    7. A very rudimentary culling system (needs testing to see if it's worth it).
    These new systems should make the whole process of getting your assets ready for dynamic loading/streaming a lot easier, and should also go a long way to improving the performance of the kit, as well as opening up the kit to be used in a greater variety of games.

    Let me know if you have any questions!
  15. gilley033


    Jul 10, 2012
    I am excited to announce that the package is on sale now at 25% off ($31.50 retail value - you save $13.50)!

    This is the first time the package has been on sale. Now is the perfect time to pick up the Terrain Slicing & Dynamic Loading Kit, as the biggest update to the kit is just on the horizon.

    You get:
    1. A terrain slicing tool second to none. Slice your entire terrain or target select regions to extract only the section of terrain you need.
    2. A Dynamic Loading/Streaming solution that is robust and easily integrates with your particular project.
    3. A robust collection of learning/help material, including a world class API even a novice programmer can navigate.
    4. AAA support.
    In addition, the largest update to date is just around the corner (see post above this one for details!).
  16. gilley033


    Jul 10, 2012
    Update 4.3.3 has been approved and is now live on the Asset Store. This update contains some small improvements and bug fixes. All javascript files have also been removed in compliance with the new Asset Store policy (you are free to delete the leftover files once you update to the latest version of the kit). The functionality of those files has been moved to the three .dll's of the kit. Note that you may have an additional "Asset Store Tools" folder with your download of the package. Please ignore this!

    Here is the full change log:

    1. Added a new Primary Cell Object Sub Controller called DistanceBasedPrimaryCellObjectSubController. This component works similar to the pooling sub controller, except the objects are removed once the player moves some user defined distance from the cell that the object belongs to.

    2. Unity 5.5+ version now utilizes the new SceneManager.UnloadSceneAsync method to unload scenes, which should improve performance. Note that this will only work if you are using a Scene Loader (as your cell object loader) and are not using a Cell Object Destroyer as that will be used if it is present).

    3. Added option for setting static flags (static lightmapper, occluder, etc.) of slices when using Slice Configuration Files. can choose to copy the static flags from the base terrain or set the static flags of the slices manually (so they are than the base terrain).

    4. Added icons for World Grid and Slice Configuration File assets, to better differentiate them from other assets in the Project Hierarchy.
    File Changes
    1. Removed all javascript files at the request of Unity Asset Store.
    1. Fixed a bug causing columns and layers to be loaded at incorrect positions when using world re-centering and a origin cell other than column = 1 or layer = 1.

    2. Restored Script Execution Ordering of World, Active Grid, and Component Manager scripts, which were mistakenly removed in previous update.

    3. Fixed Group Range Fields when slicing a group using the Slice Configuration File.

    4. Removed warning about not being in orthographic mode when slicing a group.

    5. Fixed a bug causing unwanted game objects to be included in scenes generated using Scene Generation Files.

    6. Updated Platform dependent compilation statements in SliceConfigurationFileEditor.cs file, which should eliminate some errors on Unity 4.6 and Unity 4.7 versions, as well as add support for new properties in later versions of Unity when slicing.

    7. Fixed a null reference exception that would occur when selecting a World Grid asset on Unity versions lower than 5.4.1f.

    8. Fixed unreachable code in AssetBundleLoader script.

    9. Fixed issues causing warnings in console window.
  17. taecg


    Jun 14, 2014
    Is support lightmapping?
  18. gilley033


    Jul 10, 2012
    I replied to your email but will provide the answer here for others.

    I have not tested lightmapping but there should be no problems so long as you are utilizing scenes. Any issues will be Unity issues that they must address on their end. You will however need to manually open each scene and bake the lightmap, which might be a pain. Down the road I hope to add a tool that will automate this process.
  19. infinitesunrise


    Mar 11, 2016
    Hey Kyle, would you be able to recommend any asset store alternatives to Unity's built-in terrain trees that work well with the Dynamic Loading Kit? My terrain is epic and I'm looking to draw tree billboards up to 10 km out so I think I'm going to need the help of something like Critias or AltTrees for optimization, but it's difficult to tell for sure from their documentation if there won't be any gotchas arising from compatibility and figured you might have some experience with that.
  20. gilley033


    Jul 10, 2012
    Unfortunately I have not used either one, or any other alternative tree system. You could check with author of each tool and ask if there are any issues using their systems with a streaming solution in which the terrain the trees are planted on are loaded dynamically mid game.

    Sorry I could not be of more help!
  21. Stormy102


    Jan 17, 2014
    How would this system work with a client-server architecture multiplayer game? Would the entire world be loaded or just chunks around players and AIs?
  22. gilley033


    Jul 10, 2012
    I have not worked with multiplayer extensively so this answer is based on theory and research into various techniques used in past games, but the basic idea is yes, the world is still loaded in chunks around the player. Most games run a separate server instance for each "chunk" of the world. As the player moves from chunk to chunk, they are moved concurrently from/to the appropriate server instance. On each server instance you'll also probably want to load all the chunks that neighbor the "main" one, or perhaps even the ones that neighbor those neighbors if your chunks are small (it just depends on how far players must be from one another or the AI before they stop being able to interact with each other), in order to keep players from running off the edges of the chunk.

    Things become more complicated when using origin shifting/re-centering, because suddenly there is no guarantee that anything will be where you expect it to be, as the world may be shifted in a variety of ways on the clients game. For example on the client's simulation he may be at position 100, 220, 5 but on the server instance he is at position 0, 120, 5. Even though the positions are different values they refer to the same position on your game map and are thus both valid, it's just that on the server the origin cell is one cell/chunk, but on the client it may be another, if that makes sense.

    The key to solving this issue is to treat positions sent across the network as relative positions. So when sending a position from the client to the server, the receiving party must always know which cell/chunk the position is relative to. This can either be implicitly understood or explicitly stated via extra network data.

    Implicit method: Before sending from client to server, convert the position to a position relative to the server instance the client is currently "in," i.e., relative to that server instances origin cell/chunk. This is ideal as it minimizes the network packet size, as you are only sending position data which you would have had to send anyway. When the client moves from server instance to server instance, the server instance will tell the client what its origin cell/chunk is. You can then call a method on the World class of the kit to convert any scene position to a position relative to this cell (this method will be available with the next update). When sending from server to client, the position is already relative to the servers origin cell/chunk, so no conversion is necessary before sending the position over the network. But when the client gets the position, they will need to convert the relative position to a position in their current scene (again, this will be available in the next update). The client side conversion methods (from a scene position to a relative position and vice versa) work by taking into account the clients current cell/chunk layout.

    Explicit method: Always send the current origin cell of the server/client when sending position data. The receiving party will use this to convert the position to a position that is valid with their origin cell. Not ideal as it increases network packet size and the server will have to do extra work when receiving packets.

    Again, this is theoretical and there are probably other issues that I am not addressing. The true answer will depend on your exact network architecture. Hopefully this answer gives you a general idea on how it could work though, and I will of course work with you on any needed improvements if you decide to purchase the kit and find it is lacking in order to create your game!

    Best Regards,
    Kyle Gillen
    Stormy102 likes this.
  23. MostHated


    Nov 29, 2015
    Following thread to get updates : D
  24. gilley033


    Jul 10, 2012
    Hello all,

    I am looking for feedback on the origin shifting functionality. Currently one of the options for origin shifting involves duplicating the entire world at the origin, moving the player to a relative position on this duplicated world (so they don't notice any change), and then removing the old world.

    This works well as it can be done in a performance friendly way and doesn't involve changing the position of a massive amount of objects (like the single frame shift option), however the caveat is it doubles the memory usage of the game (if only for a short time).

    I am wondering if anyone actually uses this feature though, since the doubling of the memory is likely a deal breaker for many. I am considering removing this option all together, so please let me know if you currently use it and would like to see it remain an option!
  25. MostHated


    Nov 29, 2015
    I would see that large of a memory spike as being a potential problem depending on how big of an area it is, to begin with that is being duplicated and how densely populated it is with "stuff" unless there was some way to blend it, as in you are technically not standing where you think you are and as the new area loads around you the old are goes away at the same time, if that makes sense. Think of moving the player in world space but what they see is still the old stuff minus what has already loaded so that it's loading and unloading at the same time.

    That might involve camera trickery though. Say there are two cameras at the same time, one is the actual player view of where he is, he is then moved to a new area and the only thing loaded is what is directly under him, but still looking at the place he was, the new camera is on the player, as each grid space disappears from where he was, a new gridspace appears where he is, you would not be able to tell the difference if both cameras are blended into one view because as one thing leaves in one view, another shows up in the second view at the same time. It would be the same memory usage as if things were loading and unloading as normal, minus there is an extra camera.

    I can't speak much in ways to try and do it though other than that, as I had to disable it all together since my game is client/server, can't exactly have the server trying to move players around like that, lol.
  26. gilley033


    Jul 10, 2012
    That's a really cool idea! I'm going to experiment with this and see how it works. Thanks!
  27. gilley033


    Jul 10, 2012
    The latest feature to be added to the "Coming Soon" section is . . . an organized hierarchy! This is desperately needed, as currently all objects are loaded in as root objects, cluttering the scene. With update 5.0, here is an example of how it might look (please feel free to suggest other ideas!):
    • World (root transform/parent - this is whatever game object that has the World component attached)
      • BaseCell_1_1 (an empty game object, the row/column numbering of which is defined by the cells on your main/base grid layer [likely your terrain])
        • Layer 1 (Since layer 1 is the main/base grid layer, it will only have one cell, with row/column equivalent to the row/column of the BaseCell parent)
          • Cell_1_1 (an empty game object which is parent to the chunks of the main cell - note that it's possible there are no cells loaded from layer 1. In that case this game object would not exist, and perhaps also the Layer 1 game object would not either. The "Cell" name is standard and is not related to the name of your actual scenes/prefabs - those will be present in the child chunks)
            • BaseObjects_1_1_Chunk1
            • BaseObjects_1_1_Chunk2
        • Layer 2
          • Cell_1_1
            • MiscStuff_1_1_Chunk1
            • MiscStuff_1_1_Chunk2
            • MiscStuff_1_1_chunk3
          • Cell_1_2 (layer 2 and on can have more than one cell)
            • MiscStuff_1_1_Chunk1
        • Layer 3
        • ...
    In this format, all cells from sub layers (layer 2, layer 3, etc.) can be thought of as "in" the cell from the main/base layer (layer 1). The reason I am using this structure is for world shifting purposes. There will be two options for world shifting: shift in a single frame (in which case the World transform position just needs to be changed), or shifting over multiple frames. The simplest way to shift over multiple frames will be to move one base layer cell per frame. The problem is, there will likely be a chain of dependencies, such that objects on layer 2, 3, etc. physically depend on the objects from layer 1. So if you move the objects on layer 1, you have to move the objects from the sub layers at the same time.

    Thus the structure above. As you can see, moving the "BaseCell" game object will move all the children, which includes the objects from every layer associated with that cell. Of course, you could always do some fancier movement, disabling physics, and in some instances this might even be necessary (if the performance of moving every object residing in a cell from the base layer - including the objects from the base layer- is too much). But for the simple method of moving one base cell and its containing objects per frame, this structure makes it dead simple.

    There are still some things I haven't decided on, for instance what happens when there are no cells loaded for a specific layer. Do I add an empty layer game object still? The only time this might be a problem is if you have a ton of layers, which will probably not be the case.

    Or what happens if you are not using chunking on a particular layer? Should I replace the empty "Cell_1_1" game object with the dynamically loaded root object? This will save on some memory if you have a ton of cells loaded at once that don't use chunking, but it breaks the uniformity of the hierarchy structure, which is something I'd rather avoid.

    Does anyone have any thoughts?
  28. gilley033


    Jul 10, 2012
    After considering the hierarchy organization scheme described above, I have decided that forcing this scheme on you is not the best strategy, primarily because utilizing empty game objects for organizational purposes has some obvious and less obvious drawbacks; the obvious being added overhead through the introduction of game objects into the scene, the less obvious being lower performance during shifting operations due to the empty game object transforms needing to be updated.

    However, I still believe most people will want to make use of some sort of organization scheme, and in truth the performance trade offs will probably only be noticeable to mobile users. In that vein, I have decided to implement this functionality through a new class of MonoBehaviour's. One or more default versions will be available by default, allowing you to utilize the organization scheme described in the previous post (or alternative versions with minor adjustments). But, you will also be able to implement your own class that derives from the base class, allowing you to come up with your own organization scheme.

    This will open up the full range of possibilities to you, from the current strategy of having everything be a root transform in the scene, to more involved but better organized schemes, which sacrifice performance in favor of organization. This strategy also fits in with the mix and match component based approach used in other facets of the kit, so I think it is the best approach.

  29. Zarkow


    Jul 27, 2015
    I am actually hoping it will improve performance in one important area, after being pointing in your direction by Unity QA -- I had a 4x4km terrain piece and when setting a FOV of for instance '1' for a camera, even when looking up in the sky, FPS would drop down to 10% normal amount.

    I will most likely post some feedback after testing it out later.
    Last edited: Jun 18, 2018
  30. MostHated


    Nov 29, 2015
    It sounds like an update needs to happen to the hierarchy that can allow for situations like this to not hinder the developers building workflow. It might be nice if the hierarchy could build horizontally as well as vertically, so you can have your normal hierarchy tree, but then have a second tree which can be collapsed and out of view yet still technically are root objects of the tree.

    Another option might be to have a second scene entirely in which the second hierarchy lives and then can just be added to the primary scene when needed.
  31. Zarkow


    Jul 27, 2015
    Confirmed that slicing a huge terrain (25 km^2) into 16 pieces does not improve fps. Not even if setting clipping range to 200 m. This is a Unity issue.

    Haven't looked into the loading-feature of this pack -- can it also detect and deactivate terrain-slices outside of 'visible range' and de-activate them?
  32. gilley033


    Jul 10, 2012
    Not at the moment, but this should be be added in the next update. In that same regard, the update is coming along, but progress has been slower than I've liked due to some family issues. Nothing catastrophic, and the good news is that progress should be ramping up nicely in the near term!
  33. gilley033


    Jul 10, 2012
    Sorry, I didn't notice this post at first. Note that the width/length of your terrain shouldn't matter as much as the resolution. Utilizing smaller slices of terrain will typically not improve performance unless you are using an LOD system (i.e., lower quality terrain or meshes farther out from the player). This is a feature that is coming with the next update. For the time being, however, this kit should not be relied upon to improve performance. Sorry!
  34. gilley033


    Jul 10, 2012
    I am not sure I fully understand what you mean, but I think I've solved the performance issues with utilizing more organized hierarchy schemes.

    Rather than just have one scheme, you will actually be able to specify two different schemes, one for the editor and one for standalone versions. This way, you can have a hierarchy scheme in the editor that organizes things to your liking in order to make viewing the scene makeup better, but also have a standalone scheme that maximizes performance.

    How does that sound? Or were you talking about a different problem entirely in your post? Perhaps you could elaborate? Thanks!! Input is greatly appreciated!
  35. gilley033


    Jul 10, 2012
    Just an update. The above hierarchy organization functionality has been implemented and is working great. I am very happy with the flexibility and performance of the system. By default there will be a standard Hierarchy Organizer which will give you some flexibility and will likely be suitable for most projects. Those options look like this: (note, the term "group" below means to create a parent game object and make everything a child of it):

    1) Group everything under a single root game object, which can either be the game object your World component is attached to, or a separate game object of your choosing.

    2) Group all objects according to which cell from the base grid layer they reside in. This can make shifting the world easier, as you can just shift the parent.

    3) Group all objects according to the grid layer they reside on.

    4) Group chunks (when chunking is used) from the same cell together (if a cell only has a single chunk, you can specify whether that should be grouped [to keep the grouping consistent], or if only cells with multiple chunks should be grouped).

    The order of these options is important to the hierarchy parent/child relationship. If an option is utilized, the parent used to group the objects according to that option will be children of parent/s used to organize the objects according to the next highest ranked option (option 1 > 2 > 3 > 4). Of course, since option 1 is the highest ranked, the object used for it will be a root object in the scene (it will have no parent).

    In addition to this, you will be able to override the "HierarchyOrganizer" MonoBehaviour component in order to organize your hierarchies in some other way not covered by the options above.

    That's it for now. Next up: a rethinking of how world shifting/origin resetting is performed (spoiler alert: let's give you more control!).
    MostHated likes this.
  36. MostHated


    Nov 29, 2015
    If it could be done with online aspects taken into consideration such as, you can't just up and move the world on the server side, so its world coordinates will remain the same, but the client side may be moved, so something such as a "local position" and an "actual position" so the client is in the correct place on the server side, that would be swell. : D
  37. gilley033


    Jul 10, 2012
    Hey, thanks for the feedback! This is actually something I have thought about and came to the same conclusion, so I am glad to see there is someone else out there thinking along the same lines.

    Like you say, the server shouldn't be doing any type of shifting, shifting is local only. Translating to and from a local position from/to an "actual" position is problematic however, since it's likely you will be using a non float value (maybe it's just a double, or maybe it's some custom struct that allows for really big numbers) for your "actual position." After all, generally origin shifting is only performed in cases where the world is so large that using floating point values to record position would be troublesome. Now factor in that most users will be using something different, hopefully you can see that trying to account for all the different possibilities would be impossible.

    Of course, I can provide some kind of interface or base class you can derive from, so that I can call all the needed methods/operations in order to do do the conversion. For one, the interface/class would have to have a method for translating a float value directly to your custom type. Then it would need an add method, and likely a multiply method. I considered doing this but scrapped it in favor of a different solution.

    That solution involves the addition of four new methods in the World class; TranslateScenePositionToPositionRelativeToWorldCell, TranslateScenePositionToPositionRelativeToWorldGridCell, TranslateScenePositionToPositionRelativeToEndlessGridCell, and TranslatePositionRelativeToEndlessGridCellToScenePosition. The first three methods allow you to convert a position in the local scene to a position relative to either a WorldCell (an object which encompasses an active cell in the scene - using this you can get a lot of information including the objects loaded for the cell, but it will return null if a particular cell is "empty"), world grid cell (the raw row/column/layer on the world grid), or endless grid cell (the raw row/column/layer on a projected endless grid - this is needed for endless worlds).

    These methods all return the position, plus the have an out paramater for the given WorldCell, world grid cell, or endless grid cell that the position is relative to.

    The last method does the reverse, though it only works using an endless grid cell as an argument. The reason is that for endless worlds, the world grid cell is not enough, as the same world grid cells can be loaded at the same time (in this case, they would have different endless grid cell indexes). Not to worry if using a non endless world though, in that case the endless grid cell and world grid cell are always the same (since duplicate world grid cells cannot be loaded at the same time).

    With these methods, the client can tell the server, "hey, this object is at position x,y,z relative to this cell." The server can then take that information and translate it to an "actual" position, because it knows where each cell is located in its "actual" coordinate system. Conversely, the server can take an actual position, translate it to a float value position relative to whatever cell it is in, and then send those two pieces of information to the client (the float value position and the cell the position is relative to). The client can then take that information and translate it to a scene position.

    Hopefully that makes sense. If so, what do you think?
  38. gilley033


    Jul 10, 2012
    Does anyone have an opinion on the current persistent state saving mechanism used by the dynamic loading kit? Currently, the Active Grid, World, and Component Manager have information that can change at runtime, and thus this information needs to be saved between sessions.

    This is done in one of two ways. If a key based Persistent Data Controller is set on the Component Manager, each world and active grid is saved separately with the ID of each used as the key. The persistent data for each is a single string. The same goes for the instance of the Component Manager in the scene.

    If you elect to use a custom save/load solution, then you can get the save data from the Component Manager in the form of a single string, which has the data of the Component Manager, all Worlds, and all Active Grids. The data is just appended to a string builder object, that way strings are not just constantly being appended to each other. Then you just need to save that string and when loading the next session, provide it back to the Component Manager.

    I am not sure if this is the best way to do things though, and am wondering if anyone has suggestions for a different method. For instance, rather than use a string, I was thinking about creating an interface (something like IDLKPersistentStateManager) that you could implement. It would have some general Get/Set methods for each type of data the DLK needs to save/load (currently ints, bools, floats, and strings), plus two methods that are called once the get/set operations are complete. Like so:

    Code (CSharp):
    1. public interface IDLKPersistentStateManager
    2.     {
    3.         void SetInt(int value);
    4.         void SetBool(bool value);
    5.         void SetFloat(float value);
    6.         void SetString(string value);
    7.         void OnAllDataSet();
    10.         int RetrieveNextInt();
    11.         bool RetrieveNextBool();
    12.         float RetrieveNextFloat();
    13.         string RetrieveNextString();
    14.         void OnAllDataRetrieved();
    15.     }

    The basic idea being, whenever you want to save/load the data that needs to be saved/loaded, you'd pass in a class that implements this interface, and then the Component Manager would call each appropriate method in a certain order (determined by a version number which is saved as the first integer).

    For example, when you want to save the data, you'd prep your class, then call the Component Manager's SaveData method, passing in the class as the argument.

    The Component Manager would then use SetInt to set the version number, and then start setting data using the four Set Methods. Once all the data is set, OnAllDataSet is called, at which time you can actually save the data using whatever method you prefer (binary serialization, for instance). The loading behaviour works in reverse; you load in the data from your save source (custom file format, for instance), then call the Component Manager's load method and pass in the same class). The Component Manager gets the version number using RetrieveNextInt, and then uses that version number to retrieves the rest of the data in the correct order. The Retrieve methods are called in the exact same order that the Set methods were when creating the save data.

    For example:
    Code (CSharp):
    1. public class PossibleStateManagerImplementation : IDLKPersistentStateManager
    2.     {
    3.         List<int> ints = new List<int>();
    4.         List<bool> bools = new List<bool>();
    5.         List<float> floats = new List<float>();
    6.         List<string> strings = new List<string>();
    7.         int intRetrievalCounter, boolRetrievalCounter, floatRetrievalCounter, stringRetrievalCounter;
    9.         //You'd call this before calling the Load method on the Component Manager. This is the actual method
    10.         //for loading the data from your save source (json, binary serialization, Player Prefs, whatever)
    11.         public void LoadDataFromSaveSource()
    12.         {
    13.             //load the saved ints, bools, floats, and string from whatever source you are using.
    14.         }
    17.         //These methods are used by the Component Manager to set the data that needs to be saved.
    18.         public void SetInt(int value)
    19.         {
    20.             ints.Add(value);
    21.         }
    23.         public void SetBool(bool value)
    24.         {
    25.             bools.Add(value);
    26.         }
    28.         public void SetFloat(float value)
    29.         {
    30.             floats.Add(value);
    31.         }
    33.         public void SetString(string value)
    34.         {
    35.             strings.Add(value);
    36.         }
    38.         public void OnAllDataSet()
    39.         {
    40.             //Save the data in whatever way you are doing. This might involve coverting the lists to arrays
    41.             //and serializing them via binary serialization, or some other method.
    42.         }
    45.         //These methods are used by the Component Manager to retrieve the save data
    46.         public int RetrieveNextInt()
    47.         {
    48.             //the ++ at the end increments the counter for the next call
    49.             return ints[intRetrievalCounter++];
    50.         }
    52.         public bool RetrieveNextBool()
    53.         {
    54.             return bools[boolRetrievalCounter++];
    55.         }
    57.         public float RetrieveNextFloat()
    58.         {
    59.             return floats[floatRetrievalCounter++];
    60.         }
    62.         public string RetrieveNextString()
    63.         {
    64.             return strings[stringRetrievalCounter++];
    65.         }
    67.         public void OnAllDataRetrieved()
    68.         {
    69.             //reset counters
    70.             intRetrievalCounter = boolRetrievalCounter = floatRetrievalCounter = stringRetrievalCounter = 0;
    72.             //Clear List
    73.             ints.Clear();
    74.             bools.Clear();
    75.             floats.Clear();
    76.             strings.Clear();
    77.         }
    78.     }

    The important point here is that this is just one implementation. The Set/Retrieve methods are so generic that you could literally store the data any way you want, so long as the data is able to be retrieved in the same order that it was set. For instance, when one of the Set methods is called, you could write the data directly to a memory stream using a binary writer. The Retrieve methods would just read from that same stream using a binary reader. Because the data is set/retrieved in the same order, you can use BinaryReader.Read#DataType# with the certainty that the data at that memory stream position will be of the correct type.

    I believe this system offers maximum flexibility, but I would be interested in hearing any critiques or suggestions for other ideas.
  39. Ttravi


    Jan 22, 2018
    Good afternoon. The Asset Bundle Loader works flawlessly with the Simulation Mode enabled. However when disabled or when I build the project, it loads only the first chunk. There is no error and moving my Player object through the scene does not make the other chunks load.
    What could be causing this?
    My asset bundles are at StreamingAssets folder.
  40. Ttravi


    Jan 22, 2018
    Nevermind, I found it:


    Code (CSharp):
    1. SceneManager.LoadSceneAsync(m_LevelName, m_IsAdditive ? LoadSceneMode.Additive : LoadSceneMode.Single);
    Code (CSharp):
    1. m_Request = SceneManager.LoadSceneAsync(m_LevelName, m_IsAdditive ? LoadSceneMode.Additive : LoadSceneMode.Single);
  41. gilley033


    Jul 10, 2012
    Thank you for bringing this to my attention. The file you mention is a Unity produced file included with the Asset Bundle Manager, which unfortunately is no longer available on the Asset Store. It's possible I included a version of this package that was not up to date, as currently I have a version that already includes the change you made. I think (but am not sure) that they are making changes to Asset Bundles, which is why they removed the Asset Bundle Manager. I do not think these changes are live yet (but will need to check), but if they are by the time the next update rolls around (or if they are already), I will update the Asset Bundle loading scripts to work with the changes.

    In the mean time, anyone getting the same error can make the same change that Travi made, but if you run into any other issues let me know! I believe the changes need to be made around lines 89-93.
    Last edited: Sep 1, 2018
    Ttravi likes this.
  42. Ttravi


    Jan 22, 2018
    I'm sorry, I forgot to include the line number, but if I remember correctly it is 93.
    Your Asset is amazing! Keep doing a great job!
  43. gilley033


    Jul 10, 2012
    Hello everyone! I wanted to let you all know I am still hard at work on the next update. I apologize for the length of time it has taken to get this update done and the several missed deadlines. I hope you will all see why it has taken so long once it's released (and forgive me!). It really is a complete overhaul of a lot of different systems, and I have had several personal matters come up in the last year.

    With that said, I do have something tangible to show off today. These last couple of days I have been working on creating a new Pattern Editor, which allows you to better visualize and edit the loading patterns that you will use with the Dynamic Loading Kit. Here is a preview!

    In this preview you can see how editing a ring based pattern will work (The blue squares/cubes are the inner area [cells that the player can run around on without triggering new loading/unloading], while the green squares/cubes represent the outer area [cells which are loaded around the active portion of the pattern]), though it should be noted that non ring based patterns can also be used (i.e., the patter can be whatever you want). This is truly where the pattern editor will shine, as configuring such patterns would be virtually impossible using just the inspector. I will provide another preview once the editor workflow for these types of patterns has been implemented.

    The Loading Pattern Editor is an attempt at making the kit more user friendly. Please let me know if you think I'm on the right track! It is obviously a work in progress so feedback is welcome.
    YucelBrendel likes this.
  44. gilley033


    Jul 10, 2012

    I have been hard at work on the Pattern Editor. Here you can see some progress made on the scene view + major improvements to the GUI.

    Note that this is just an editor window, and I hope you will agree that it is a major improvement over how editor windows normally look. I probably should have taken a screen shot before implementing these updates so you could see the old ugly version! This has been a major effort, as Editor GUI styling is not a very well understood area. Through experimentation, however, I have learned a lot and will be applying this appearance to the rest of my editors (including inspectors), although this is a work in progress so if you have any suggestions, please let me know!
    YucelBrendel likes this.
  45. YucelBrendel


    Aug 31, 2013
    Hi gilley :D
    looks very good im looking forward for the update ^^
    great work wish you all the best and good luck
  46. LeoJr


    Feb 1, 2013
    Hey Gilley, just bought your tool and nothing is happening when I'm trying to add the terrain to the slice configuration file. Initially the option doesn't even appear to create one unless I update the API... What should I do?
    Trying to add the terrain gameobject says it must be a prefab now, and it ignores prefabs when I do try that.

    I am Using Unity 2018.3. Is it just not compatible?
  47. gilley033


    Jul 10, 2012
    The terrain must be a prefab stored in your project. Even if you have made your terrain into a prefab, it will not work if you try and drag the terrain game object from the scene onto the file. You must drag the terrain prefab from your project hierarchy.

    With that said, I just tried testing it out on 2018.3 and there is a NullReferenceException when I drag a terrain onto the Terrain To Slice field. It seems that they made the internal detail resolution per patch field public with 2018.3 which is an issue because previously I was getting it via reflection using the non public binding flag. Since it's no longer private, it the reflection fails.

    I will provide an update soon. I have already fixed the issue (and I will make a couple more changes to reflect the recent Terrain updates), however I need to make sure there aren't any issues with pushing these updates to the Asset Store code.
    Last edited: Jan 28, 2019
  48. LeoJr


    Feb 1, 2013
    Thank you for looking into it! I did also try storing it as a prefeb in the project and got the same result as what you described. Please let me know as soon as you figure it out and have a fix, as this is kind of a time crunch project and your tools would have been perfect to solve the issue we ran into with the terrain.

  49. gilley033


    Jul 10, 2012
    Please email me your invoice number. Once I have the update ready I can send send it to you via email so you don't have to wait for the Asset Store update process. My email is

    Edit: Just a heads up, I will be out of the office tomorrow so won't be able to address this issue until Wednesday. I apologize!!
    Last edited: Jan 29, 2019
  50. LeoJr


    Feb 1, 2013
    I understand! Email sent. Thanks for doing your best! :D