RAM usage and big worlds...

Hello everyone,

With my team we are working on MMORPG game. We are trying to prepare a good solution for RAM optimalization on our big scene.
I’ve heard that Unity comes with LoadLevelAdditiveAsync, but there will be a problem to divide current map to smaller sectors.

We have a script, that was written for Unity 4.0, but now it doesn’t unload meshes from the scene. I don’t know why.

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Threading;

public class RAMController : MonoBehaviour
{
    private const float SECTOR_SIZE_X = 50;
    private const float SECTOR_SIZE_Y = 50;
    private const int LAYERS_NUMER = 18;
    public int sectorsToLoad = 0;
    public Transform player;
    private float sector_size_x, sector_size_y;
    private Vector2 oldPlayerPosition;
    private Dictionary<Vector2, int> pendingSectorsToLoad;

    // first element marks sector location in 3d space, second marks list of objects that are stored there
    private Dictionary<Vector2, List<GameObject>>[] sectorsModels;

    private Vector2 currentSector = new Vector2();

    void Awake()
    {
        sectorsModels = new Dictionary<Vector2, List<GameObject>>[LAYERS_NUMER];

        for (int i = 8; i < LAYERS_NUMER; i++)
        {
            sectorsModels[i] = new Dictionary<Vector2, List<GameObject>>();
        }

        oldPlayerPosition = new Vector2();
        //Terrain_x = GameObject.Find("Terrain").GetComponent<Terrain>().terrainData.size.x;
        //Terrain_z = GameObject.Find("Terrain").GetComponent<Terrain>().terrainData.size.z;
    }

    // Use this for initialization
    void Start()
    {
        sector_size_x = SECTOR_SIZE_X;
        sector_size_y = SECTOR_SIZE_Y;
        oldPlayerPosition.x = player.transform.position.x;
        oldPlayerPosition.y = player.transform.position.z;
        Vector2 positioner;

        // Sector - layer
        pendingSectorsToLoad = new Dictionary<Vector2, int>();

        GameObject[] gobj = GameObject.FindSceneObjectsOfType(typeof(GameObject)) as GameObject[];

        StartCoroutine(TurnOff(null, gobj));

        int tmpLayer;

        // Assigining objects to sectors basing on their coordinates
        foreach (GameObject obj in GameObject.FindObjectsOfType(typeof(GameObject)))
        {
            if (obj.tag == "Terrain")
                continue;
            positioner = new Vector2();
            positioner.x = obj.transform.position.x - obj.transform.position.x % sector_size_x;
            positioner.y = obj.transform.position.z - obj.transform.position.z % sector_size_y;

            if (obj.layer > 27)
                continue;

            // Water distance layers go into same bucket as common layers
            tmpLayer = obj.layer < 18 ? obj.layer : obj.layer - 10;

            // Default layer
            if (obj.layer == 0)
                tmpLayer = 17;

            // Another object in sector
            if (sectorsModels[tmpLayer].ContainsKey(positioner))
            {
                sectorsModels[tmpLayer][positioner].Add(obj);
            }
            // First object in sector
            else
            {
                List<GameObject> go = new List<GameObject>();
                go.Add(obj);
                sectorsModels[tmpLayer].Add(positioner, go);
            }
        }

        float sectorIndexX = player.transform.position.x - player.transform.position.x % sector_size_x;
        float sectorIndexY = player.transform.position.z - player.transform.position.z % sector_size_y;

        ChangeSectors(sectorIndexX, sectorIndexY);

        InvokeRepeating("HandlePlayerMovementWrapper", 1f, 5f);
    }

    private void HandlePlayerMovementWrapper()
    {
        HandlePlayerMovement(player.transform.position.x, player.transform.position.z);
    }

    /// <summary>
    /// Verifies is player has crossed sector borders
    /// </summary>
    /// <param name="x">player x position</param>
    /// <param name="y">player z position (y on 2D space)</param>
    private void HandlePlayerMovement(float x, float y)
    {
        // Player is still
        if (x == oldPlayerPosition.x  y == oldPlayerPosition.y)
            return;
        else
        {
            // Sectors x,y indexes
            float sectorIndexX = x - x % sector_size_x;
            float sectorOldIndexX = oldPlayerPosition.x - oldPlayerPosition.x % sector_size_x;
            float sectorIndexY = y - y % sector_size_y;
            float sectorOldIndexY = oldPlayerPosition.y - oldPlayerPosition.y % sector_size_y;

            currentSector.x = sectorIndexX;
            currentSector.y = sectorIndexY;

            // Player changed sectors
            if ((sectorIndexX != sectorOldIndexX)
            || (sectorIndexY != sectorOldIndexY))
            {
                ChangeSectors(sectorIndexX, sectorIndexY);
            }
            oldPlayerPosition.x = x;
            oldPlayerPosition.y = y;
        }
    }

