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>(); }
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(); }
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); }
public CookingContext(GameAssetKitchen kitchen, string baseDirectory, string recipePath, GameAssetRecipe recipe) : this(kitchen, kitchen.Storage, null, baseDirectory, recipePath, recipe) { }
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(); } } }); }
public NetworkGameAssetServer(GameAssetKitchen kitchen) : this(kitchen, NetworkAssetProvider.DefaultPort) { }