diff --git a/gaseous-server/Classes/Metadata/GameModes.cs b/gaseous-server/Classes/Metadata/GameModes.cs new file mode 100644 index 0000000..bca0c7a --- /dev/null +++ b/gaseous-server/Classes/Metadata/GameModes.cs @@ -0,0 +1,110 @@ +using System; +using gaseous_tools; +using IGDB; +using IGDB.Models; +using MySqlX.XDevAPI.Common; +using static gaseous_tools.Config.ConfigFile; + +namespace gaseous_server.Classes.Metadata +{ + public class GameModes + { + const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;"; + + public GameModes() + { + } + + private static IGDBClient igdb = new IGDBClient( + // Found in Twitch Developer portal for your app + Config.IGDB.ClientId, + Config.IGDB.Secret + ); + + public static GameMode? GetGame_Modes(long? Id) + { + if ((Id == 0) || (Id == null)) + { + return null; + } + else + { + Task RetVal = _GetGame_Modes(SearchUsing.id, Id); + return RetVal.Result; + } + } + + public static GameMode GetGame_Modes(string Slug) + { + Task RetVal = _GetGame_Modes(SearchUsing.slug, Slug); + return RetVal.Result; + } + + private static async Task _GetGame_Modes(SearchUsing searchUsing, object searchValue) + { + // check database first + Storage.CacheStatus? cacheStatus = new Storage.CacheStatus(); + if (searchUsing == SearchUsing.id) + { + cacheStatus = Storage.GetCacheStatus("GameMode", (long)searchValue); + } + else + { + cacheStatus = Storage.GetCacheStatus("GameMode", (string)searchValue); + } + + // set up where clause + string WhereClause = ""; + switch (searchUsing) + { + case SearchUsing.id: + WhereClause = "where id = " + searchValue; + break; + case SearchUsing.slug: + WhereClause = "where slug = " + searchValue; + break; + default: + throw new Exception("Invalid search type"); + } + + GameMode returnValue = new GameMode(); + bool forceImageDownload = false; + switch (cacheStatus) + { + case Storage.CacheStatus.NotPresent: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue); + forceImageDownload = true; + break; + case Storage.CacheStatus.Expired: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue, true); + forceImageDownload = true; + break; + case Storage.CacheStatus.Current: + returnValue = Storage.GetCacheValue(returnValue, "id", (long)searchValue); + break; + default: + throw new Exception("How did you get here?"); + } + + return returnValue; + } + + private enum SearchUsing + { + id, + slug + } + + private static async Task GetObjectFromServer(string WhereClause) + { + // get Game_Modes metadata + var results = await igdb.QueryAsync(IGDBClient.Endpoints.GameModes, query: fieldList + " " + WhereClause + ";"); + var result = results.First(); + + return result; + } + } +} + diff --git a/gaseous-server/Classes/Metadata/Games.cs b/gaseous-server/Classes/Metadata/Games.cs index 169cb7a..8cd02d4 100644 --- a/gaseous-server/Classes/Metadata/Games.cs +++ b/gaseous-server/Classes/Metadata/Games.cs @@ -205,6 +205,22 @@ namespace gaseous_server.Classes.Metadata } } + if (Game.GameModes != null) + { + foreach (long gameModeId in Game.GameModes.Ids) + { + GameMode gameMode = GameModes.GetGame_Modes(gameModeId); + } + } + + if (Game.MultiplayerModes != null) + { + foreach (long multiplayerModeId in Game.MultiplayerModes.Ids) + { + MultiplayerMode multiplayerMode = MultiplayerModes.GetGame_MultiplayerModes(multiplayerModeId); + } + } + if (Game.Platforms != null) { foreach (long PlatformId in Game.Platforms.Ids) @@ -213,6 +229,14 @@ namespace gaseous_server.Classes.Metadata } } + if (Game.PlayerPerspectives != null) + { + foreach (long PerspectiveId in Game.PlayerPerspectives.Ids) + { + PlayerPerspective GamePlayPerspective = PlayerPerspectives.GetGame_PlayerPerspectives(PerspectiveId); + } + } + if (Game.Screenshots != null) { foreach (long ScreenshotId in Game.Screenshots.Ids) @@ -221,6 +245,14 @@ namespace gaseous_server.Classes.Metadata } } + if (Game.Themes != null) + { + foreach (long ThemeId in Game.Themes.Ids) + { + Theme GameTheme = Themes.GetGame_Themes(ThemeId); + } + } + if (Game.Videos != null) { foreach (long GameVideoId in Game.Videos.Ids) diff --git a/gaseous-server/Classes/Metadata/MultiplayerModes.cs b/gaseous-server/Classes/Metadata/MultiplayerModes.cs new file mode 100644 index 0000000..d025e79 --- /dev/null +++ b/gaseous-server/Classes/Metadata/MultiplayerModes.cs @@ -0,0 +1,110 @@ +using System; +using gaseous_tools; +using IGDB; +using IGDB.Models; +using MySqlX.XDevAPI.Common; +using static gaseous_tools.Config.ConfigFile; + +namespace gaseous_server.Classes.Metadata +{ + public class MultiplayerModes + { + const string fieldList = "fields campaigncoop,checksum,dropin,game,lancoop,offlinecoop,offlinecoopmax,offlinemax,onlinecoop,onlinecoopmax,onlinemax,platform,splitscreen,splitscreenonline;"; + + public MultiplayerModes() + { + } + + private static IGDBClient igdb = new IGDBClient( + // Found in Twitch Developer portal for your app + Config.IGDB.ClientId, + Config.IGDB.Secret + ); + + public static MultiplayerMode? GetGame_MultiplayerModes(long? Id) + { + if ((Id == 0) || (Id == null)) + { + return null; + } + else + { + Task RetVal = _GetGame_MultiplayerModes(SearchUsing.id, Id); + return RetVal.Result; + } + } + + public static MultiplayerMode GetGame_MultiplayerModes(string Slug) + { + Task RetVal = _GetGame_MultiplayerModes(SearchUsing.slug, Slug); + return RetVal.Result; + } + + private static async Task _GetGame_MultiplayerModes(SearchUsing searchUsing, object searchValue) + { + // check database first + Storage.CacheStatus? cacheStatus = new Storage.CacheStatus(); + if (searchUsing == SearchUsing.id) + { + cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (long)searchValue); + } + else + { + cacheStatus = Storage.GetCacheStatus("MultiplayerMode", (string)searchValue); + } + + // set up where clause + string WhereClause = ""; + switch (searchUsing) + { + case SearchUsing.id: + WhereClause = "where id = " + searchValue; + break; + case SearchUsing.slug: + WhereClause = "where slug = " + searchValue; + break; + default: + throw new Exception("Invalid search type"); + } + + MultiplayerMode returnValue = new MultiplayerMode(); + bool forceImageDownload = false; + switch (cacheStatus) + { + case Storage.CacheStatus.NotPresent: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue); + forceImageDownload = true; + break; + case Storage.CacheStatus.Expired: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue, true); + forceImageDownload = true; + break; + case Storage.CacheStatus.Current: + returnValue = Storage.GetCacheValue(returnValue, "id", (long)searchValue); + break; + default: + throw new Exception("How did you get here?"); + } + + return returnValue; + } + + private enum SearchUsing + { + id, + slug + } + + private static async Task GetObjectFromServer(string WhereClause) + { + // get Game_MultiplayerModes metadata + var results = await igdb.QueryAsync(IGDBClient.Endpoints.MultiplayerModes, query: fieldList + " " + WhereClause + ";"); + var result = results.First(); + + return result; + } + } +} + diff --git a/gaseous-server/Classes/Metadata/PlayerPerspectives.cs b/gaseous-server/Classes/Metadata/PlayerPerspectives.cs new file mode 100644 index 0000000..988f093 --- /dev/null +++ b/gaseous-server/Classes/Metadata/PlayerPerspectives.cs @@ -0,0 +1,110 @@ +using System; +using gaseous_tools; +using IGDB; +using IGDB.Models; +using MySqlX.XDevAPI.Common; +using static gaseous_tools.Config.ConfigFile; + +namespace gaseous_server.Classes.Metadata +{ + public class PlayerPerspectives + { + const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;"; + + public PlayerPerspectives() + { + } + + private static IGDBClient igdb = new IGDBClient( + // Found in Twitch Developer portal for your app + Config.IGDB.ClientId, + Config.IGDB.Secret + ); + + public static PlayerPerspective? GetGame_PlayerPerspectives(long? Id) + { + if ((Id == 0) || (Id == null)) + { + return null; + } + else + { + Task RetVal = _GetGame_PlayerPerspectives(SearchUsing.id, Id); + return RetVal.Result; + } + } + + public static PlayerPerspective GetGame_PlayerPerspectives(string Slug) + { + Task RetVal = _GetGame_PlayerPerspectives(SearchUsing.slug, Slug); + return RetVal.Result; + } + + private static async Task _GetGame_PlayerPerspectives(SearchUsing searchUsing, object searchValue) + { + // check database first + Storage.CacheStatus? cacheStatus = new Storage.CacheStatus(); + if (searchUsing == SearchUsing.id) + { + cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (long)searchValue); + } + else + { + cacheStatus = Storage.GetCacheStatus("PlayerPerspective", (string)searchValue); + } + + // set up where clause + string WhereClause = ""; + switch (searchUsing) + { + case SearchUsing.id: + WhereClause = "where id = " + searchValue; + break; + case SearchUsing.slug: + WhereClause = "where slug = " + searchValue; + break; + default: + throw new Exception("Invalid search type"); + } + + PlayerPerspective returnValue = new PlayerPerspective(); + bool forceImageDownload = false; + switch (cacheStatus) + { + case Storage.CacheStatus.NotPresent: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue); + forceImageDownload = true; + break; + case Storage.CacheStatus.Expired: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue, true); + forceImageDownload = true; + break; + case Storage.CacheStatus.Current: + returnValue = Storage.GetCacheValue(returnValue, "id", (long)searchValue); + break; + default: + throw new Exception("How did you get here?"); + } + + return returnValue; + } + + private enum SearchUsing + { + id, + slug + } + + private static async Task GetObjectFromServer(string WhereClause) + { + // get Game_PlayerPerspectives metadata + var results = await igdb.QueryAsync(IGDBClient.Endpoints.PlayerPerspectives, query: fieldList + " " + WhereClause + ";"); + var result = results.First(); + + return result; + } + } +} + diff --git a/gaseous-server/Classes/Metadata/Themes.cs b/gaseous-server/Classes/Metadata/Themes.cs new file mode 100644 index 0000000..f9c5fea --- /dev/null +++ b/gaseous-server/Classes/Metadata/Themes.cs @@ -0,0 +1,110 @@ +using System; +using gaseous_tools; +using IGDB; +using IGDB.Models; +using MySqlX.XDevAPI.Common; +using static gaseous_tools.Config.ConfigFile; + +namespace gaseous_server.Classes.Metadata +{ + public class Themes + { + const string fieldList = "fields checksum,created_at,name,slug,updated_at,url;"; + + public Themes() + { + } + + private static IGDBClient igdb = new IGDBClient( + // Found in Twitch Developer portal for your app + Config.IGDB.ClientId, + Config.IGDB.Secret + ); + + public static Theme? GetGame_Themes(long? Id) + { + if ((Id == 0) || (Id == null)) + { + return null; + } + else + { + Task RetVal = _GetGame_Themes(SearchUsing.id, Id); + return RetVal.Result; + } + } + + public static Theme GetGame_Themes(string Slug) + { + Task RetVal = _GetGame_Themes(SearchUsing.slug, Slug); + return RetVal.Result; + } + + private static async Task _GetGame_Themes(SearchUsing searchUsing, object searchValue) + { + // check database first + Storage.CacheStatus? cacheStatus = new Storage.CacheStatus(); + if (searchUsing == SearchUsing.id) + { + cacheStatus = Storage.GetCacheStatus("Theme", (long)searchValue); + } + else + { + cacheStatus = Storage.GetCacheStatus("Theme", (string)searchValue); + } + + // set up where clause + string WhereClause = ""; + switch (searchUsing) + { + case SearchUsing.id: + WhereClause = "where id = " + searchValue; + break; + case SearchUsing.slug: + WhereClause = "where slug = " + searchValue; + break; + default: + throw new Exception("Invalid search type"); + } + + Theme returnValue = new Theme(); + bool forceImageDownload = false; + switch (cacheStatus) + { + case Storage.CacheStatus.NotPresent: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue); + forceImageDownload = true; + break; + case Storage.CacheStatus.Expired: + returnValue = await GetObjectFromServer(WhereClause); + Storage.NewCacheValue(returnValue, true); + forceImageDownload = true; + break; + case Storage.CacheStatus.Current: + returnValue = Storage.GetCacheValue(returnValue, "id", (long)searchValue); + break; + default: + throw new Exception("How did you get here?"); + } + + return returnValue; + } + + private enum SearchUsing + { + id, + slug + } + + private static async Task GetObjectFromServer(string WhereClause) + { + // get Game_Themes metadata + var results = await igdb.QueryAsync(IGDBClient.Endpoints.Themes, query: fieldList + " " + WhereClause + ";"); + var result = results.First(); + + return result; + } + } +} + diff --git a/gaseous-server/Controllers/FilterController.cs b/gaseous-server/Controllers/FilterController.cs index e8af867..3e10065 100644 --- a/gaseous-server/Controllers/FilterController.cs +++ b/gaseous-server/Controllers/FilterController.cs @@ -45,6 +45,39 @@ namespace gaseous_server.Controllers } FilterSet.Add("genres", genres); + // game modes + List gameModes = new List(); + sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM GameMode AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.GameModes, CAST(t1.Id AS char), '$') ORDER BY t1.Id"; + dbResponse = db.ExecuteCMD(sql); + + foreach (DataRow dr in dbResponse.Rows) + { + gameModes.Add(Classes.Metadata.GameModes.GetGame_Modes((long)dr["id"])); + } + FilterSet.Add("gamemodes", gameModes); + + // player perspectives + List playerPerspectives = new List(); + sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM PlayerPerspective AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.PlayerPerspectives, CAST(t1.Id AS char), '$') ORDER BY t1.`Name`"; + dbResponse = db.ExecuteCMD(sql); + + foreach (DataRow dr in dbResponse.Rows) + { + playerPerspectives.Add(Classes.Metadata.PlayerPerspectives.GetGame_PlayerPerspectives((long)dr["id"])); + } + FilterSet.Add("playerperspectives", playerPerspectives); + + // themes + List themes = new List(); + sql = "SELECT DISTINCT t1.Id, t1.`Name` FROM Theme AS t1 JOIN (SELECT * FROM Game WHERE (SELECT COUNT(Id) FROM Games_Roms WHERE GameId = Game.Id) > 0) AS t2 ON JSON_CONTAINS(t2.Themes, CAST(t1.Id AS char), '$') ORDER BY t1.`Name`"; + dbResponse = db.ExecuteCMD(sql); + + foreach (DataRow dr in dbResponse.Rows) + { + themes.Add(Classes.Metadata.Themes.GetGame_Themes((long)dr["id"])); + } + FilterSet.Add("themes", themes); + return FilterSet; } } diff --git a/gaseous-server/Controllers/GamesController.cs b/gaseous-server/Controllers/GamesController.cs index 8d2c0b9..b035678 100644 --- a/gaseous-server/Controllers/GamesController.cs +++ b/gaseous-server/Controllers/GamesController.cs @@ -23,7 +23,16 @@ namespace gaseous_server.Controllers { [HttpGet] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] - public ActionResult Game(string name = "", string platform = "", string genre = "", bool sortdescending = false) + public ActionResult Game( + string name = "", + string platform = "", + string genre = "", + string gamemode = "", + string playerperspective = "", + string theme = "", + int minrating = -1, + int maxrating = -1, + bool sortdescending = false) { string whereClause = ""; string havingClause = ""; @@ -41,6 +50,20 @@ namespace gaseous_server.Controllers havingClauses.Add(tempVal); } + if (minrating != -1) + { + string ratingTempMinVal = "totalRating >= @totalMinRating"; + whereParams.Add("@totalMinRating", minrating); + havingClauses.Add(ratingTempMinVal); + } + + if (maxrating != -1) + { + string ratingTempMaxVal = "totalRating <= @totalMaxRating"; + whereParams.Add("@totalMaxRating", maxrating); + havingClauses.Add(ratingTempMaxVal); + } + if (platform.Length > 0) { tempVal = "Games_Roms.PlatformId IN ("; @@ -77,6 +100,60 @@ namespace gaseous_server.Controllers whereClauses.Add(tempVal); } + if (gamemode.Length > 0) + { + tempVal = "("; + string[] gameModeClauseItems = gamemode.Split(","); + for (int i = 0; i < gameModeClauseItems.Length; i++) + { + if (i > 0) + { + tempVal += " AND "; + } + string gameModeLabel = "@GameMode" + i; + tempVal += "JSON_CONTAINS(Game.GameModes, " + gameModeLabel + ", '$')"; + whereParams.Add(gameModeLabel, gameModeClauseItems[i]); + } + tempVal += ")"; + whereClauses.Add(tempVal); + } + + if (playerperspective.Length > 0) + { + tempVal = "("; + string[] playerPerspectiveClauseItems = playerperspective.Split(","); + for (int i = 0; i < playerPerspectiveClauseItems.Length; i++) + { + if (i > 0) + { + tempVal += " AND "; + } + string playerPerspectiveLabel = "@PlayerPerspective" + i; + tempVal += "JSON_CONTAINS(Game.PlayerPerspectives, " + playerPerspectiveLabel + ", '$')"; + whereParams.Add(playerPerspectiveLabel, playerPerspectiveClauseItems[i]); + } + tempVal += ")"; + whereClauses.Add(tempVal); + } + + if (theme.Length > 0) + { + tempVal = "("; + string[] themeClauseItems = theme.Split(","); + for (int i = 0; i < themeClauseItems.Length; i++) + { + if (i > 0) + { + tempVal += " AND "; + } + string themeLabel = "@Theme" + i; + tempVal += "JSON_CONTAINS(Game.Themes, " + themeLabel + ", '$')"; + whereParams.Add(themeLabel, themeClauseItems[i]); + } + tempVal += ")"; + whereClauses.Add(tempVal); + } + // build where clause if (whereClauses.Count > 0) { diff --git a/gaseous-server/wwwroot/emulators/EmulatorJS b/gaseous-server/wwwroot/emulators/EmulatorJS index e19c023..8c5def7 160000 --- a/gaseous-server/wwwroot/emulators/EmulatorJS +++ b/gaseous-server/wwwroot/emulators/EmulatorJS @@ -1 +1 @@ -Subproject commit e19c0233d162ad6d7442bf77553a6557c8a351c5 +Subproject commit 8c5def77a094dd2fc38f3d17dd7c909c140eb2f4 diff --git a/gaseous-server/wwwroot/pages/game.html b/gaseous-server/wwwroot/pages/game.html index 5f862a1..4262caf 100644 --- a/gaseous-server/wwwroot/pages/game.html +++ b/gaseous-server/wwwroot/pages/game.html @@ -4,11 +4,17 @@
+
+ + +

-

+

Also known as:

+ +

@@ -78,6 +84,17 @@ var gameTitleLabel = document.getElementById('gametitle_label'); gameTitleLabel.innerHTML = result.name; + // get critic rating + if (gameData.totalRating) { + var criticscoreval = document.getElementById('gametitle_criticrating_value'); + criticscoreval.innerHTML = Math.floor(gameData.totalRating) + '%'; + + if (gameData.totalRatingCount) { + var criticscorelabel = document.getElementById('gametitle_criticrating_label'); + criticscorelabel.innerHTML = "based on
" + gameData.totalRatingCount + " votes" + } + } + // get alt name var gameTitleAltLabel = document.getElementById('gametitle_alts'); if (result.alternativeNames) { diff --git a/gaseous-server/wwwroot/pages/home.html b/gaseous-server/wwwroot/pages/home.html index 439e388..1ef29ae 100644 --- a/gaseous-server/wwwroot/pages/home.html +++ b/gaseous-server/wwwroot/pages/home.html @@ -7,10 +7,12 @@ ajaxCall('/api/v1/Filter', 'GET', function (result) { var filterElement = document.getElementById('games_filter'); formatFilterPanel(filterElement, result); + + executeFilter(); }); - ajaxCall('/api/v1/Games', 'GET', function (result) { - var gameElement = document.getElementById('games_library'); - formatGamesPanel(gameElement, result); - }); + //ajaxCall('/api/v1/Games', 'GET', function (result) { + // var gameElement = document.getElementById('games_library'); + // formatGamesPanel(gameElement, result); + //}); \ No newline at end of file diff --git a/gaseous-server/wwwroot/scripts/filterformating.js b/gaseous-server/wwwroot/scripts/filterformating.js index b5ed334..41c8f39 100644 --- a/gaseous-server/wwwroot/scripts/filterformating.js +++ b/gaseous-server/wwwroot/scripts/filterformating.js @@ -15,44 +15,111 @@ panel.appendChild(containerPanelSearch); + panel.appendChild(buildFilterPanelHeader('userrating', 'User Rating')); + var containerPanelUserRating = document.createElement('div'); + containerPanelUserRating.className = 'filter_panel_box'; + var containerPanelUserRatingMinField = document.createElement('input'); + containerPanelUserRatingMinField.id = 'filter_panel_userrating_min'; + containerPanelUserRatingMinField.type = 'number'; + containerPanelUserRatingMinField.placeholder = '0'; + containerPanelUserRatingMinField.setAttribute('onchange', 'executeFilterDelayed();'); + containerPanelUserRatingMinField.setAttribute('onkeydown', 'executeFilterDelayed();'); + containerPanelUserRatingMinField.setAttribute('min', '0'); + containerPanelUserRatingMinField.setAttribute('max', '100'); + containerPanelUserRating.appendChild(containerPanelUserRatingMinField); + + var containerPanelUserRatingMaxField = document.createElement('input'); + containerPanelUserRatingMaxField.id = 'filter_panel_userrating_max'; + containerPanelUserRatingMaxField.type = 'number'; + containerPanelUserRatingMaxField.placeholder = '100'; + containerPanelUserRatingMaxField.setAttribute('onchange', 'executeFilterDelayed();'); + containerPanelUserRatingMaxField.setAttribute('onkeydown', 'executeFilterDelayed();'); + containerPanelUserRatingMaxField.setAttribute('min', '0'); + containerPanelUserRatingMaxField.setAttribute('max', '100'); + containerPanelUserRating.appendChild(containerPanelUserRatingMaxField); + + panel.appendChild(containerPanelUserRating); + if (result.platforms) { - panel.appendChild(buildFilterPanelHeader('platforms', 'Platforms')); - - var containerPanelPlatform = document.createElement('div'); - containerPanelPlatform.className = 'filter_panel_box'; - for (var i = 0; i < result.platforms.length; i++) { - containerPanelPlatform.appendChild(buildFilterPanelItem('platforms', result.platforms[i].id, result.platforms[i].name)); - } - panel.appendChild(containerPanelPlatform); - - targetElement.appendChild(panel); + buildFilterPanel(panel, 'platform', 'Platforms', result.platforms, true, true); } if (result.genres) { - panel.appendChild(buildFilterPanelHeader('genres', 'Genres')); - - var containerPanelGenres = document.createElement('div'); - containerPanelGenres.className = 'filter_panel_box'; - for (var i = 0; i < result.genres.length; i++) { - containerPanelGenres.appendChild(buildFilterPanelItem('genres', result.genres[i].id, result.genres[i].name)); - } - panel.appendChild(containerPanelGenres); - - targetElement.appendChild(panel); + buildFilterPanel(panel, 'genre', 'Genres', result.genres, true, false); } - + if (result.gamemodes) { + buildFilterPanel(panel, 'gamemode', 'Players', result.gamemodes, true, false); + } + + if (result.playerperspectives) { + buildFilterPanel(panel, 'playerperspective', 'Player Perspectives', result.playerperspectives, true, false); + } + + if (result.themes) { + buildFilterPanel(panel, 'theme', 'Themes', result.themes, true, false); + } + + targetElement.appendChild(panel); } -function buildFilterPanelHeader(headerString, friendlyHeaderString) { +function buildFilterPanel(targetElement, headerString, friendlyHeaderString, valueList, showToggle, initialDisplay) { + if (showToggle == false) { initialDisplay = true; } + targetElement.appendChild(buildFilterPanelHeader(headerString, friendlyHeaderString, showToggle, initialDisplay)); + + var containerPanel = document.createElement('div'); + containerPanel.className = 'filter_panel_box'; + containerPanel.id = 'filter_panel_box_' + headerString; + if (initialDisplay == false) { + containerPanel.setAttribute('style', 'display: none;'); + } + for (var i = 0; i < valueList.length; i++) { + containerPanel.appendChild(buildFilterPanelItem(headerString, valueList[i].id, valueList[i].name)); + } + targetElement.appendChild(containerPanel); +} + +function buildFilterPanelHeader(headerString, friendlyHeaderString, showVisibleToggle, toggleInitialValue) { + var headerToggle = document.createElement('div'); + headerToggle.setAttribute('style', 'float: right;'); + headerToggle.id = 'filter_panel_header_toggle_' + headerString; + if (toggleInitialValue == true) { + headerToggle.innerHTML = '-'; + } else { + headerToggle.innerHTML = '+'; + } + + var headerLabel = document.createElement('span'); + headerLabel.innerHTML = friendlyHeaderString; + var header = document.createElement('div'); header.id = 'filter_panel_header_' + headerString; header.className = 'filter_header'; - header.innerHTML = friendlyHeaderString; + + if (showVisibleToggle == true) { + header.appendChild(headerToggle); + header.setAttribute('onclick', 'toggleFilterPanel("' + headerString + '");'); + header.style.cursor = 'pointer'; + } + + header.appendChild(headerLabel); return header; } +function toggleFilterPanel(panelName) { + var filterPanel = document.getElementById('filter_panel_box_' + panelName); + var filterPanelToggle = document.getElementById('filter_panel_header_toggle_' + panelName); + + if (filterPanel.style.display == 'none') { + filterPanelToggle.innerHTML = '-'; + filterPanel.style.display = ''; + } else { + filterPanelToggle.innerHTML = '+'; + filterPanel.style.display = 'none'; + } +} + function buildFilterPanelItem(filterType, itemString, friendlyItemString) { var filterPanelItem = document.createElement('div'); filterPanelItem.id = 'filter_panel_item_' + itemString; @@ -61,7 +128,7 @@ function buildFilterPanelItem(filterType, itemString, friendlyItemString) { var filterPanelItemCheckBox = document.createElement('div'); var filterPanelItemCheckBoxItem = document.createElement('input'); - filterPanelItemCheckBoxItem.id = 'filter_panel_item_checkbox_' + itemString; + filterPanelItemCheckBoxItem.id = 'filter_panel_item_' + filterType + '_checkbox_' + itemString; filterPanelItemCheckBoxItem.type = 'checkbox'; filterPanelItemCheckBoxItem.className = 'filter_panel_item_checkbox'; filterPanelItemCheckBoxItem.name = 'filter_' + filterType; @@ -92,33 +159,73 @@ function executeFilterDelayed() { function executeFilter() { // build filter lists + var queries = []; + var platforms = ''; var genres = ''; var searchString = document.getElementById('filter_panel_search').value; - var platformFilters = document.getElementsByName('filter_platforms'); - var genreFilters = document.getElementsByName('filter_genres'); + if (searchString.length > 0) { + queries.push('name=' + searchString); + } - for (var i = 0; i < platformFilters.length; i++) { - if (platformFilters[i].checked) { - if (platforms.length > 0) { - platforms += ','; + var minUserRating = 0; + var minUserRatingInput = document.getElementById('filter_panel_userrating_min').value; + if (minUserRatingInput) { + minUserRating = minUserRatingInput; + queries.push('minrating=' + minUserRating); + } + + var maxUserRating = 100; + var maxUserRatingInput = document.getElementById('filter_panel_userrating_max').value; + if (maxUserRatingInput) { + maxUserRating = maxUserRatingInput; + queries.push('maxrating=' + maxUserRating); + } + + queries.push(GetFilterQuery('platform')); + queries.push(GetFilterQuery('genre')); + queries.push(GetFilterQuery('gamemode')); + queries.push(GetFilterQuery('playerperspective')); + queries.push(GetFilterQuery('theme')); + + var queryString = ''; + for (var i = 0; i < queries.length; i++) { + if (queries[i].length > 0) { + if (queryString.length == 0) { + queryString = '?'; + } else { + queryString += '&'; } - platforms += platformFilters[i].getAttribute('filter_id'); + + queryString += queries[i]; } } - for (var i = 0; i < genreFilters.length; i++) { - if (genreFilters[i].checked) { - if (genres.length > 0) { - genres += ','; - } - genres += genreFilters[i].getAttribute('filter_id'); - } - } + console.log('Query string = ' + queryString); - ajaxCall('/api/v1/Games?name=' + searchString + '&platform=' + platforms + '&genre=' + genres, 'GET', function (result) { + ajaxCall('/api/v1/Games' + queryString, 'GET', function (result) { var gameElement = document.getElementById('games_library'); formatGamesPanel(gameElement, result); }); +} + +function GetFilterQuery(filterName) { + var Filters = document.getElementsByName('filter_' + filterName); + var queryString = ''; + + for (var i = 0; i < Filters.length; i++) { + if (Filters[i].checked) { + if (queryString.length > 0) { + queryString += ','; + } + queryString += Filters[i].getAttribute('filter_id'); + } + } + + if (queryString.length > 0) { + queryString = filterName + '=' + queryString; + } + + return queryString; } \ No newline at end of file diff --git a/gaseous-server/wwwroot/styles/style.css b/gaseous-server/wwwroot/styles/style.css index 47997a8..955d0de 100644 --- a/gaseous-server/wwwroot/styles/style.css +++ b/gaseous-server/wwwroot/styles/style.css @@ -13,6 +13,10 @@ src: url('/fonts/Commodore Pixelized v1.2.ttf'); } +h1 { + margin-bottom: unset; +} + h3 { border-bottom-style: solid; /*border-bottom-color: #916b01;*/ @@ -206,7 +210,7 @@ h3 { padding: 10px; } -input[type='text'] { +input[type='text'], input[type='number'] { background-color: #2b2b2b; color: white; padding: 5px; @@ -225,6 +229,15 @@ input[id='filter_panel_search'] { width: 160px; } +input[id='filter_panel_userrating_min'] { + width: 50px; + margin-right: 5px; +} + +input[id='filter_panel_userrating_max'] { + width: 50px; +} + /* width */ ::-webkit-scrollbar { width: 10px; @@ -286,12 +299,20 @@ input[id='filter_panel_search'] { text-align: center; vertical-align: top; margin-bottom: 10px; + border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + border: 1px solid transparent; } .game_tile:hover { cursor: pointer; text-decoration: underline; background-color: #2b2b2b; + border-radius: 10px 10px 10px 10px; + -webkit-border-radius: 10px 10px 10px 10px; + -moz-border-radius: 10px 10px 10px 10px; + border: 1px solid #2b2b2b; } .game_tile_image { @@ -770,4 +791,25 @@ button:disabled { box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44); -webkit-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44); -moz-box-shadow: 5px 5px 19px 0px rgba(0,0,0,0.44); +} + +#gametitle_criticrating { + float: right; +} + +#gametitle_alts { + margin-top: -2px; +} + +#gametitle_criticrating_value { + display: inline-block; + font-family: Commodore64; + font-size: 36px; + text-align: center; + margin-right: 2px; +} + +#gametitle_criticrating_label { + display: inline-block; + text-align: left; } \ No newline at end of file diff --git a/gaseous-tools/Database/MySQL/gaseous-1001.sql b/gaseous-tools/Database/MySQL/gaseous-1001.sql new file mode 100644 index 0000000..421dd99 --- /dev/null +++ b/gaseous-tools/Database/MySQL/gaseous-1001.sql @@ -0,0 +1,65 @@ +DROP TABLE IF EXISTS `GameMode`; +CREATE TABLE `gaseous`.`GameMode` ( + `Id` BIGINT NOT NULL, + `CreatedAt` DATETIME NULL, + `Checksum` VARCHAR(45) NULL, + `Name` VARCHAR(100) NULL, + `Slug` VARCHAR(100) NULL, + `UpdatedAt` DATETIME NULL, + `Url` VARCHAR(255) NULL, + `dateAdded` DATETIME NULL, + `lastUpdated` DATETIME NULL, + PRIMARY KEY (`Id`) +); + +DROP TABLE IF EXISTS `MultiplayerMode`; +CREATE TABLE `MultiplayerMode` ( + `Id` bigint NOT NULL, + `CreatedAt` datetime DEFAULT NULL, + `Checksum` varchar(45) DEFAULT NULL, + `CampaignCoop` boolean DEFAULT NULL, + `DropIn` boolean DEFAULT NULL, + `Game` bigint DEFAULT NULL, + `LanCoop` boolean DEFAULT NULL, + `OfflineCoop` boolean DEFAULT NULL, + `OfflineCoopMax` int DEFAULT NULL, + `OfflineMax` int DEFAULT NULL, + `OnlineCoop` boolean DEFAULT NULL, + `OnlineCoopMax` int DEFAULT NULL, + `OnlineMax` int DEFAULT NULL, + `Platform` bigint DEFAULT NULL, + `SplitScreen` boolean DEFAULT NULL, + `SplitScreenOnline` boolean DEFAULT NULL, + `UpdatedAt` datetime DEFAULT NULL, + `dateAdded` datetime DEFAULT NULL, + `lastUpdated` datetime DEFAULT NULL, + PRIMARY KEY (`Id`) +); + +DROP TABLE IF EXISTS `PlayerPerspective`; +CREATE TABLE `PlayerPerspective` ( + `Id` bigint NOT NULL, + `CreatedAt` datetime DEFAULT NULL, + `Checksum` varchar(45) DEFAULT NULL, + `Name` varchar(100) DEFAULT NULL, + `Slug` varchar(45) DEFAULT NULL, + `UpdatedAt` datetime DEFAULT NULL, + `Url` varchar(255) DEFAULT NULL, + `dateAdded` datetime DEFAULT NULL, + `lastUpdated` datetime DEFAULT NULL, + PRIMARY KEY (`Id`) +); + +DROP TABLE IF EXISTS `Theme`; +CREATE TABLE `Theme` ( + `Id` bigint NOT NULL, + `CreatedAt` datetime DEFAULT NULL, + `Checksum` varchar(45) DEFAULT NULL, + `Name` varchar(100) DEFAULT NULL, + `Slug` varchar(45) DEFAULT NULL, + `UpdatedAt` datetime DEFAULT NULL, + `Url` varchar(255) DEFAULT NULL, + `dateAdded` datetime DEFAULT NULL, + `lastUpdated` datetime DEFAULT NULL, + PRIMARY KEY (`Id`) +); \ No newline at end of file diff --git a/gaseous-tools/gaseous-tools.csproj b/gaseous-tools/gaseous-tools.csproj index 1d5c765..31d6c71 100644 --- a/gaseous-tools/gaseous-tools.csproj +++ b/gaseous-tools/gaseous-tools.csproj @@ -16,6 +16,7 @@ + @@ -23,5 +24,6 @@ +