    /// <summary>
    /// Loads sectors, that will be needed and unloads old because player changed sectors
    /// </summary>
    /// <param name="sectorOldIndexX">X coord of sector where player was</param>
    /// <param name="sectorOldIndexY">Y coord of sector where player was</param>
    /// <param name="sectorIndexX">X coord of sector where player is</param>
    /// <param name="sectorIndexY">Y coord of sector where player is</param>
    private void ChangeSectors(float sectorIndexX, float sectorIndexY)
    {
  		Debug.Log("Zmiana sektora " + sectorIndexX.ToString() + " " + sectorIndexY.ToString());
		Vector2 localVector;

        for (int secX = -sectorsToLoad; secX <= sectorsToLoad; secX++)
        {
            for (int secY = -sectorsToLoad; secY <= sectorsToLoad; secY++)
            {
                localVector = new Vector2();
                localVector.x = sectorIndexX + sector_size_x * secX;
                localVector.y = sectorIndexY + sector_size_y * secY;

                // Negative sectors will be loaded and made positive

                if (secX <= 1  secX >= -1  secY <= 1  secY >= -1)
                {
                    UpdateSector(8, localVector);
                }
                else if (secX <= 2  secX >= -2  secY <= 2  secY >= -2)
                {
                    UpdateSector(9, localVector);
                }
                else if (secX <= 3  secX >= -3  secY <= 3  secY >= -3)
                {
                    UpdateSector(10, localVector);
                }
                else if (secX <= 4  secX >= -4  secY <= 4  secY >= -4)
                {
                    UpdateSector(11, localVector);
                }
                else if (secX <= 5  secX >= -5  secY <= 5  secY >= -5)
                {
                    UpdateSector(12, localVector);
                }
                else if (secX <= 7  secX >= -7  secY <= 7  secY >= -7)
                {
                    UpdateSector(13, localVector);
                }
                else if (secX <= 10  secX >= -10  secY <= 10  secY >= -10)
                {
                    UpdateSector(14, localVector);
                }
                else if (secX <= 16  secX >= -16  secY <= 16  secY >= -16)
                {
                    UpdateSector(15, localVector);
                }
                else if (secX <= 20  secX >= -20  secY <= 20  secY >= -20)
                {
                    UpdateSector(16, localVector);
                }
                else if (secX <= 26  secX >= -26  secY <= 26  secY >= -26)
                {
                    UpdateSector(17, localVector);
                }
                else
                {
                    if (pendingSectorsToLoad.ContainsKey(localVector))
                        pendingSectorsToLoad[localVector] = 0;
                }
            }
        }
    }

    void UpdateSector(int layerNumber, Vector2 localVector)
    {
        if (pendingSectorsToLoad.ContainsKey(localVector))
        {
            if (pendingSectorsToLoad[localVector] > layerNumber || pendingSectorsToLoad[localVector] == 0)
            {
                pendingSectorsToLoad[localVector] = layerNumber;

                if (sectorsModels[layerNumber].ContainsKey(localVector))
                {
                    StartCoroutine(TurnOn(sectorsModels[layerNumber][localVector], null));
                }
            }
            else
            {
				try
				{
                	StartCoroutine(TurnOff(sectorsModels[layerNumber][localVector], null));
				}catch ( System.Exception ex ) 
				{
					Debug.Log(ex.Message);
				}
            }
        }
        // Initial condition
        else
        {
            pendingSectorsToLoad.Add(localVector, layerNumber);
            for (int i = layerNumber; i < LAYERS_NUMER; i++)
            {
                if (sectorsModels[i].ContainsKey(localVector))
                {
                    StartCoroutine(TurnOn(sectorsModels[i][localVector], null));
                }
            }
        }
    }

    void OnGUI()
    {
        GUILayout.Label("Sector:  " + currentSector);
    }

The problem is, that UpdateSector doesn’t call TurnOff coroutine, but it should call it when user moves to another sector.
Is there any better solution ? Does someone know why this script doesn’t call TurnOff coroutine ?

Regards,
Chris

Anyone know what is going on? It crash after update to unity 4…

How can we check if you don’t post the coroutine itself ?