public async Task <bool> AddAsync(SporeServerAsset asset, SporeServerUser author, string comment) { try { var assetComment = new SporeServerAssetComment() { Author = author, Asset = asset, // comments on your own creations are automatically approved Approved = (author.Id == asset.AuthorId), Timestamp = DateTime.Now, Comment = comment }; await _context.AssetComments.AddAsync(assetComment); await _context.SaveChangesAsync(); _logger.LogInformation($"AddAsync: Added Comment {assetComment.CommentId}"); return(true); } catch (Exception e) { _logger.LogError($"AddAsync: Failed To Add Comment For {asset.AssetId}: {e}"); return(false); } }
public async Task <bool> ReserveAsync(SporeServerUser user) { try { // create new empty asset var asset = new SporeServerAsset() { Used = false, Author = user }; // add it to assets await _context.Assets.AddAsync(asset); await _context.SaveChangesAsync(); // update user user.NextAssetId = asset.AssetId; await _userManager.UpdateAsync(user); _logger.LogInformation($"ReserveAsync: Reserved Asset {asset.AssetId} For User {user.Id}"); return(true); } catch (Exception e) { _logger.LogError($"ReserveAsync: Failed To Reserve Asset For User {user.Id}: {e}"); return(false); } }
public async Task <bool> AddAsync(SporeServerUser author, SporeServerAsset asset, bool rating) { try { var assetRating = new SporeServerRating() { Author = author, Asset = asset, Timestamp = DateTime.Now, Rating = rating }; await _context.AssetRatings.AddAsync(assetRating); await _context.SaveChangesAsync(); // update asset rating await UpdateAssetRatingAsync(asset); _logger.LogInformation($"AddAsync: Added Rating {assetRating.RatingId}"); return(true); } catch (Exception e) { _logger.LogError($"AddAsync: Failed To Add Rating For {asset.AssetId}: {e}"); return(false); } }
public async Task <bool> DeleteAsync(SporeServerAsset asset) { try { var files = GetAssetFiles(asset.AssetId); // delete files foreach (string file in new string[] { files.ModelFile, files.ThumbFile, files.ImageFile, files.ImageFile2, files.ImageFile3, files.ImageFile4 }) { if (File.Exists(file)) { File.Delete(file); } } // update database _context.Assets.Remove(asset); await _context.SaveChangesAsync(); _logger.LogInformation($"DeleteAsync: Deleted Asset {asset.AssetId}"); return(true); } catch (Exception e) { _logger.LogError($"DeleteAsync: Failed To Delete Asset {asset.AssetId}: {e}"); return(false); } }
/// <summary> /// Updates asset rating /// </summary> /// <param name="asset"></param> /// <returns></returns> private async Task <bool> UpdateAssetRatingAsync(SporeServerAsset asset) { try { var assetRatings = await FindAllByAssetAsync(asset); // only update asset rating, // when we have more than 1 rating if (assetRatings != null && assetRatings.Length > 1) { // so we calculate the rating like this: // get the percentage of the positive votes, // then make sure the maximum value is 10.0 // and the minimum is -10.0 int positiveRatingCount = assetRatings.Where(r => r.Rating).Count(); float positivePercentage = positiveRatingCount / (float)assetRatings.Length * 100f; asset.Rating = (positivePercentage / 5) - 10; // update asset await _assetManager.UpdateAsync(asset); } return(true); } catch (Exception e) { _logger.LogError($"UpdateAssetRatingAsync: Failed To Update Asset Rating For {asset.AssetId}: {e}"); return(false); } }
public async Task <bool> AddAsync(SporeServerAsset adventureAsset, SporeServerAsset captainAsset, Int32 percentageCompleted, Int32 timeInMilliseconds, SporeServerUser author) { try { var entry = new SporeServerLeaderboardEntry() { Asset = adventureAsset, Author = author, Timestamp = DateTime.Now, PercentageCompleted = percentageCompleted, TimeInMilliseconds = timeInMilliseconds, Captain = captainAsset }; await _context.LeaderboardEntries.AddAsync(entry); await _context.SaveChangesAsync(); _logger.LogInformation($"AddAsync: Added Leaderboard Entry {entry.EntryId} For {entry.AuthorId}"); return(true); } catch (Exception e) { _logger.LogError($"AddAsync: Failed To Add Leaderboard Entry: {e}"); return(false); } }
public async Task <SporeServerRating[]> FindAllByAssetAsync(SporeServerAsset asset) { try { return(await _context.AssetRatings .Where(r => r.AssetId == asset.AssetId) .ToArrayAsync()); } catch (Exception e) { _logger.LogError($"FindAllByAssetAsync: Failed To Find Ratings For {asset.AssetId}: {e}"); return(null); } }
public async Task <SporeServerAsset[]> GetRandomAssetsAsync(Int64 authorId, SporeModelType type) { try { // maximum of 5 assets per request int amountOfItems = GetRandomNumber(0, 5); // find only used assets which don't have the author specified by author id // and make sure it's the type we want var assets = await _context.Assets .Include(a => a.Author) .Where(a => a.Used && a.AuthorId != authorId && a.ModelType == type) .ToArrayAsync(); int assetsCount = assets.Length; // make sure we find some assets if (assetsCount == 0) { return(null); } // adjust amountOfItems as needed if (assetsCount < amountOfItems) { amountOfItems = assetsCount; } var retAssets = new SporeServerAsset[amountOfItems]; for (int i = 0; i < amountOfItems; i++) { int randomIndex = GetRandomNumber(0, assetsCount); retAssets[i] = assets.ElementAt(randomIndex); } return(retAssets); } catch (Exception e) { _logger.LogError($"GetRandomAssets: Failed To Get random Assets: {e}"); return(null); } }
public async Task <bool> UpdateAsync(SporeServerAsset asset) { try { // update asset in database _context.Assets.Update(asset); await _context.SaveChangesAsync(); _logger.LogInformation($"UpdateAsync: Updated Asset {asset.AssetId}"); return(true); } catch (Exception e) { _logger.LogError($"UpdateAsync: Failed To Update Asset {asset.AssetId}: {e}"); return(false); } }
public async Task <SporeServerRating> FindAsync(SporeServerUser author, SporeServerAsset asset) { try { return(await _context.AssetRatings .Include(r => r.Asset) .Where(r => r.AuthorId == author.Id && r.AssetId == asset.AssetId) .FirstOrDefaultAsync()); } catch (Exception e) { _logger.LogError($"FindAsync: Failed To Find Rating For {asset.AssetId}: {e}"); return(null); } }
public async Task <SporeServerAssetComment[]> FindAllApprovedByAssetAsync(SporeServerAsset asset) { try { return(await _context.AssetComments .Include(c => c.Author) .Where(c => c.AssetId == asset.AssetId && c.Approved) .OrderByDescending(c => c.Timestamp) .Take(10) .ToArrayAsync()); } catch (Exception e) { _logger.LogError($"FindAllApprovedByAssetAsync: Failed To Find Approved Comments For {asset.AssetId}: {e}"); return(null); } }
public async Task <IActionResult> AssetUploadServlet([FromForm] AssetUploadForm formAsset) { Console.WriteLine($"/pollinator/public-interface/AssetUploadServlet{Request.QueryString}"); // the game client always sends the slurp query // and it's always either 0 or 1 if (!Request.Query.ContainsKey("slurp") || !int.TryParse(Request.Query["slurp"], out int slurpValue) || (slurpValue != 0 && slurpValue != 1)) { return(Ok()); } Int64 parentId = 0; // the game sometimes sends a parent id, // make sure we can parse it if (Request.Query.ContainsKey("parent") && !Int64.TryParse(Request.Query["parent"], out parentId)) { return(Ok()); } SporeServerAsset parentAsset = null; // when parentId is not 0, // try to find parent asset if (parentId != 0) { parentAsset = await _assetManager.FindByIdAsync(parentId); } // the game always sends the type id // make sure we can parse it // and that's it a valid id if (!Int64.TryParse(formAsset.TypeId.TrimStart('0', 'x'), NumberStyles.HexNumber, null, out Int64 typeId) || !Enum.IsDefined(typeof(SporeAssetType), typeId)) { Console.WriteLine($"invalid type id: {typeId}"); return(Ok()); } var user = await _userManager.GetUserAsync(User); // make sure the requested assetId is the user's nextAssetId if (user.NextAssetId != formAsset.AssetId) { return(Ok()); } var asset = await _assetManager.FindByIdAsync(formAsset.AssetId); // make sure the asset exists and // make sure it isn't already used if (asset == null || asset.Used) { return(Ok()); } // make sure the asset doesn't go over any limits if ((formAsset.Description != null && formAsset.Description.Length > 256) || (formAsset.ModelData != null && formAsset.ModelData.FileName.Length > 32) || (formAsset.Tags != null && formAsset.Tags.Length > 256)) { return(Ok()); } // save the asset if (!await _assetManager.AddAsync(formAsset, asset, parentAsset, (slurpValue == 1), (SporeAssetType)typeId)) { return(StatusCode(500)); } return(Ok()); }
public async Task <bool> AddAsync(AssetUploadForm form, SporeServerAsset asset, SporeServerAsset parentAsset, bool slurped, SporeAssetType type) { try { var files = GetAssetFiles(form.AssetId); // load, validate & deserialize SporeModel SporeModel model = null; string modelXml = null; using (Stream modelStream = OpenFormFileStream(form.ModelData)) { if (!LoadSporeModel(modelStream, out model)) { throw new Exception("LoadSporeModel Failed"); } if (!ValidateSporeModel(model)) { throw new Exception("ValidateSporeModel Failed"); } if (!DeserializeSporeModel(model, out modelXml)) { throw new Exception("DeserializeSporeModel Failed"); } } // save files File.WriteAllText(files.ModelFile, modelXml); await SaveFormFile(form.ThumbnailData, files.ThumbFile); if (form.ImageData != null) { await SaveFormFile(form.ImageData, files.ImageFile); } if (form.ImageData_2 != null) { await SaveFormFile(form.ImageData_2, files.ImageFile2); } if (form.ImageData_3 != null) { await SaveFormFile(form.ImageData_3, files.ImageFile3); } if (form.ImageData_4 != null) { await SaveFormFile(form.ImageData_4, files.ImageFile4); } // update database asset.Used = true; asset.Timestamp = DateTime.Now; asset.OriginalAssetId = 0; asset.ParentAssetId = 0; if (parentAsset != null) { // when original asset id of parent is 0, // the parent id is the original asset id // else follow the original asset id specified if (parentAsset.OriginalAssetId == 0) { asset.OriginalAssetId = parentAsset.AssetId; } else { asset.OriginalAssetId = parentAsset.OriginalAssetId; } asset.ParentAssetId = parentAsset.AssetId; } asset.Name = form.ModelData.FileName; var tags = new List <SporeServerAssetTag>(); if (form.Tags != null) { foreach (string tagString in form.Tags.Split(",")) { string trimmedTagString = tagString.TrimStart().TrimEnd(); tags.Add(new SporeServerAssetTag() { Asset = asset, Tag = trimmedTagString }); } } asset.Tags = tags; var traits = new List <SporeServerAssetTrait>(); if (form.TraitGuids != null) { foreach (string traitString in form.TraitGuids.Split(",")) { string trimmedTraitString = traitString.TrimStart() .TrimStart('0', 'x') .TrimEnd(); Int64 traitType = Int64.Parse(trimmedTraitString, NumberStyles.HexNumber); // make sure the trait id is valid if (!Enum.IsDefined(typeof(SporeAssetTraitType), traitType)) { throw new Exception($"Invalid Trait Id: {traitType}"); } traits.Add(new SporeServerAssetTrait() { Asset = asset, TraitType = (SporeAssetTraitType)traitType }); } } asset.Traits = traits; asset.Description = form.Description; asset.Size = form.ThumbnailData.Length; asset.Slurped = slurped; // TODO, put this in a struct or whatever? asset.ModelFileUrl = GetRelativeUrlFromPath(files.ModelFile); asset.ThumbFileUrl = GetRelativeUrlFromPath(files.ThumbFile); asset.ImageFileUrl = GetRelativeUrlFromPath(files.ImageFile); asset.ImageFile2Url = GetRelativeUrlFromPath(files.ImageFile2); asset.ImageFile3Url = GetRelativeUrlFromPath(files.ImageFile3); asset.ImageFile4Url = GetRelativeUrlFromPath(files.ImageFile4); asset.ModelType = (SporeModelType)model.Properties.ModelType; asset.Type = type; _context.Assets.Update(asset); await _context.SaveChangesAsync(); _logger.LogInformation($"AddAsync: Added Asset {asset.AssetId}"); return(true); } catch (Exception e) { _logger.LogError($"AddAsync: Failed To Add Asset {asset.AssetId}: {e}"); return(false); } }
/// <summary> /// Creates an ATOM feed entry for the given asset /// </summary> /// <param name="document"></param> /// <param name="asset"></param> public static void AddAssetFeedEntry(XmlDocument document, SporeServerAsset asset) { // <entry /> // var entryFeed = AtomFeedBuilder.AddFeedEntry(document, id: $"tag:spore.com,2006:asset/{asset.AssetId}", title: $"{asset.Name}", updated: asset.Timestamp, subtitle: null, authorName: $"{asset.Author.UserName}", authorUri: $"{asset.Author.Id}", subCount: null, link: null); // <locale /> // TODO AtomFeedBuilder.AddCustomElement(document, entryFeed, "locale", "en_US"); // <modeltype /> AtomFeedBuilder.AddCustomElement(document, entryFeed, "modeltype", $"0x{((Int64)asset.ModelType):x2}"); // <sp:stats /> // TODO if (asset.Type == SporeAssetType.Adventure) { var statsElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "sp:stats"); // <sp:stat name="playcount" /> var statElement = AtomFeedBuilder.AddCustomElement(document, statsElement, "sp:stat", "0"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "name", "playcount"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "type", "int"); // <sp:stat name="difficulty" /> statElement = AtomFeedBuilder.AddCustomElement(document, statsElement, "sp:stat", "0"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "name", "difficulty"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "type", "int"); // <sp:stat name="rating" /> statElement = AtomFeedBuilder.AddCustomElement(document, statsElement, "sp:stat", $"{asset.Rating}"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "name", "rating"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "type", "float"); // <sp:stat name="pointvalue" /> statElement = AtomFeedBuilder.AddCustomElement(document, statsElement, "sp:stat", "0"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "name", "pointvalue"); AtomFeedBuilder.AddCustomAttribute(document, statElement, "type", "int"); } // <sp:images /> // if (asset.Type == SporeAssetType.Adventure) { var imagesElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "sp:images", null); // <sp:image_1 /> if (asset.ImageFileUrl != null) { AtomFeedBuilder.AddLinkElement(document, imagesElement, name: "sp:image_1", rel: null, url: $"https://static.spore.com/{asset.ImageFileUrl}", type: "image/png", length: null); } // <sp:image_2 /> if (asset.ImageFile2Url != null) { AtomFeedBuilder.AddLinkElement(document, imagesElement, name: "sp:image_2", rel: null, url: $"https://static.spore.com/{asset.ImageFile2Url}", type: "image/png", length: null); } // <sp:image_3 /> if (asset.ImageFile3Url != null) { AtomFeedBuilder.AddLinkElement(document, imagesElement, name: "sp:image_3", rel: null, url: $"https://static.spore.com/{asset.ImageFile3Url}", type: "image/png", length: null); } // <sp:image_4 /> if (asset.ImageFile4Url != null) { AtomFeedBuilder.AddLinkElement(document, imagesElement, name: "sp:image_4", rel: null, url: $"https://static.spore.com/{asset.ImageFile4Url}", type: "image/png", length: null); } } // <sp:ownership /> // var ownershipElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "sp:ownership"); // <sp:original /> var originalElement = AtomFeedBuilder.AddCustomElement(document, ownershipElement, "sp:original", $"{asset.OriginalAssetId}"); AtomFeedBuilder.AddCustomAttribute(document, originalElement, "name", "id"); AtomFeedBuilder.AddCustomAttribute(document, originalElement, "type", "int"); // <sp:parent /> var parentElement = AtomFeedBuilder.AddCustomElement(document, ownershipElement, "sp:parent", $"{asset.ParentAssetId}"); AtomFeedBuilder.AddCustomAttribute(document, parentElement, "name", "id"); AtomFeedBuilder.AddCustomAttribute(document, parentElement, "type", "int"); // <content /> // var contentElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "content"); AtomFeedBuilder.AddCustomAttribute(document, contentElement, "type", "html"); // <img /> var imgElement = AtomFeedBuilder.AddCustomElement(document, contentElement, "img"); AtomFeedBuilder.AddCustomAttribute(document, imgElement, "src", $"https://static.spore.com/{asset.ThumbFileUrl}"); // <link /> // AtomFeedBuilder.AddLinkElement(document, entryFeed, rel: "enclosure", url: $"https://static.spore.com/{asset.ThumbFileUrl}", type: "image/png", length: $"{asset.Size}"); // <link /> // AtomFeedBuilder.AddLinkElement(document, entryFeed, rel: "enclosure", url: $"https://static.spore.com/{asset.ModelFileUrl}", type: $"application/x-{asset.Type.ToString().ToLower()}+xml", length: null); // <summary /> // AtomFeedBuilder.AddCustomElement(document, entryFeed, "summary", $"{asset.Description}"); // <category /> // if (asset.Tags != null) { for (int i = 0; i < asset.Tags.Count; i++) { // <category scheme="tag" term="tag1" /> // <category scheme="tag" term=" tag2" /> var tag = asset.Tags.ElementAt(i); var categoryElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "category"); AtomFeedBuilder.AddCustomAttribute(document, categoryElement, "scheme", "tag"); AtomFeedBuilder.AddCustomAttribute(document, categoryElement, "term", $"{(i == 0 ? "" : " ")}{tag.Tag}"); } } if (asset.Traits != null) { foreach (var trait in asset.Traits) { // <category scheme="consequence" term="0x2b35f523" /> var categoryElement = AtomFeedBuilder.AddCustomElement(document, entryFeed, "category"); AtomFeedBuilder.AddCustomAttribute(document, categoryElement, "scheme", "consequence"); AtomFeedBuilder.AddCustomAttribute(document, categoryElement, "term", $"0x{(Int64)trait.TraitType:x}"); } } }