示例#1
0
        private void LoadMeshFromCgfCallback(NodeData node, Matrix m, CgfLoader cgf, List <MeshData> meshesPack)
        {
            if (node.Mesh.vertices.Length <= 0 || node.Mesh.indices.Length <= 0)
            {
                //VERBOSE Console.WriteLine("        Skipping (empty): " + node.Mesh.vertices.Length + "/" + node.Mesh.indices.Length);
            }

            /*else if ((node.Mesh.vertices.Length & 0xffff0000) != 0
            || ((node.Mesh.indices.Length * 3) & 0xffff0000) != 0)
            || {
            ||  Console.WriteLine("***     ERROR: Count of elements is bigger than MAX_SHORT");
            ||  Console.WriteLine("        Skipping: " + node.Mesh.vertices.Length + "/"
            + node.Mesh.indices.Length * 3 + " [" + node.Mesh.indices.Length + " * 3]");
            +  }*/
            else if (!cgf.IsNodeCollidable(node))
            {
                //VERBOSE Console.WriteLine("        Skipping (not collidable): " + node.Mesh.vertices.Length + "/" + node.Mesh.indices.Length);
            }
            else
            {
                // transform the node into object coordinates. indices stay the same.
                var xformMesh = new MeshData();
                xformMesh.vertices = new Vector3[node.Mesh.vertices.Length];
                Vector3.Transform(node.Mesh.vertices, ref m, xformMesh.vertices);
                xformMesh.indices = node.Mesh.indices;

                meshesPack.Add(xformMesh);
            }
        }
示例#2
0
        private void DrawDoorCgaInWorld(CgfLoader cga, int startTicks, ref Matrix xform, Vector3 position,
                                        List <VertexPositionColor> vertices,
                                        List <VertexPositionColor> collisionVertices,
                                        List <VertexPositionColor> lineVertices)
        {
            // Collect collidable meshes
            int collisionStart = collisionVertices.Count;

            var vertStartCount = vertices.Count;

            DOOR_HACK = true;//draw numbers on nodes
            cga.CloneAtTime(startTicks).TraverseNodes((node, transform)
                                                      => NodeHandler(cga, node, position, transform, vertices, collisionVertices, lineVertices, CgfDrawStyle.Door2),
                                                      ref xform);
            DOOR_HACK = false;

            var bboxTemp = new List <Vector3>();

            for (int i = collisionStart; i < collisionVertices.Count; i++)
            {
                bboxTemp.Add(collisionVertices[i].Position);
            }
            for (int i = vertStartCount; i < vertices.Count; i++)
            {
                bboxTemp.Add(vertices[i].Position);
            }
            Util.DrawBoundingBox(Util.GetBoundingBox(bboxTemp), lineVertices, new Color(25, 66, 250));
        }
