diff --git a/SMB3Explorer/Enums/PlayerTrait.cs b/SMB3Explorer/Enums/PlayerTrait.cs index 6674ac8..6f2d8cc 100644 --- a/SMB3Explorer/Enums/PlayerTrait.cs +++ b/SMB3Explorer/Enums/PlayerTrait.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel; // ReSharper disable NotAccessedPositionalProperty.Global @@ -9,7 +10,7 @@ public static class PlayerTrait { public record struct DatabaseTraitSubtypePair(int TraitId, int? SubtypeId); - public static Dictionary TraitMap { get; } = new() + private static Dictionary _smb3TraitMap { get; } = new() { {new DatabaseTraitSubtypePair(0, 0), Trait.BatterPowerVsRight}, {new DatabaseTraitSubtypePair(0, 1), Trait.BatterPowerVsLeft}, @@ -32,67 +33,171 @@ public record struct DatabaseTraitSubtypePair(int TraitId, int? SubtypeId); {new DatabaseTraitSubtypePair(8, 7), Trait.BatterBadJumps}, {new DatabaseTraitSubtypePair(9, null), Trait.BatterUtility}, }; + + public static ImmutableDictionary Smb3TraitMap { get; } = + _smb3TraitMap.ToImmutableDictionary(); + + private static Dictionary _smb4TraitMap { get; } = new() + { + {new DatabaseTraitSubtypePair(0, 0), Trait.BatterPowerVsRight}, + {new DatabaseTraitSubtypePair(0, 1), Trait.BatterPowerVsLeft}, + {new DatabaseTraitSubtypePair(1, 0), Trait.BatterContactVsRight}, + {new DatabaseTraitSubtypePair(1, 1), Trait.BatterContactVsLeft}, + {new DatabaseTraitSubtypePair(2, 6), Trait.BatterRbiMan}, + {new DatabaseTraitSubtypePair(2, 7), Trait.BatterRbiZero}, + {new DatabaseTraitSubtypePair(3, 2), Trait.BatterHighPitch}, + {new DatabaseTraitSubtypePair(3, 3), Trait.BatterLowPitch}, + {new DatabaseTraitSubtypePair(3, 4), Trait.BatterInsidePitch}, + {new DatabaseTraitSubtypePair(3, 5), Trait.BatterOutsidePitch}, + {new DatabaseTraitSubtypePair(4, 6), Trait.BatterToughOut}, + {new DatabaseTraitSubtypePair(4, 7), Trait.BatterWhiffer}, + {new DatabaseTraitSubtypePair(5, 12), Trait.PitcherSpecialist}, + {new DatabaseTraitSubtypePair(5, 13), Trait.PitcherReverseSplits}, + {new DatabaseTraitSubtypePair(6, 6), Trait.PitcherComposed}, + {new DatabaseTraitSubtypePair(6, 7), Trait.PitcherWalkProne}, + {new DatabaseTraitSubtypePair(7, 6), Trait.PitcherKCollector}, + {new DatabaseTraitSubtypePair(7, 7), Trait.PitcherKNeglector}, + {new DatabaseTraitSubtypePair(8, 6), Trait.BatterStealer}, + {new DatabaseTraitSubtypePair(8, 7), Trait.BatterBadJumps}, + {new DatabaseTraitSubtypePair(9, 6), Trait.BatterUtility}, + {new DatabaseTraitSubtypePair(10, 8), Trait.BatterFastballHitter}, + {new DatabaseTraitSubtypePair(10, 9), Trait.BatterOffSpeedHitter}, + {new DatabaseTraitSubtypePair(11, 6), Trait.BatterBadBallHitter}, + {new DatabaseTraitSubtypePair(12, 10), Trait.BatterBigHack}, + {new DatabaseTraitSubtypePair(12, 11), Trait.BatterLittleHack}, + {new DatabaseTraitSubtypePair(13, 6), Trait.BatterRallyStarter}, + {new DatabaseTraitSubtypePair(14, 6), Trait.BatterFirstPitchSlayer}, + {new DatabaseTraitSubtypePair(14, 7), Trait.BatterFirstPitchPrayer}, + {new DatabaseTraitSubtypePair(15, 6), Trait.BatterPinchPerfect}, + {new DatabaseTraitSubtypePair(16, 6), Trait.BatterAceExterminator}, + {new DatabaseTraitSubtypePair(17, 6), Trait.BatterMindGamer}, + {new DatabaseTraitSubtypePair(17, 7), Trait.BatterEasyTarget}, + {new DatabaseTraitSubtypePair(18, 6), Trait.PitcherPickOfficer}, + {new DatabaseTraitSubtypePair(18, 7), Trait.PitcherEasyJumps}, + {new DatabaseTraitSubtypePair(19, 6), Trait.PitcherGetsAhead}, + {new DatabaseTraitSubtypePair(19, 7), Trait.PitcherFallsBehind}, + {new DatabaseTraitSubtypePair(20, 6), Trait.PitcherRallyStopper}, + {new DatabaseTraitSubtypePair(20, 7), Trait.PitcherSurrounded}, + {new DatabaseTraitSubtypePair(21, 7), Trait.PitcherCrossedUp}, + {new DatabaseTraitSubtypePair(22, 14), Trait.PitcherElite4SeamFastball}, + {new DatabaseTraitSubtypePair(22, 15), Trait.PitcherElite2SeamFastball}, + {new DatabaseTraitSubtypePair(22, 16), Trait.PitcherEliteCutter}, + {new DatabaseTraitSubtypePair(22, 17), Trait.PitcherEliteCurveball}, + {new DatabaseTraitSubtypePair(22, 18), Trait.PitcherEliteSlider}, + {new DatabaseTraitSubtypePair(22, 19), Trait.PitcherEliteChangeUp}, + {new DatabaseTraitSubtypePair(22, 20), Trait.PitcherEliteScrewball}, + {new DatabaseTraitSubtypePair(22, 21), Trait.PitcherEliteForkball}, + {new DatabaseTraitSubtypePair(23, 6), Trait.PitcherWorkhorse}, + {new DatabaseTraitSubtypePair(24, 22), Trait.PitcherTwoWayOutfielder}, + {new DatabaseTraitSubtypePair(24, 23), Trait.PitcherTwoWayInfielder}, + {new DatabaseTraitSubtypePair(24, 24), Trait.PitcherTwoWayCatcher}, + {new DatabaseTraitSubtypePair(25, 6), Trait.PitcherMetalHead}, + {new DatabaseTraitSubtypePair(26, 6), Trait.BatterSprinter}, + {new DatabaseTraitSubtypePair(26, 7), Trait.BatterSlowPoke}, + {new DatabaseTraitSubtypePair(27, 6), Trait.BatterBaseRounder}, + {new DatabaseTraitSubtypePair(27, 7), Trait.BatterBaseJogger}, + {new DatabaseTraitSubtypePair(28, 6), Trait.BatterDistractor}, + {new DatabaseTraitSubtypePair(29, 6), Trait.MagicHands}, + {new DatabaseTraitSubtypePair(29, 7), Trait.ButterFingers}, + {new DatabaseTraitSubtypePair(30, 7), Trait.WildThrower}, + {new DatabaseTraitSubtypePair(31, 7), Trait.PitcherWildThing}, + {new DatabaseTraitSubtypePair(32, 6), Trait.Clutch}, + {new DatabaseTraitSubtypePair(32, 7), Trait.Choker}, + {new DatabaseTraitSubtypePair(33, 25), Trait.Consistent}, + {new DatabaseTraitSubtypePair(33, 26), Trait.Volatile}, + {new DatabaseTraitSubtypePair(34, 6), Trait.Durable}, + {new DatabaseTraitSubtypePair(34, 7), Trait.InjuryProne}, + {new DatabaseTraitSubtypePair(35, 6), Trait.Stimulated}, + {new DatabaseTraitSubtypePair(36, 6), Trait.BatterCannonArm}, + {new DatabaseTraitSubtypePair(36, 7), Trait.BatterNoodleArm}, + {new DatabaseTraitSubtypePair(37, 6), Trait.BatterDiveWizard}, + {new DatabaseTraitSubtypePair(38, 6), Trait.BatterSignStealer}, + {new DatabaseTraitSubtypePair(39, 7), Trait.PitcherMeltdown}, + {new DatabaseTraitSubtypePair(40, 6), Trait.BatterBunter}, + }; + + public static ImmutableDictionary Smb4TraitMap { get; } = + _smb4TraitMap.ToImmutableDictionary(); } public enum Trait { - [Description("POW vs RHP")] - BatterPowerVsRight, - - [Description("POW vs LHP")] - BatterPowerVsLeft, - - [Description("CON vs RHP")] - BatterContactVsRight, - - [Description("CON vs LHP")] - BatterContactVsLeft, - - [Description("RBI Man")] - BatterRbiMan, - - [Description("RBI Dud")] - BatterRbiDud, - - [Description("High Pitch")] - BatterHighPitch, - - [Description("Low Pitch")] - BatterLowPitch, - - [Description("Inside Pitch")] - BatterInsidePitch, - - [Description("Outside Pitch")] - BatterOutsidePitch, - - [Description("Tough Out")] - BatterToughOut, - - [Description("Whiffer")] - BatterWhiffer, - - [Description("Stealer")] - BatterStealer, - - [Description("Bad Jumps")] - BatterBadJumps, - - [Description("Utility")] - BatterUtility, - - [Description("Composed")] - PitcherComposed, - - [Description("BB Prone")] - PitcherWalkProne, - - [Description("Specialist")] - PitcherSpecialist, - - [Description("K Man")] - PitcherStrikeoutMan, - - [Description("K Dud")] - PitcherStrikeoutDud, + [Description("POW vs RHP")] BatterPowerVsRight, + [Description("POW vs LHP")] BatterPowerVsLeft, + [Description("CON vs RHP")] BatterContactVsRight, + [Description("CON vs LHP")] BatterContactVsLeft, + [Description("RBI Man")] BatterRbiMan, + [Description("RBI Dud")] BatterRbiDud, + [Description("High Pitch")] BatterHighPitch, + [Description("Low Pitch")] BatterLowPitch, + [Description("Inside Pitch")] BatterInsidePitch, + [Description("Outside Pitch")] BatterOutsidePitch, + [Description("Tough Out")] BatterToughOut, + [Description("Whiffer")] BatterWhiffer, + [Description("Stealer")] BatterStealer, + [Description("Bad Jumps")] BatterBadJumps, + [Description("Utility")] BatterUtility, + [Description("Composed")] PitcherComposed, + [Description("BB Prone")] PitcherWalkProne, + [Description("Specialist")] PitcherSpecialist, + [Description("K Man")] PitcherStrikeoutMan, + [Description("K Dud")] PitcherStrikeoutDud, + [Description("Big Hack")] BatterBigHack, + [Description("Magic Hands")] MagicHands, + [Description("Little Hack")] BatterLittleHack, + [Description("Elite 4F")] PitcherElite4SeamFastball, + [Description("K Collector")] PitcherKCollector, + [Description("Falls Behind")] PitcherFallsBehind, + [Description("Mind Gamer")] BatterMindGamer, + [Description("Elite CH")] PitcherEliteChangeUp, + [Description("Meltdown")] PitcherMeltdown, + [Description("Gets Ahead")] PitcherGetsAhead, + [Description("K Neglector")] PitcherKNeglector, + [Description("Choker")] Choker, + [Description("Consistent")] Consistent, + [Description("RBI Zero")] BatterRbiZero, + [Description("First Pitch Prayer")] BatterFirstPitchPrayer, + [Description("First Pitch Slayer")] BatterFirstPitchSlayer, + [Description("Sprinter")] BatterSprinter, + [Description("Pick Officer")] PitcherPickOfficer, + [Description("Fastball Hitter")] BatterFastballHitter, + [Description("Workhorse")] PitcherWorkhorse, + [Description("Clutch")] Clutch, + [Description("Elite 2F")] PitcherElite2SeamFastball, + [Description("Crossed Up")] PitcherCrossedUp, + [Description("Volatile")] Volatile, + [Description("Rally Stopper")] PitcherRallyStopper, + [Description("Butter Fingers")] ButterFingers, + [Description("Off-speed Hitter")] BatterOffSpeedHitter, + [Description("Ace Exterminator")] BatterAceExterminator, + [Description("Metal Head")] PitcherMetalHead, + [Description("Stimulated")] Stimulated, + [Description("Reverse Splits")] PitcherReverseSplits, + [Description("Rally Starter")] BatterRallyStarter, + [Description("Pinch Perfect")] BatterPinchPerfect, + [Description("Base Jogger")] BatterBaseJogger, + [Description("Cannon Arm")] BatterCannonArm, + [Description("Easy Target")] BatterEasyTarget, + [Description("Elite CB")] PitcherEliteCurveball, + [Description("Surrounded")] PitcherSurrounded, + [Description("Easy Jumps")] PitcherEasyJumps, + [Description("Slow Poke")] BatterSlowPoke, + [Description("Wild Thrower")] WildThrower, + [Description("Sign Stealer")] BatterSignStealer, + [Description("Noodle Arm")] BatterNoodleArm, + [Description("Elite CF")] PitcherEliteCutter, + [Description("Wild Thing")] PitcherWildThing, + [Description("Elite SL")] PitcherEliteSlider, + [Description("Dive Wizard")] BatterDiveWizard, + [Description("Injury Prone")] InjuryProne, + [Description("Distractor")] BatterDistractor, + [Description("Durable")] Durable, + [Description("Bunter")] BatterBunter, + [Description("Base Rounder")] BatterBaseRounder, + [Description("Elite FK")] PitcherEliteForkball, + [Description("Elite SB")] PitcherEliteScrewball, + [Description("Two Way (IF)")] PitcherTwoWayInfielder, + [Description("Two Way (OF)")] PitcherTwoWayOutfielder, + [Description("Two Way (C)")] PitcherTwoWayCatcher, + [Description("Bad Ball Hitter")] BatterBadBallHitter } \ No newline at end of file diff --git a/SMB3Explorer/Models/Exports/SeasonPlayer.cs b/SMB3Explorer/Models/Exports/SeasonPlayer.cs index e5f418a..1b28a16 100644 --- a/SMB3Explorer/Models/Exports/SeasonPlayer.cs +++ b/SMB3Explorer/Models/Exports/SeasonPlayer.cs @@ -110,4 +110,7 @@ public Trait[] Traits [Name("Trait 2"), Index(19)] public string? Trait2 { get; set; } + + [Name("Chemistry"), Index(20)] + public string? Chemistry { get; set; } } \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/MostRecentSeasonPlayers.sql b/SMB3Explorer/Resources/Sql/MostRecentSeasonPlayersSmb3.sql similarity index 100% rename from SMB3Explorer/Resources/Sql/MostRecentSeasonPlayers.sql rename to SMB3Explorer/Resources/Sql/MostRecentSeasonPlayersSmb3.sql diff --git a/SMB3Explorer/Resources/Sql/MostRecentSeasonPlayersSmb4.sql b/SMB3Explorer/Resources/Sql/MostRecentSeasonPlayersSmb4.sql new file mode 100644 index 0000000..3b0641f --- /dev/null +++ b/SMB3Explorer/Resources/Sql/MostRecentSeasonPlayersSmb4.sql @@ -0,0 +1,88 @@ +WITH teams AS + (SELECT ttli.GUID AS teamGUID, tt.teamName + FROM t_team_local_ids ttli + JOIN t_teams tt ON ttli.GUID = tt.GUID), + mostRecentSeason AS (SELECT id AS seasonID, + RANK() OVER (ORDER BY id) AS seasonNum + FROM t_seasons + JOIN t_leagues ON t_seasons.historicalLeagueGUID = t_leagues.GUID + JOIN t_franchise tf ON t_leagues.GUID = tf.leagueGUID + WHERE t_leagues.GUID = CAST(@leagueId AS BLOB) + ORDER BY ID DESC + LIMIT 1) +SELECT vbpi.baseballPlayerGUID, + tsea.ID AS seasonId, + s.seasonNum, + CASE + WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[firstName] + ELSE vbpi.[firstName] END AS firstName, + CASE + WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[lastName] + ELSE vbpi.[lastName] END AS lastName, + CASE + WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[primaryPos] + ELSE vbpi.[primaryPosition] END AS primaryPosition, + CASE + WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[pitcherRole] + ELSE vbpi.[pitcherRole] END AS pitcherRole, + CAST(secondaryPosition.optionValue AS INTEGER) AS secondaryPosition, + currentTeam.teamName AS currentTeam, + previousTeam.teamName AS previousTeam, + tbp.power, + tbp.contact, + tbp.speed, + tbp.fielding, + tbp.arm, + tbp.velocity, + tbp.junk, + tbp.accuracy, + tbp.age, + salary.salary * 200 AS salaryDollars, + CASE + WHEN COUNT(tbpt.trait) = 0 THEN NULL + ELSE json_group_array(json_object('traitId', tbpt.trait, 'subtypeId', tbpt.subType)) + END AS traits, + CASE + WHEN chemistry.optionValue = 0 + THEN 'Competitive' + WHEN chemistry.optionValue = 1 + THEN 'Spirited' + WHEN chemistry.optionValue = 2 + THEN 'Disciplined' + WHEN chemistry.optionValue = 3 + THEN 'Scholarly' + WHEN chemistry.optionValue = 4 + THEN 'Crafty' + ELSE 'Unknown' + END AS chemistryType + +FROM [v_baseball_player_info] vbpi + LEFT JOIN t_baseball_player_local_ids tbpli ON vbpi.baseballPlayerGUID = tbpli.GUID + LEFT JOIN t_stats_players tsp ON tbpli.localID = tsp.baseballPlayerLocalID + LEFT JOIN t_stats ts ON tsp.statsPlayerID = ts.statsPlayerID + LEFT JOIN t_season_stats tss ON ts.aggregatorID = tss.aggregatorID + JOIN t_baseball_players tbp ON tbpli.GUID = tbp.GUID + LEFT JOIN t_baseball_player_traits tbpt ON tbpli.localID = tbpt.baseballPlayerLocalID + + JOIN t_seasons tsea ON tss.seasonID = tsea.ID + JOIN mostRecentSeason s ON tsea.ID = s.seasonID + JOIN t_league_local_ids tlli ON tsp.leagueLocalID = tlli.localID + JOIN t_leagues tl ON tlli.GUID = tl.GUID + + JOIN t_salary salary ON vbpi.baseballPlayerGUID = salary.baseballPlayerGUID + + LEFT JOIN t_baseball_player_options secondaryPosition + ON tbpli.localID = secondaryPosition.baseballPlayerLocalID AND secondaryPosition.optionKey = 55 + + LEFT JOIN t_baseball_player_options chemistry + ON tbpli.localID = chemistry.baseballPlayerLocalID AND chemistry.optionKey = 107 + + LEFT JOIN [t_team_local_ids] tt1 ON ts.[currentTeamLocalID] = tt1.[localID] + LEFT JOIN [t_team_local_ids] tt2 + ON ts.[previousRecentlyPlayedTeamLocalID] = tt2.[localID] + LEFT JOIN teams currentTeam ON tt1.GUID = currentTeam.teamGUID + LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID + +WHERE tl.GUID = CAST(@leagueId AS BLOB) +GROUP BY vbpi.baseballPlayerGUID, currentTeam, salaryDollars +ORDER BY currentTeam IS NULL, currentTeam, salaryDollars DESC \ No newline at end of file diff --git a/SMB3Explorer/SMB3Explorer.csproj b/SMB3Explorer/SMB3Explorer.csproj index c8c74f1..53e8f6f 100644 --- a/SMB3Explorer/SMB3Explorer.csproj +++ b/SMB3Explorer/SMB3Explorer.csproj @@ -48,10 +48,6 @@ - - - - @@ -88,7 +84,6 @@ - @@ -99,6 +94,10 @@ + + + + diff --git a/SMB3Explorer/Services/DataService/DataServiceInit.cs b/SMB3Explorer/Services/DataService/DataServiceInit.cs index 3fca04d..c4cada4 100644 --- a/SMB3Explorer/Services/DataService/DataServiceInit.cs +++ b/SMB3Explorer/Services/DataService/DataServiceInit.cs @@ -102,6 +102,8 @@ public async Task, Error>> EstablishDbCo Log.Error("Invalid save file, missing expected tables"); return new Error("Invalid save file, missing expected tables"); } + + if (_applicationContext.MostRecentSelectedSaveFilePath is null) return new List(); List leagues = new(); var command2 = Connection.CreateCommand(); diff --git a/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs b/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs index 5b84b8b..49cc1eb 100644 --- a/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs +++ b/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs @@ -149,7 +149,13 @@ public async IAsyncEnumerable GetMostRecentSeasonPlayers() { var command = Connection!.CreateCommand(); - var commandText = SqlRunner.GetSqlCommand(SqlFile.MostRecentSeasonPlayers); + var commandText = _applicationContext.SelectedGame switch + { + SelectedGame.Smb3 => SqlRunner.GetSqlCommand(SqlFile.MostRecentSeasonPlayersSmb3), + SelectedGame.Smb4 => SqlRunner.GetSqlCommand(SqlFile.MostRecentSeasonPlayersSmb4), + _ => throw new ArgumentOutOfRangeException() + }; + command.CommandText = commandText; command.Parameters.Add(new SqliteParameter("@leagueId", SqliteType.Blob) @@ -188,12 +194,25 @@ public async IAsyncEnumerable GetMostRecentSeasonPlayers() var traitsSerialized = reader.IsDBNull(20) ? null : reader.GetString(20); if (!string.IsNullOrEmpty(traitsSerialized)) { - var traits = JsonConvert - .DeserializeObject(traitsSerialized); + var traits = + JsonConvert.DeserializeObject(traitsSerialized) ?? Array.Empty(); + + seasonPlayer.Traits = _applicationContext.SelectedGame switch + { + SelectedGame.Smb3 => traits + .Select(x => PlayerTrait.Smb3TraitMap[x]) + .ToArray(), + SelectedGame.Smb4 => traits + .Select(x => PlayerTrait.Smb4TraitMap[x]) + .ToArray(), + _ => throw new ArgumentException() + }; + } - seasonPlayer.Traits = (traits ?? Array.Empty()) - .Select(_ => PlayerTrait.TraitMap[_]) - .ToArray(); + if (_applicationContext.SelectedGame is SelectedGame.Smb4) + { + var chemistry = reader.GetString(21); + seasonPlayer.Chemistry = chemistry; } yield return seasonPlayer; diff --git a/SMB3Explorer/Utils/SqlRunner.cs b/SMB3Explorer/Utils/SqlRunner.cs index 6317957..43db814 100644 --- a/SMB3Explorer/Utils/SqlRunner.cs +++ b/SMB3Explorer/Utils/SqlRunner.cs @@ -63,8 +63,11 @@ public enum SqlFile [Description("TopPerformersRookiesBatting.sql")] TopPerformersRookiesBatting, - [Description("MostRecentSeasonPlayers.sql")] - MostRecentSeasonPlayers, + [Description("MostRecentSeasonPlayersSmb3.sql")] + MostRecentSeasonPlayersSmb3, + + [Description("MostRecentSeasonPlayersSmb4.sql")] + MostRecentSeasonPlayersSmb4, [Description("MostRecentSeasonTeams.sql")] MostRecentSeasonTeams,