예제 #1
0
        protected GameAssetServer(GameAssetKitchen kitchen)
        {
            Kitchen          = kitchen;
            taskQueue        = new ConcurrentQueue <Action>();
            taskThread       = new Thread(new ThreadStart(WorkCookingThread));
            taskThreadClosed = 0;
            taskThread.Start();

            assetCaches        = new Dictionary <string, AssetCache>();
            dependencyWatchers = new List <FileSystemWatcher>();
        }
예제 #2
0
        public NetworkGameAssetServer(GameAssetKitchen kitchen, int port)
            : base(kitchen)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            {
                SendTimeout    = 30000,
                SendBufferSize = 1024 * 1024,
                ReceiveTimeout = 30000,
                NoDelay        = true
            };
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, port));
            serverSocket.Listen(100);

            Ready();
        }
예제 #3
0
        private CookingContext(GameAssetKitchen kitchen, GameAssetStorage storage, CookingContext parent, string baseDirectory, string recipePath, GameAssetRecipe recipe)
        {
            int    variableCapacity = 4;
            string directory        = Path.GetDirectoryName(recipePath);

            this.Kitchen             = kitchen;
            this.Storage             = storage;
            this.Parent              = parent;
            this.baseDirectory       = baseDirectory ?? string.Empty;
            this.directory           = directory ?? string.Empty;
            this.variables           = new Dictionary <string, string>(variableCapacity);
            this.expandableVariables = new Dictionary <string, string>(variableCapacity);
            this.readonlyVariables   = new ReadOnlyDictionary <string, string>(this.variables);

            this.dependencies = new SortedSet <string>();
            this.CanHotload   = recipe != null ? recipe.CanHotload : false;

            SetVariable("Directory", directory);
            SetVariable("Path", recipePath);
        }
예제 #4
0
 public CookingContext(GameAssetKitchen kitchen, string baseDirectory, string recipePath, GameAssetRecipe recipe)
     : this(kitchen, kitchen.Storage, null, baseDirectory, recipePath, recipe)
 {
 }
예제 #5
0
        protected void BeginCook(string clientName, string directory, string assetPath, Action <byte[], int, int> callback, Action fallback)
        {
            string binaryAbsolutePath = Path.ChangeExtension(Path.Combine(directory, assetPath), GameAsset.BinaryFileExtension);

            // Cache Table에 Asset Binary가 존재하면 Cooking하지 않습니다.

            AssetCache cache;
            bool       hasCache = false;

            lock (assetCachesLock)
                hasCache = assetCaches.TryGetValue(binaryAbsolutePath, out cache);

            if (hasCache)
            {
                Trace.WriteLine(string.Format(":[{0}] Cache > {1}", clientName, assetPath));

                if (callback != null)
                {
                    callback(cache.Buffer, 0, cache.Buffer.Length);
                }

                return;
            }

            GameAssetKitchen kitchen = Kitchen;

            taskQueue.Enqueue(() =>
            {
                try
                {
                    string recipePath = Path.ChangeExtension(assetPath, GameAsset.TextFileExtension);
                    GameAssetKitchen.CookingReport report = kitchen.Cook(directory, recipePath);
                    if (report.Asset != null)
                    {
                        // Cooking 된 asset은 나중에 가져다 쓰기 쉽게 단순 Binary화합니다.

                        GameAssetWriter writer         = GameAssetWriter.CreateWriter(report.Asset.GetType());
                        MemoryStream memoryStream      = new MemoryStream();
                        AssetStreamWriter streamWriter = new AssetStreamWriter(memoryStream, null, Kitchen.Storage);
                        writer.Write(streamWriter, report.Asset);

                        if (callback != null)
                        {
                            callback(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
                        }

                        // Cooking 작업을 마치고 Callback까지 호출했으면,
                        //   1. Asset Binary를 Cache Table에 보관합니다.
                        //      다음 요청부터 Cooking 하지 않고 바로 Cache에서 넘겨줍니다.
                        //   2. "{AssetName}.ab" File에 Asset Binary를 저장합니다.

                        byte[] cacheBuffer = new byte[memoryStream.Length];
                        System.Buffer.BlockCopy(memoryStream.GetBuffer(), 0, cacheBuffer, 0, (int)memoryStream.Length);

                        string[] dependencies = new string[report.Dependencies.Count];
                        int dependenciesIndex = 0;
                        foreach (var item in report.Dependencies)
                        {
                            // 파일 시스템 감시자에서 넘긴 변경된 파일명과 비교해야하기 때문에 /에서 \\로 변환합니다.
                            dependencies[dependenciesIndex] = item.Replace('/', '\\');
                            dependenciesIndex++;
                        }

                        lock (assetCachesLock)
                            assetCaches[binaryAbsolutePath] = new AssetCache(cacheBuffer, dependencies);

                        WriteCacheFile(binaryAbsolutePath, cacheBuffer);

                        Trace.TraceInformation(":[{0}] Asset cooking succeed > {1}", clientName, assetPath);

                        foreach (string item in dependencies)
                        {
                            string dependencyDirectory = Path.GetDirectoryName(item);
                            if (dependencyWatchers.Exists((watcher) => string.Compare(watcher.Path, dependencyDirectory) == 0) == false)
                            {
                                var watcher      = new FileSystemWatcher(dependencyDirectory);
                                watcher.Changed += (o, e) => { RemoveAssetCachesByDependency(e.FullPath); };
                                watcher.Deleted += (o, e) => { RemoveAssetCachesByDependency(e.FullPath); };
                                watcher.Renamed += (o, e) => { RemoveAssetCachesByDependency(e.FullPath); };
                                watcher.IncludeSubdirectories = false;
                                watcher.EnableRaisingEvents   = true;
                                dependencyWatchers.Add(watcher);
                            }
                        }
                    }
                    else
                    {
                        Trace.TraceError(":[{0}] AssetRecipe not found > {1}", clientName, assetPath);

                        if (fallback != null)
                        {
                            fallback();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);

                    if (fallback != null)
                    {
                        fallback();
                    }
                }
            });
        }
예제 #6
0
 public NetworkGameAssetServer(GameAssetKitchen kitchen)
     : this(kitchen, NetworkAssetProvider.DefaultPort)
 {
 }