示例#3
0
        private void AddToMeshesGeo(string cgfPath, CgfLoader cgf, BinaryWriter meshesGeoDataStream,
                                    byte collisionIntention)
        {
            Matrix identity = Matrix.Identity;

            // process each unique filename only once.
            if (m_loadedCgfs.Contains(cgfPath))
            {
                throw new InvalidOperationException("input should have been deduped already");
            }
            m_loadedCgfs.Add(cgfPath);

            try
            {
                // collect not empty, collidable meshes.
                var meshesPack = new List <MeshData>();
                cgf.TraverseNodes((node, m) => LoadMeshFromCgfCallback(node, m, cgf, meshesPack), ref identity);

                if (meshesPack.Count > 0)
                {
                    WriteToMeshsGeo(cgfPath, meshesPack, meshesGeoDataStream, collisionIntention);
                }
                else
                {
                    m_emptyCgfs.Add(cgfPath);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("***     ERROR: Cannot process mesh: " + e);
            }
        }
示例#4
0
        private static void AddCgfToWorld(CgfLoader cgf, ref Matrix xform,
                                          Vector3 position, GeoSpace geoSpace)
        {
            s_tempVertices.Clear();

            // traverse nodes
            cgf.TraverseNodes((node, transform) =>
                              NodeHandler(cgf, node, position, transform), ref xform);

            // Add collected vertices as a new mesh.
            geoSpace.AddCollidableMeshToTree(s_tempVertices);
        }
示例#5
0
        private void DrawCgfInWorld(CgfLoader cgf, ref Matrix xform, Vector3 position, CgfDrawStyle style,
                                    List <VertexPositionColor> vertices,
                                    List <VertexPositionColor> collisionVertices,
                                    List <VertexPositionColor> lineVertices)
        {
            // Collect collidable meshes
            int collisionStart = collisionVertices.Count;

            // traverse nodes
            cgf.TraverseNodes((node, transform)
                              => NodeHandler(cgf, node, position, transform, vertices, collisionVertices, lineVertices, style),
                              ref xform);

            // Add collected vertices as a new mesh.
            m_geoSpace.AddCollidableMeshToTree(collisionVertices, collisionStart, collisionVertices.Count - collisionStart);
        }
示例#6
0
文件: Form1.cs 项目: xvanick1/monono2
        private void ShowCgfViewer(CgfLoader cgf)
        {
            HideLevelViewer();
            HideImageViewer();
            HideTextViewer();

            m_vc          = new AionLevelViewerControl(null, null, cgf);
            m_vc.Location = new Point(m_treeView.Width, m_menuStrip.Bottom);
            var clientHeight = ClientSize.Height - m_menuStrip.Height;

            m_vc.Size           = new Size(ClientSize.Width - m_treeView.Width, clientHeight);
            m_vc.OnUpdateTitle += OnLevelViewerControlTitleUpdated;
            Controls.Add(m_vc);
            m_vc.Focus();
            Invalidate();
        }
示例#7
0
        private void NodeHandler(CgfLoader cgf, NodeData node, Vector3 worldPosition, Matrix transform,
                                 List <VertexPositionColor> vertices,
                                 List <VertexPositionColor> collisionVertices,
                                 List <VertexPositionColor> lineVertices,
                                 CgfDrawStyle style)
        {
            var hackackack = true;

            //Debug.WriteLine($"NODE {transform.Translation} === {node.chunkId}");
            bool isNodeCollidable = cgf.IsNodeCollidable(node);

            foreach (var vi in node.Mesh.indices)
            {
                var v0 = Vector3.Transform(node.Mesh.vertices[vi.v0], transform);
                var v1 = Vector3.Transform(node.Mesh.vertices[vi.v1], transform);
                var v2 = Vector3.Transform(node.Mesh.vertices[vi.v2], transform);

                if (hackackack && DOOR_HACK)
                {
                    m_renderData.labels.Add(new Label3D {
                        position = v0, text = node.objectId.ToString()
                    });
                    hackackack = false;
                }

                Color color = NodeColorizer(style, isNodeCollidable, vi.v0);
                var   dest  = isNodeCollidable ? collisionVertices : vertices;

                dest.Add(new VertexPositionColor(v1, color));
                dest.Add(new VertexPositionColor(v0, color));
                dest.Add(new VertexPositionColor(v2, color));
            }

            var zero = Vector3.Transform(Vector3.Zero, transform);

            lineVertices.Add(new VertexPositionColor(zero, Color.Blue));
            lineVertices.Add(new VertexPositionColor(Vector3.Transform(Vector3.UnitX, transform), Color.Blue));
            lineVertices.Add(new VertexPositionColor(zero, Color.Red));
            lineVertices.Add(new VertexPositionColor(Vector3.Transform(Vector3.UnitY, transform), Color.Red));
            lineVertices.Add(new VertexPositionColor(zero, Color.Yellow));
            lineVertices.Add(new VertexPositionColor(Vector3.Transform(Vector3.UnitZ, transform), Color.Yellow));

            lineVertices.Add(new VertexPositionColor(worldPosition, Color.Cyan));
            lineVertices.Add(new VertexPositionColor(zero, Color.Cyan));
        }
示例#8
0
        private static void NodeHandler(CgfLoader cgf, NodeData node, Vector3 worldPosition,
                                        Matrix transform)
        {
            if (!cgf.IsNodeCollidable(node))
            {
                return;
            }

            foreach (var vi in node.Mesh.indices)
            {
                var v0 = Vector3.Transform(node.Mesh.vertices[vi.v0], transform);
                var v1 = Vector3.Transform(node.Mesh.vertices[vi.v1], transform);
                var v2 = Vector3.Transform(node.Mesh.vertices[vi.v2], transform);

                s_tempVertices.Add(v1);
                s_tempVertices.Add(v0);
                s_tempVertices.Add(v2);
            }
        }
示例#9
0
        public void LoadCgfDoorHack(CgfLoader cgf, int ticks)
        {
            var vertices          = new List <VertexPositionColor>();
            var collisionVertices = new List <VertexPositionColor>();
            var lineVertices      = new List <VertexPositionColor>();

            var xform = Matrix.Identity;

            DrawDoorCgaInWorld(cgf, ticks, ref xform, Vector3.Zero, vertices, collisionVertices, lineVertices);

            m_renderData.vertexBuffer = VertexBufferUtil.CreateLargeVertexBuffer(GraphicsDevice, vertices);

            m_renderData.collisionVertexBuffer = VertexBufferUtil.CreateLargeVertexBuffer(GraphicsDevice, collisionVertices);

            if (lineVertices.Count > 0)
            {
                m_renderData.lineVertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), lineVertices.Count, BufferUsage.WriteOnly);
                m_renderData.lineVertexBuffer.SetData <VertexPositionColor>(lineVertices.ToArray());
            }
        }
