diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index a5c93aa..9e7c5c6 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -22,6 +22,7 @@ public class ContentController : Controller { private GameDataService gameDataService; private DisplayNamesService displayNamesService; private NeighborhoodService neighborhoodService; + private WorldIdService worldIdService; private Random random = new Random(); private readonly IOptions config; @@ -36,6 +37,7 @@ public class ContentController : Controller { GameDataService gameDataService, DisplayNamesService displayNamesService, NeighborhoodService neighborhoodService, + WorldIdService worldIdService, IOptions config ) { this.ctx = ctx; @@ -48,6 +50,7 @@ public class ContentController : Controller { this.gameDataService = gameDataService; this.displayNamesService = displayNamesService; this.neighborhoodService = neighborhoodService; + this.worldIdService = worldIdService; this.config = config; } @@ -2117,14 +2120,105 @@ public class ContentController : Controller { public IActionResult GetTreasureChest() { // TODO: This is a placeholder return Ok(new TreasureChestData()); + } + + //Oh boy it's the AL code stuff you guys ready for p a i n + + [HttpPost] + [Produces("application/xml")] + [Route("MissionWebService.asmx/GetWorldId")] // used by Math Blaster and WoJS Adventureland + public IActionResult GetWorldId([FromForm] int gameId, [FromForm] string sceneName, [FromForm] string apiKey) + { + var result = worldIdService.GetWorldID(sceneName); + return Ok(result); + } + + [HttpPost] + //[Produces("application/xml")] + [Route("MissionWebService.asmx/GetBadge")] + public IActionResult GetBadge([FromForm] int gameId) + { + if (gameId == 1) return Ok(System.IO.File.ReadAllText("./Resources/missions/badge_wojs_al.xml")); + return Ok(); // if it doesn't work/causes errors then: return Ok(XmlUtil.SerializeXml(new BadgeData())); } [HttpPost] [Produces("application/xml")] - [Route("MissionWebService.asmx/GetWorldId")] // used by Math Blaster - public IActionResult GetWorldId() { - // TODO: This is a placeholder - return Ok(0); + [Route("MissionWebService.asmx/GetMission")] + public IActionResult GetMission([FromForm] int gameId, [FromForm] int type, [FromForm] string apiKey) + { + MissionData mission = missionService.GetMissionDataFromFile(ClientVersion.GetVersion(apiKey), gameId, type); + if (mission != null) return Ok(mission); + else return Ok(new MissionData()); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetUserMission")] + [VikingSession] + public IActionResult GetUserMission(Viking viking, [FromForm] int worldId, [FromForm] string apiKey) + { + //if (ClientVersion.GetVersion(apiKey) <= ClientVersion.WoJS_AdvLand) + //{ + return Ok(missionService.GetUserMissionData(viking, worldId)); + //} + + return Ok(new Schema.UserMissionData()); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetUserMission")] + [VikingSession] + public IActionResult SetUserMission(Viking viking, [FromForm] int worldId, [FromForm] int missionId, [FromForm] int stepId, [FromForm] int taskId, [FromForm] string apiKey) + { + //if (ClientVersion.GetVersion(apiKey) <= ClientVersion.WoJS_AdvLand) + //{ + missionService.SetOrUpdateUserMissionData(viking, worldId, missionId, stepId, taskId); + return Ok(true); // assuming true or false response here + //} + + return Ok(false); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetUserMissionComplete")] + [VikingSession] + public IActionResult SetUserMissionComplete(Viking viking, [FromForm] int worldId, [FromForm] int missionId, [FromForm] string apiKey) + { + //if (ClientVersion.GetVersion(apiKey) <= ClientVersion.WoJS_AdvLand) + //{ + return Ok(missionService.SetUserMissionCompleted(viking, worldId, missionId, true)); + //} + + return Ok(false); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetUserBadgeComplete")] + [VikingSession] + public IActionResult SetUserBadgeComplete(Viking viking, [FromForm] int badgeId) + { + return Ok(missionService.SetUserBadgeComplete(viking, badgeId)); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetUserBadgeComplete")] + [VikingSession] + public IActionResult GetUserBadgeComplete(Viking viking) + { + return Ok(missionService.GetUserBadgesCompleted(viking)); + } + + [HttpPost] + [Produces("application/xml")] + [Route("MissionWebService.asmx/GetStep")] + public IActionResult GetMissionStep([FromForm] int stepId, [FromForm] string apiKey) + { + return Ok(missionService.GetMissionStepFromFile(ClientVersion.GetVersion(apiKey), stepId)); } [HttpPost] diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index cd75567..3a963af 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -3,7 +3,8 @@ using Microsoft.Extensions.Options; using sodoff.Configuration; namespace sodoff.Model; -public class DBContext : DbContext { +public class DBContext : DbContext +{ public DbSet Users { get; set; } = null!; public DbSet Vikings { get; set; } = null!; public DbSet Dragons { get; set; } = null!; @@ -27,28 +28,32 @@ public class DBContext : DbContext { // we had a brief debate on whether it's neighborhoods or neighborheed public DbSet Groups { get; set; } = null!; public DbSet Ratings { get; set; } = null!; - public DbSet RatingRanks { get; set; } = null!; + public DbSet RatingRanks { get; set; } = null!; + public DbSet UserMissionData { get; set; } = null!; + public DbSet UserBadgesCompleted { get; set; } = null!; private readonly IOptions config; - public DBContext(IOptions config) { + public DBContext(IOptions config) + { this.config = config; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - #if USE_POSTGRESQL + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { +#if USE_POSTGRESQL if (config.Value.DbProvider == DbProviders.PostgreSQL) { optionsBuilder.UseNpgsql(config.Value.DbConnection).UseLazyLoadingProxies(); return; } - #endif - #if USE_MYSQL +#endif +#if USE_MYSQL if (config.Value.DbProvider == DbProviders.MySQL) { optionsBuilder.UseMySQL(config.Value.DbConnection).UseLazyLoadingProxies(); return; } - #endif - #if USE_SQLITE +#endif +#if USE_SQLITE if (config.Value.DbProvider == DbProviders.SQLite) { string DbPath; if (String.IsNullOrEmpty(config.Value.DbPath)) { @@ -59,11 +64,12 @@ public class DBContext : DbContext { optionsBuilder.UseSqlite($"Data Source={DbPath}").UseLazyLoadingProxies(); return; } - #endif +#endif throw new Exception($"Unsupported DbProvider {config.Value.DbProvider}"); } - protected override void OnModelCreating(ModelBuilder builder) { + protected override void OnModelCreating(ModelBuilder builder) + { // Sessions builder.Entity().HasOne(s => s.User) .WithMany(e => e.Sessions) diff --git a/src/Model/UserBadgeCompleteData.cs b/src/Model/UserBadgeCompleteData.cs new file mode 100644 index 0000000..efab4c9 --- /dev/null +++ b/src/Model/UserBadgeCompleteData.cs @@ -0,0 +1,11 @@ +namespace sodoff.Model +{ + public class UserBadgeCompleteData + { + public int Id { get; set; } + public int VikingId { get; set; } + public int BadgeId { get; set; } + + public virtual Viking? Viking { get; set; } + } +} diff --git a/src/Model/UserMissionData.cs b/src/Model/UserMissionData.cs new file mode 100644 index 0000000..db3d7fc --- /dev/null +++ b/src/Model/UserMissionData.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace sodoff.Model +{ + public class UserMissionData + { + [Key] + public int Id { get; set; } + public int VikingId { get; set; } + public int WorldId { get; set; } + public int MissionId { get; set; } + public int StepId { get; set; } + public int TaskId { get; set; } + public bool IsCompleted { get; set; } = false; + + public virtual Viking? Viking { get; set; } + } +} diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index 6403745..163e51d 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -5,7 +5,8 @@ using sodoff.Schema; namespace sodoff.Model; [Index(nameof(Uid))] -public class Viking { +public class Viking +{ [Key] public int Id { get; set; } @@ -42,6 +43,8 @@ public class Viking { public virtual ICollection Groups { get; set; } = null!; public virtual ICollection Ratings { get; set; } = null!; public virtual Dragon? SelectedDragon { get; set; } + public virtual ICollection UserMissions { get; set; } = null!; + public virtual ICollection UserBadgesCompleted { get; set; } = null!; public DateTime? CreationDate { get; set; } public DateTime? BirthDate { get; set; } diff --git a/src/Program.cs b/src/Program.cs index 1eca9c4..d50819b 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -30,6 +30,7 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -40,6 +41,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + bool assetServer = builder.Configuration.GetSection("AssetServer").GetValue("Enabled"); string assetIP = builder.Configuration.GetSection("AssetServer").GetValue("ListenIP"); int assetPort = builder.Configuration.GetSection("AssetServer").GetValue("Port"); diff --git a/src/Schema/BadgeData.cs b/src/Schema/BadgeData.cs new file mode 100644 index 0000000..357e153 --- /dev/null +++ b/src/Schema/BadgeData.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "BadgeData", Namespace = "", IsNullable = true)] + [Serializable] + public class BadgeData + { + [XmlElement(ElementName = "Badge")] + public BadgeDataBadge[] Badge; + } +} diff --git a/src/Schema/BadgeDataBadge.cs b/src/Schema/BadgeDataBadge.cs new file mode 100644 index 0000000..46c094a --- /dev/null +++ b/src/Schema/BadgeDataBadge.cs @@ -0,0 +1,39 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "BadgeDataBadge", Namespace = "")] + [Serializable] + public class BadgeDataBadge + { + [XmlElement(ElementName = "BadgeId")] + public int BadgeId; + + [XmlElement(ElementName = "Name")] + public string Name; + + [XmlElement(ElementName = "Description")] + public string Description; + + [XmlElement(ElementName = "Experience")] + public int Experience; + + [XmlElement(ElementName = "Pieces")] + public int Pieces; + + [XmlElement(ElementName = "Mask")] + public string Mask; + + [XmlElement(ElementName = "Color")] + public string Color; + + [XmlElement(ElementName = "Grey")] + public string Grey; + + [XmlElement(ElementName = "PieceDialog", IsNullable = true)] + public BadgeDataBadgePieceDialog PieceDialog; + + [XmlElement(ElementName = "CompleteDialog", IsNullable = true)] + public BadgeDataBadgeCompleteDialog CompleteDialog; + } +} \ No newline at end of file diff --git a/src/Schema/BadgeDataBadgeCompleteDialog.cs b/src/Schema/BadgeDataBadgeCompleteDialog.cs new file mode 100644 index 0000000..590db7e --- /dev/null +++ b/src/Schema/BadgeDataBadgeCompleteDialog.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "BadgeDataBadgeCompleteDialog", Namespace = "")] + [Serializable] + public class BadgeDataBadgeCompleteDialog + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/BadgeDataBadgePieceDialog.cs b/src/Schema/BadgeDataBadgePieceDialog.cs new file mode 100644 index 0000000..8971b3f --- /dev/null +++ b/src/Schema/BadgeDataBadgePieceDialog.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "BadgeDataBadgePieceDialog", Namespace = "")] + [Serializable] + public class BadgeDataBadgePieceDialog + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/MissionData.cs b/src/Schema/MissionData.cs new file mode 100644 index 0000000..2cc1dcb --- /dev/null +++ b/src/Schema/MissionData.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "MissionData", Namespace = "", IsNullable = false)] + [Serializable] + public class MissionData + { + [XmlElement(ElementName = "Mission")] + public MissionDataMission[] Mission; + } +} diff --git a/src/Schema/MissionDataMission.cs b/src/Schema/MissionDataMission.cs new file mode 100644 index 0000000..cd25df2 --- /dev/null +++ b/src/Schema/MissionDataMission.cs @@ -0,0 +1,36 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "MissionDataMission", Namespace = "")] + [Serializable] + public class MissionDataMission + { + [XmlElement(ElementName = "MissionID")] + public int MissionID; + + [XmlElement(ElementName = "Name")] + public string Name; + + [XmlElement(ElementName = "DisplayName", IsNullable = true)] + public string DisplayName; + + [XmlElement(ElementName = "IconName", IsNullable = true)] + public string IconName; + + [XmlElement(ElementName = "Description", IsNullable = true)] + public string Description; + + [XmlElement(ElementName = "Experience")] + public int Experience; + + [XmlElement(ElementName = "RewardDialog", IsNullable = true)] + public MissionDataMissionRewardDialog RewardDialog; + + [XmlElement(ElementName = "UnlockMission")] + public int[] UnlockMission; + + [XmlElement(ElementName = "Step", IsNullable = true)] + public MissionDataMissionStep[] Step; + } +} \ No newline at end of file diff --git a/src/Schema/MissionDataMissionRewardDialog.cs b/src/Schema/MissionDataMissionRewardDialog.cs new file mode 100644 index 0000000..2e127c7 --- /dev/null +++ b/src/Schema/MissionDataMissionRewardDialog.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "MissionDataMissionRewardDialog", Namespace = "")] + [Serializable] + public class MissionDataMissionRewardDialog + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/MissionDataMissionStep.cs b/src/Schema/MissionDataMissionStep.cs new file mode 100644 index 0000000..a1e2dda --- /dev/null +++ b/src/Schema/MissionDataMissionStep.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "MissionDataMissionStep", Namespace = "")] + [Serializable] + public class MissionDataMissionStep + { + [XmlElement(ElementName = "StepID")] + public int StepID; + + [XmlElement(ElementName = "TaskID")] + public int[] TaskID; + } +} \ No newline at end of file diff --git a/src/Schema/Step.cs b/src/Schema/Step.cs new file mode 100644 index 0000000..39aeff8 --- /dev/null +++ b/src/Schema/Step.cs @@ -0,0 +1,36 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "Step", Namespace = "", IsNullable = false)] + [Serializable] + public class Step + { + [XmlElement(ElementName = "StepID")] + public StepStepID StepID; + + [XmlElement(ElementName = "OfferSpeech", IsNullable = true)] + public StepOfferSpeech OfferSpeech; + + [XmlElement(ElementName = "EndSpeech", IsNullable = true)] + public StepEndSpeech EndSpeech; + + [XmlElement(ElementName = "TasksNeeded")] + public int TasksNeeded; + + [XmlElement(ElementName = "Task")] + public StepTask[] Task; + + [XmlElement(ElementName = "Message")] + public StepMessage[] Message; + + [XmlElement(ElementName = "NPCData")] + public StepNPCData[] NPCData; + + [XmlElement(ElementName = "StoreItem")] + public StepStoreItem[] StoreItem; + + [XmlElement(ElementName = "StartPlayerItem")] + public StepStartPlayerItem[] StartPlayerItem; + } +} diff --git a/src/Schema/StepEndSpeech.cs b/src/Schema/StepEndSpeech.cs new file mode 100644 index 0000000..7d5d99d --- /dev/null +++ b/src/Schema/StepEndSpeech.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepEndSpeech", Namespace = "")] + [Serializable] + public class StepEndSpeech + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/StepMessage.cs b/src/Schema/StepMessage.cs new file mode 100644 index 0000000..68c1bf5 --- /dev/null +++ b/src/Schema/StepMessage.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepMessage", Namespace = "")] + [Serializable] + public class StepMessage + { + [XmlElement(ElementName = "Text", IsNullable = true)] + public string Text; + + [XmlElement(ElementName = "ItemID", IsNullable = true)] + public int? ItemID; + + [XmlElement(ElementName = "Scale", IsNullable = true)] + public float? Scale; + } +} \ No newline at end of file diff --git a/src/Schema/StepNPCData.cs b/src/Schema/StepNPCData.cs new file mode 100644 index 0000000..74dcfb4 --- /dev/null +++ b/src/Schema/StepNPCData.cs @@ -0,0 +1,21 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepNPCData", Namespace = "")] + [Serializable] + public class StepNPCData + { + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Marker")] + public string Marker; + + [XmlElement(ElementName = "Scene")] + public string Scene; + + [XmlElement(ElementName = "Animation", IsNullable = true)] + public string Animation; + } +} \ No newline at end of file diff --git a/src/Schema/StepOfferSpeech.cs b/src/Schema/StepOfferSpeech.cs new file mode 100644 index 0000000..f7b005d --- /dev/null +++ b/src/Schema/StepOfferSpeech.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepOfferSpeech", Namespace = "")] + [Serializable] + public class StepOfferSpeech + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/StepStartPlayerItem.cs b/src/Schema/StepStartPlayerItem.cs new file mode 100644 index 0000000..3a51964 --- /dev/null +++ b/src/Schema/StepStartPlayerItem.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepStartPlayerItem", Namespace = "")] + [Serializable] + public class StepStartPlayerItem + { + [XmlElement(ElementName = "ItemID")] + public int ItemID; + + [XmlElement(ElementName = "Quantity")] + public int Quantity; + } +} \ No newline at end of file diff --git a/src/Schema/StepStepID.cs b/src/Schema/StepStepID.cs new file mode 100644 index 0000000..fcd03cb --- /dev/null +++ b/src/Schema/StepStepID.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepStepID", Namespace = "")] + [Serializable] + public class StepStepID + { + [XmlText] + public int Value; + } +} \ No newline at end of file diff --git a/src/Schema/StepStoreItem.cs b/src/Schema/StepStoreItem.cs new file mode 100644 index 0000000..2cd17c3 --- /dev/null +++ b/src/Schema/StepStoreItem.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepStoreItem", Namespace = "")] + [Serializable] + public class StepStoreItem + { + [XmlElement(ElementName = "StoreID")] + public int StoreID; + + [XmlElement(ElementName = "ItemID")] + public int ItemID; + } +} \ No newline at end of file diff --git a/src/Schema/StepTask.cs b/src/Schema/StepTask.cs new file mode 100644 index 0000000..3ddf5a0 --- /dev/null +++ b/src/Schema/StepTask.cs @@ -0,0 +1,52 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTask", Namespace = "")] + [Serializable] + public class StepTask + { + [XmlElement(ElementName = "TaskID")] + public int TaskID; + + // Token: 0x0400043C RID: 1084 + [XmlElement(ElementName = "Type")] + public string Type; + + // Token: 0x0400043D RID: 1085 + [XmlElement(ElementName = "Dialog", IsNullable = true)] + public StepTaskDialog Dialog; + + // Token: 0x0400043E RID: 1086 + [XmlElement(ElementName = "Message")] + public StepTaskMessage[] Message; + + // Token: 0x0400043F RID: 1087 + [XmlElement(ElementName = "SetupGroup", IsNullable = true)] + public string SetupGroup; + + // Token: 0x04000440 RID: 1088 + [XmlElement(ElementName = "SetupScene", IsNullable = true)] + public string SetupScene; + + // Token: 0x04000441 RID: 1089 + [XmlElement(ElementName = "Help")] + public StepTaskHelp[] Help; + + // Token: 0x04000442 RID: 1090 + [XmlElement(ElementName = "RewardPlayerItem")] + public StepTaskRewardPlayerItem[] RewardPlayerItem; + + // Token: 0x04000443 RID: 1091 + [XmlElement(ElementName = "Experience")] + public int Experience; + + // Token: 0x04000444 RID: 1092 + [XmlElement(ElementName = "Time", IsNullable = true)] + public int? Time; + + // Token: 0x04000445 RID: 1093 + [XmlElement(ElementName = "Objective")] + public StepTaskObjective Objective; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskDialog.cs b/src/Schema/StepTaskDialog.cs new file mode 100644 index 0000000..94fa43e --- /dev/null +++ b/src/Schema/StepTaskDialog.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskDialog", Namespace = "")] + [Serializable] + public class StepTaskDialog + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskHelp.cs b/src/Schema/StepTaskHelp.cs new file mode 100644 index 0000000..c07495f --- /dev/null +++ b/src/Schema/StepTaskHelp.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskHelp", Namespace = "")] + [Serializable] + public class StepTaskHelp + { + [XmlElement(ElementName = "FileName")] + public string FileName; + + [XmlElement(ElementName = "NPC")] + public string NPC; + + [XmlElement(ElementName = "Bundle")] + public string Bundle; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskMessage.cs b/src/Schema/StepTaskMessage.cs new file mode 100644 index 0000000..dc07474 --- /dev/null +++ b/src/Schema/StepTaskMessage.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskMessage", Namespace = "")] + [Serializable] + public class StepTaskMessage + { + [XmlElement(ElementName = "Text", IsNullable = true)] + public string Text; + + [XmlElement(ElementName = "ItemID", IsNullable = true)] + public int? ItemID; + + [XmlElement(ElementName = "Scale", IsNullable = true)] + public float? Scale; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskObjective.cs b/src/Schema/StepTaskObjective.cs new file mode 100644 index 0000000..f5c730a --- /dev/null +++ b/src/Schema/StepTaskObjective.cs @@ -0,0 +1,72 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskObjective", Namespace = "")] + [Serializable] + public class StepTaskObjective + { + [XmlElement(ElementName = "Beacon", IsNullable = true)] + public bool? Beacon; + + // Token: 0x0400045B RID: 1115 + [XmlElement(ElementName = "NPC", IsNullable = true)] + public string NPC; + + // Token: 0x0400045C RID: 1116 + [XmlElement(ElementName = "Marker", IsNullable = true)] + public string Marker; + + // Token: 0x0400045D RID: 1117 + [XmlElement(ElementName = "Scene", IsNullable = true)] + public string Scene; + + // Token: 0x0400045E RID: 1118 + [XmlElement(ElementName = "Range", IsNullable = true)] + public float? Range; + + // Token: 0x0400045F RID: 1119 + [XmlElement(ElementName = "Module", IsNullable = true)] + public string Module; + + // Token: 0x04000460 RID: 1120 + [XmlElement(ElementName = "Group", IsNullable = true)] + public string Group; + + // Token: 0x04000461 RID: 1121 + [XmlElement(ElementName = "Object", IsNullable = true)] + public string Object; + + // Token: 0x04000462 RID: 1122 + [XmlElement(ElementName = "StoreID", IsNullable = true)] + public int? StoreID; + + // Token: 0x04000463 RID: 1123 + [XmlElement(ElementName = "ItemID", IsNullable = true)] + public int? ItemID; + + // Token: 0x04000464 RID: 1124 + [XmlElement(ElementName = "ItemName", IsNullable = true)] + public string ItemName; + + // Token: 0x04000465 RID: 1125 + [XmlElement(ElementName = "CategoryID", IsNullable = true)] + public int? CategoryID; + + // Token: 0x04000466 RID: 1126 + [XmlElement(ElementName = "AttributeID")] + public int[] AttributeID; + + // Token: 0x04000467 RID: 1127 + [XmlElement(ElementName = "Quantity", IsNullable = true)] + public int? Quantity; + + // Token: 0x04000468 RID: 1128 + [XmlElement(ElementName = "Photo", IsNullable = true)] + public StepTaskObjectivePhoto Photo; + + // Token: 0x04000469 RID: 1129 + [XmlElement(ElementName = "Creative", IsNullable = true)] + public StepTaskObjectiveCreative Creative; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskObjectiveCreative.cs b/src/Schema/StepTaskObjectiveCreative.cs new file mode 100644 index 0000000..ad8cc49 --- /dev/null +++ b/src/Schema/StepTaskObjectiveCreative.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskObjectiveCreative", Namespace = "")] + [Serializable] + public class StepTaskObjectiveCreative + { + [XmlElement(ElementName = "Type")] + public int Type; + + [XmlElement(ElementName = "AttributeID")] + public int[] AttributeID; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskObjectivePhoto.cs b/src/Schema/StepTaskObjectivePhoto.cs new file mode 100644 index 0000000..e9e8c1f --- /dev/null +++ b/src/Schema/StepTaskObjectivePhoto.cs @@ -0,0 +1,24 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskObjectivePhoto", Namespace = "")] + [Serializable] + public class StepTaskObjectivePhoto + { + [XmlElement(ElementName = "ItemName")] + public string[] ItemName; + + [XmlElement(ElementName = "NPC")] + public string[] NPC; + + [XmlElement(ElementName = "CategoryID")] + public int[] CategoryID; + + [XmlElement(ElementName = "AttributeID")] + public int[] AttributeID; + + [XmlElement(ElementName = "Quantity")] + public int Quantity; + } +} \ No newline at end of file diff --git a/src/Schema/StepTaskRewardPlayerItem.cs b/src/Schema/StepTaskRewardPlayerItem.cs new file mode 100644 index 0000000..59fc2c1 --- /dev/null +++ b/src/Schema/StepTaskRewardPlayerItem.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "StepTaskRewardPlayerItem", Namespace = "")] + [Serializable] + public class StepTaskRewardPlayerItem + { + [XmlElement(ElementName = "ItemID")] + public int ItemID; + + [XmlElement(ElementName = "Quantity")] + public int Quantity; + } +} \ No newline at end of file diff --git a/src/Schema/UserBadge.cs b/src/Schema/UserBadge.cs new file mode 100644 index 0000000..5e54173 --- /dev/null +++ b/src/Schema/UserBadge.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "UserBadge", Namespace = "", IsNullable = false)] + [Serializable] + public class UserBadge + { + [XmlElement(ElementName = "BadgeId")] + public int[] BadgeId; + } +} diff --git a/src/Schema/UserMissionData.cs b/src/Schema/UserMissionData.cs new file mode 100644 index 0000000..5433bbe --- /dev/null +++ b/src/Schema/UserMissionData.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "UserMissionData", Namespace = "")] + [Serializable] + public class UserMissionData + { + [XmlElement(ElementName = "Mission")] + public UserMissionDataMission[] Mission; + + [XmlElement(ElementName = "MissionComplete")] + public int[] MissionComplete; + } +} diff --git a/src/Schema/UserMissionDataMission.cs b/src/Schema/UserMissionDataMission.cs new file mode 100644 index 0000000..52937bb --- /dev/null +++ b/src/Schema/UserMissionDataMission.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "UserMissionDataMission", Namespace = "")] + [Serializable] + public class UserMissionDataMission + { + [XmlElement(ElementName = "MissionId")] + public int MissionId; + + [XmlElement(ElementName = "Step")] + public UserMissionDataMissionStep[] Step; + } +} \ No newline at end of file diff --git a/src/Schema/UserMissionDataMissionStep.cs b/src/Schema/UserMissionDataMissionStep.cs new file mode 100644 index 0000000..94d5eb9 --- /dev/null +++ b/src/Schema/UserMissionDataMissionStep.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema +{ + [XmlRoot(ElementName = "UserMissionDataMissionStep", Namespace = "")] + [Serializable] + public class UserMissionDataMissionStep + { + [XmlElement(ElementName = "StepId")] + public int StepId; + + [XmlElement(ElementName = "TaskId")] + public int[] TaskId; + } +} \ No newline at end of file diff --git a/src/Schema/World.cs b/src/Schema/World.cs new file mode 100644 index 0000000..a357226 --- /dev/null +++ b/src/Schema/World.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +[XmlRoot(ElementName = "World", Namespace = "")] +[Serializable] +public class World +{ + [XmlElement(ElementName = "Scene")] + public string Scene; + + [XmlElement(ElementName = "ID")] + public int ID; +} \ No newline at end of file diff --git a/src/Services/MissionService.cs b/src/Services/MissionService.cs index a69275e..fdb4e65 100644 --- a/src/Services/MissionService.cs +++ b/src/Services/MissionService.cs @@ -54,6 +54,141 @@ public class MissionService { return mission; } + public MissionData GetMissionDataFromFile(uint gameVersion, int gameId, int type) + { + //if (gameVersion <= ClientVersion.WoJS_AdvLand) + //{ + return XmlUtil.DeserializeXml(File.ReadAllText($"./Resources/missions/stepsmissions_{gameId}_{type}.xml")); + //} + + return new MissionData(); + } + + public Step GetMissionStepFromFile(uint gameVersion, int id) + { + //if (gameVersion <= ClientVersion.WoJS_AdvLand) + //{ + return XmlUtil.DeserializeXml(File.ReadAllText($"./Resources/missions/steps/{id}.xml")); + //} + + return new Step(); + } + + public Schema.UserMissionData GetUserMissionData(Viking viking, int worldId) + { + Schema.UserMissionData umdRes = new Schema.UserMissionData(); + + // instantiate schema lists and int lists + List userMissionsCompletedIds = new List(); + List missions = new List(); + List steps = new List(); + List tasks = new List(); + + // get all initiated missions + List vikingUmds = viking.UserMissions.Where(e => e.WorldId == worldId).ToList(); + + foreach (Model.UserMissionData mission in vikingUmds) + { + tasks.Add(mission.TaskId); + steps.Add(new UserMissionDataMissionStep { StepId = mission.StepId, TaskId = tasks.ToArray() }); + missions.Add(new UserMissionDataMission { MissionId = mission.MissionId, Step = steps.ToArray() }); + } + + // add completed mission id's to usermissionscompletedids + List vikingCompletedUmds = vikingUmds.Where(e => e.IsCompleted == true).ToList(); + + foreach (Model.UserMissionData mission in vikingCompletedUmds) + { + userMissionsCompletedIds.Add(mission.MissionId); + } + + // construct response + umdRes.Mission = missions.ToArray(); + umdRes.MissionComplete = userMissionsCompletedIds.ToArray(); + + // return + return umdRes; + } + + public UserBadge GetUserBadgesCompleted(Viking viking) + { + // get badges + List userBadgesCompleted = viking.UserBadgesCompleted.ToList(); + List completedBadgeIds = new List(); + + foreach (var userBadge in userBadgesCompleted) + { + completedBadgeIds.Add(userBadge.BadgeId); + } + + return new UserBadge { BadgeId = completedBadgeIds.ToArray() }; + } + + public Model.UserMissionData SetOrUpdateUserMissionData(Viking viking, int worldId, int missionId, int stepId, int taskId) + { + // find any existing records of this mission + Model.UserMissionData? existingMission = viking.UserMissions.Where(e => e.WorldId == worldId) + .Where(e => e.MissionId == missionId) + .FirstOrDefault(); + + if (existingMission != null) + { + // update taskid and stepid + existingMission.StepId = stepId; + existingMission.TaskId = taskId; + ctx.SaveChanges(); + + return existingMission; + } + + // add mission data to db + + Model.UserMissionData missionData = new Model.UserMissionData() + { + WorldId = worldId, + MissionId = missionId, + StepId = stepId, + TaskId = taskId + }; + + viking.UserMissions.Add(missionData); + ctx.SaveChanges(); + + return missionData; + } + + public bool SetUserMissionCompleted(Viking viking, int worldId, int missionId, bool isCompleted) + { + Model.UserMissionData? mission = viking.UserMissions.Where(e => e.WorldId == worldId) + .Where(e => e.MissionId == missionId) + .FirstOrDefault(); + + if (mission != null) + { + // set mission complete + mission.IsCompleted = isCompleted; + + // add jumpstars for completing the mission + if (isCompleted) achievementService.AddAchievementPoints(viking, AchievementPointTypes.PlayerXP, 25); // hardcoding earning 25 for now + + ctx.SaveChanges(); + return true; + } + + return false; + } + + public bool SetUserBadgeComplete(Viking viking, int gameId) + { + // add completed badge to database + UserBadgeCompleteData userBadgeCompleteData = new() { BadgeId = gameId }; + + viking.UserBadgesCompleted.Add(userBadgeCompleteData); + ctx.SaveChanges(); + + return true; + } + public List UpdateTaskProgress(int missionId, int taskId, int userId, bool completed, string xmlPayload, uint gameVersion) { SetTaskProgressDB(missionId, taskId, userId, completed, xmlPayload); diff --git a/src/Services/WorldIdService.cs b/src/Services/WorldIdService.cs new file mode 100644 index 0000000..f41e85d --- /dev/null +++ b/src/Services/WorldIdService.cs @@ -0,0 +1,29 @@ +using sodoff.Schema; +using sodoff.Util; + +namespace sodoff.Services; + + +public class WorldIdService { + + Dictionary worlds_id = new(); + + public WorldIdService() + { + var worlds = XmlUtil.DeserializeXml(XmlUtil.ReadResourceXmlString("worlds")); + //Console.WriteLine("We are confirming this thing works"); + foreach (var w in worlds) + { + worlds_id[w.Scene] = w.ID; + } + } + + public int GetWorldID(string mapName) + { + //Console.WriteLine(worlds_id[mapName]); + if (worlds_id.ContainsKey(mapName)) + return worlds_id[mapName]; + else + return 0; + } +} \ No newline at end of file diff --git a/src/sodoff.csproj b/src/sodoff.csproj index c457abf..136d82e 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -141,6 +141,9 @@ PreserveNewest + + + PreserveNewest