示例#10
0
        private void LoadDoors(DirManager meshesDir, DirManager levelDir, int startTicks, List <VertexPositionColor> doorVertices,
                               List <VertexPositionColor> doorCollisionVertices, List <VertexPositionColor> lineVertices)
        {
            var doorInfos = DoorLoader.LoadDoorInfosForLevel(levelDir);

            foreach (var door in doorInfos)
            {
                using (var s = meshesDir.OpenFile(door.object_AnimatedModel))
                {
                    var cgf   = new CgfLoader(s);
                    var xform = door.GetMatrix();

                    DrawDoorCgaInWorld(cgf, startTicks, ref xform, door.Pos, doorVertices, doorCollisionVertices, lineVertices);

                    m_renderData.labels.Add(new Label3D {
                        position = door.Pos, text = door.object_AnimatedModel
                    });
                }
            }
        }
示例#11
0
        public static AionLevelViewerImpl CreateCgfViewer(GraphicsDevice GraphicsDevice,
                                                          IServiceProvider serviceProvider, CgfLoader cgf)
        {
            var result = new AionLevelViewerImpl(GraphicsDevice, serviceProvider);

            result.camera.StepSpeed   = 1;
            result.camera.UpDownSpeed = 1;
            result.m_contentLoader.LoadCgf(cgf);
            //result.doorHackCgf = cgf;
            return(result);
        }
示例#12
0
        public void Process()
        {
            DateTime timer = DateTime.Now;

            if (!Directory.Exists(aionClientPath))
            {
                throw new FileNotFoundException($"Aion client installation path [{aionClientPath}] doesn't exist or not a folder path");
            }

            var meshesDir = new DirManager(aionClientPath,
                                           new[] { @"Levels\Common", @"objects\npc\event_object", @"objects\npc\level_object" });

            // Read world_maps.xml and WorldId.xml and find Levels to process
            Console.WriteLine("  Generating available levels list...");
            WorldIdXmlLoader worldIdXmlLoader = LoadWorldIdXml();

            Console.WriteLine("  Done.");

            var worldGeoBuilders = new List <WorldGeoFileBuilder>();

            var levelMeshData = new Dictionary <string, CgfMeshesToLoad>(); // key is level folder name

            Console.WriteLine("  Processing levels...");
            bool containsValidLevel = false;
            int  curFolderIndex     = -1;

            // Load levels dir... load all except common.
            var subdirs = Directory.EnumerateDirectories(Path.Combine(aionClientPath, "Levels"))
                          .Select(fulldir => Path.GetFileName(fulldir))
                          .Where(dir => !dir.Equals("common", StringComparison.InvariantCultureIgnoreCase));
            var levelsDir = new DirManager(Path.Combine(aionClientPath, "Levels"), subdirs);

            // special case to extract the login level...
            // login is like any other level, except it has no ID and isn't included in WorldId.xml.
            if (levelId == "login")
            {
                Console.WriteLine("*** Extracting login level ***");
                worldIdXmlLoader.FolderNamesById["login"] = "******";
            }

            if (generateGeo)
            {
                foreach (var pairs in worldIdXmlLoader.FolderNamesById)
                {
                    curFolderIndex++;

                    string clientLevelId = pairs.Key;
                    string levelFolder   = pairs.Value;

                    if (!string.IsNullOrEmpty(levelId) && levelId != clientLevelId)
                    {
                        // skip excluded
                        continue;
                    }

                    Console.WriteLine($"    [{clientLevelId}] - ({curFolderIndex}/{worldIdXmlLoader.FolderNamesById.Count}) - {levelFolder} ...");

                    Console.WriteLine("      Parsing leveldata.xml ...");

                    if (!levelsDir.Exists(Path.Combine(levelFolder, "leveldata.xml")))
                    {
                        Console.WriteLine("        leveldata.xml not found, skipping level.");
                        continue;
                    }

                    // Note: this list is referenced later by index.
                    List <string> vegetationCgfFilenames;
                    Point         mapSize;
                    using (var levelDataXml = levelsDir.OpenFile(Path.Combine(levelFolder, "leveldata.xml")))
                    {
                        var levelData = new LevelDataXmlLoader(levelDataXml);
                        vegetationCgfFilenames = levelData.VegetationCgfFilenames.Select(Util.NormalizeMeshFilename).ToList();
                        mapSize = levelData.MapWidthAndHeight;
                    }

                    var meshData = new CgfMeshesToLoad();

                    BrushLstLoader brushLst = null;
                    if (levelsDir.Exists(Path.Combine(levelFolder, "brush.lst")))
                    {
                        Console.WriteLine("      Parsing brush.lst ... ");
                        using (var stream = levelsDir.OpenFile(Path.Combine(levelFolder, "brush.lst")))
                            brushLst = new BrushLstLoader(stream);

                        // TODO - un-hardcode
                        if (brushLst.m_eventUsage[1])
                        {
                            Console.WriteLine("        * Supports event: X-Mas");
                        }
                        if (brushLst.m_eventUsage[2])
                        {
                            Console.WriteLine("        * Supports event: Halloween");
                        }
                        if (brushLst.m_eventUsage[3])
                        {
                            Console.WriteLine("        * Supports event: Brax Cafe");
                        }
                        if (brushLst.m_eventUsage[4])
                        {
                            Console.WriteLine("        * Supports event: Valentines");
                        }
                    }
                    else
                    {
                        Console.WriteLine("      brush.lst not found, skipping");
                    }


                    List <ObjectsLstItem> objectsLst = null;
                    if (levelsDir.Exists(Path.Combine(levelFolder, "objects.lst")))
                    {
                        Console.WriteLine("      Parsing objects.lst ... ");
                        using (var stream = levelsDir.OpenFile(Path.Combine(levelFolder, "objects.lst")))
                            objectsLst = ObjectsLstLoader.Load(stream, mapSize.X, mapSize.Y);
                    }
                    else
                    {
                        Console.WriteLine("      objects.lst not found, skipping");
                    }

                    // ------------------------------
                    meshData.meshFiles = new List <string>();

                    // brushes
                    if (brushLst != null)
                    {
                        meshData.meshFiles.AddRange(brushLst.brushInfoList.Select(o => o.filename));
                    }

                    // vegetation
                    meshData.meshFiles.AddRange(vegetationCgfFilenames);

                    // normalize names and dedupe. example entry: "levels/common/dark/natural/rocks/base/na_d_rockgngrass_05a.cgf"
                    meshData.meshFiles = meshData.meshFiles.Select(Util.NormalizeMeshFilename).Distinct().ToList();

                    meshData.meshUsage = new int[meshData.meshFiles.Count];
                    if (!noMesh)
                    {
                        levelMeshData.Add(levelFolder, meshData);
                    }

                    byte[] landMapH32 = null;

                    if (levelsDir.Exists(Path.Combine(levelFolder, @"terrain\land_map.h32")))
                    {
                        using (var stream = levelsDir.OpenFile(Path.Combine(levelFolder, @"terrain\land_map.h32")))
                        {
                            using (var ms = new MemoryStream())
                            {
                                stream.CopyTo(ms);
                                landMapH32 = ms.ToArray();
                            }
                        }
                    }

                    // keep track of all required cgfs
                    if (brushLst != null)
                    {
                        m_requiredCgfs.UnionWith(brushLst.brushInfoList.Select(o => Util.NormalizeMeshFilename(o.filename)));
                    }
                    if (objectsLst != null)
                    {
                        m_requiredCgfs.UnionWith(vegetationCgfFilenames.Select(Util.NormalizeMeshFilename));
                    }

                    // level data must be loaded first to find the required cgfs. then, cgfs must be loaded to determine if
                    // they contain collision data or not. then we can write the geo file minus non-collidable meshes.
                    var w = new WorldGeoFileBuilder(clientLevelId, landMapH32, brushLst, vegetationCgfFilenames, objectsLst);

                    // these will be processed after meshs
                    worldGeoBuilders.Add(w);

                    containsValidLevel = true;

                    Console.WriteLine("    Done.");
                }
                Console.WriteLine("  Done.");

                // --------------------------------------------------------------------------------
                if (!noMesh && containsValidLevel)
                {
                    Console.WriteLine("  Generating meshs.geo ...");

                    int    meshesSaved   = 0;
                    string meshesGeoFile = Path.Combine(outputPath, "meshs.geo");
                    using (var meshesGeoDataStream = new BinaryWriter(File.Open(meshesGeoFile, FileMode.Create)))
                    {
                        foreach (string s in m_requiredCgfs)
                        {
                            string cgfPath = PakUtil.NormalizeFilename(s);
                            if (!meshesDir.Exists(cgfPath))
                            {
                                Console.WriteLine("    Cgf not found: " + cgfPath);
                                continue;
                            }
                            using (var cgfStream = meshesDir.OpenFile(cgfPath))
                                AddToMeshesGeo(cgfPath, new CgfLoader(cgfStream), meshesGeoDataStream,
                                               1 /*collisionIntention=physical*/);
                            meshesSaved++;
                        }
                    }

                    Console.WriteLine("  Done. " + meshesSaved + "/" + m_requiredCgfs.Count + " meshes saved.");

                    // -----------------------------------
                    Console.WriteLine("  Writing world.geo files ...");
                    int wc = 0;
                    foreach (var w in worldGeoBuilders)
                    {
                        wc++;
                        Console.Write($"      Creating {w.ClientLevelId}.geo file [{wc}/{worldGeoBuilders.Count}]... ");

                        w.CreateWorldGeoFile(outputPath, noH32, m_loadedCgfs, m_emptyCgfs);
                        Console.WriteLine("   Done.");
                    }
                    Console.WriteLine("  Done.");
                }

                // ------------------------------------

                /*VERBOSE Console.WriteLine("  Check meshes that were not found ...");
                 *          foreach (var levelMeshes in levelMeshData)
                 *          {
                 *                  Console.WriteLine("    " + levelMeshes.Key);
                 *                  CgfMeshesToLoad brushLstMeshData = levelMeshes.Value;
                 *                  for (int i = 0; i < brushLstMeshData.meshFiles.Count; i++)
                 *                  {
                 *                          if (brushLstMeshData.meshUsage[i] == 0 && !m_emptyCgfs.Contains(Util.NormalizeMeshFilename(brushLstMeshData.meshFiles[i])))
                 *                          {
                 *                                  Console.WriteLine("      " + brushLstMeshData.meshFiles[i]);
                 *                          }
                 *                  }
                 *          }*/
                Console.WriteLine("  Done.");
            }

            // --------------------------------------------------------------------------------
            if (generateDoors)
            {
                Console.WriteLine("Generating door mesh data...");

                // Writes 2 files:
                // - door data, pairing level+entityid to position
                // - door mesh file, containing start and end variations of each door model.

                // Original AL stores models in data\geo\model\static_doors as .cga files.
                // These are not actually .cga files, but instead are the same format as .geo files.
                // These meshes only contained a single state.
                //
                // This following code generates door data in a new format:
                // - Each door model is loaded twice, in the start and end positions.
                // - Each model has _start or _end appended to the mesh name.
                // - All unique door meshes are stored in doors.geo, following the same format as
                //   meshes.geo. Meshes should be identified by original name + _start or _end.
                // - All door instances are stored in doors.dat and define world placement.
                //   static_doors.xml is still necessary as it provides unique info such as key item id.

                var doorModelNames = new HashSet <string>();

                using (var doorsDat = new BinaryWriter(File.Open(Path.Combine(outputPath, "doors.dat"), FileMode.Create)))
                {
                    doorsDat.Write(0x524F4F44);

                    // collect unique doors
                    foreach (var pairs in worldIdXmlLoader.FolderNamesById)
                    {
                        curFolderIndex++;

                        string clientLevelId = pairs.Key;
                        string levelFolder   = pairs.Value;

                        if (!string.IsNullOrEmpty(levelId) && levelId != clientLevelId)
                        {
                            // skip excluded
                            continue;
                        }

                        Console.WriteLine($"    [{clientLevelId}] - ({curFolderIndex}/{worldIdXmlLoader.FolderNamesById.Count}) - {levelFolder} ...");

                        List <DoorInfo> doorInfos;
                        try
                        {
                            doorInfos = DoorLoader.LoadDoorInfosForLevel(levelsDir, levelFolder);
                        }
                        catch
                        {
                            Console.WriteLine("        Level folder not found.");
                            continue;
                        }

                        foreach (var door in doorInfos)
                        {
                            string meshName = PakUtil.NormalizeFilename(door.object_AnimatedModel);
                            doorModelNames.Add(meshName);

                            doorsDat.Write((short)meshName.Length);
                            byte[] meshFileNameBytes = Encoding.ASCII.GetBytes(meshName);
                            doorsDat.Write(meshFileNameBytes);
                            doorsDat.Write(int.Parse(clientLevelId));
                            doorsDat.Write(door.EntityId);
                            doorsDat.Write(door.Pos.X);
                            doorsDat.Write(door.Pos.Y);
                            doorsDat.Write(door.Pos.Z);
                            // TODO investigate dir / use_dir. value correlates to z angle...
                            doorsDat.Write(door.Angles.X);
                            doorsDat.Write(door.Angles.Y);
                            doorsDat.Write(door.Angles.Z);
                        }
                    }
                }

                m_loadedCgfs = new HashSet <string>();
                m_emptyCgfs  = new HashSet <string>();

                // generate door meshes.
                // a door model may be referenced many times, so models are saved separately from instances.
                int    meshesSaved  = 0;
                string doorsGeoFile = Path.Combine(outputPath, "doors.geo");
                using (var doorMeshesGeoDataStream = new BinaryWriter(File.Open(doorsGeoFile, FileMode.Create)))
                {
                    foreach (var cgfPath in doorModelNames.OrderBy(o => o))
                    {
                        if (!meshesDir.Exists(cgfPath))
                        {
                            Console.WriteLine("    Door Cgf/Cga not found: " + cgfPath);
                            continue;
                        }

                        // TODO - parameterize m_loadedCgfs and m_emptyCgfs...
                        using (var cgfStream = meshesDir.OpenFile(cgfPath))
                        {
                            var cgfFirstState  = new CgfLoader(cgfStream);
                            var cgfSecondState = cgfFirstState.CloneAtTime(999999);

                            byte collisionIntention = 1 + (1 << 4); // physical + door
                            AddToMeshesGeo(cgfPath + "_start", cgfFirstState, doorMeshesGeoDataStream, collisionIntention);
                            AddToMeshesGeo(cgfPath + "_end", cgfSecondState, doorMeshesGeoDataStream, collisionIntention);
                        }
                        meshesSaved++;
                    }
                }

                // doors should have collision data, otherwise they won't be very effective.
                foreach (var empty in m_emptyCgfs)
                {
                    Console.WriteLine("Warning: door has no collision data: " + empty);
                }
                Console.WriteLine("Door meshes: " + meshesSaved);
            }

            // --------------------------------------------------------------------------------
            if (generateNav)
            {
                Console.WriteLine("  Generating NavMesh .nav data...");
                var start = DateTime.Now;
                NavMeshProcessor.GenerateAllNav(worldIdXmlLoader, meshesDir, levelsDir,
                                                levelId, skipExistingNav, outputPath);
                Console.WriteLine("    NavMesh processing time: " + (DateTime.Now - start));
            }

            TimeSpan timerEnd = DateTime.Now - timer;

            Console.WriteLine("  Processing time: " + timerEnd);
        }
示例#13
0
 // TODO configure better... load level OR cgf, not both
 public AionLevelViewerControl(string aionClientRoot, string levelFolder, CgfLoader cgf)
 {
     m_aionClientRoot = aionClientRoot;
     m_levelFolder    = levelFolder;
     m_cgf            = cgf;
 }