From 27e5e0064c175a30c90565fc6e3c89548dbdb17e Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:42:24 +0300 Subject: [PATCH] feat: Enhance API endpoints with new methods, improved response structures, and added Photon access token endpoint --- .../CompatibilityFeatureController.cs | 36 ++++++--- .../ExternalFriendInviteController.cs | 2 + .../InfluencerPartnerProgramController.cs | 18 +++-- .../API/Keepsakes/KeepsakesController.cs | 60 ++++++++++++--- .../ProgressionEventsController.cs | 60 ++++++++++++--- .../API/QuickPlay/QuickPlayController.cs | 22 +++++- .../RoomConsumablesController.cs | 75 ++++++++++++++++--- .../API/Rooms/V2/RoomsController.cs | 63 +++++++++++----- .../Commerce/PurchaseCampaignController.cs | 13 ++++ .../Controllers/Match/MatchController.cs | 22 ++++++ 10 files changed, 304 insertions(+), 67 deletions(-) create mode 100644 DorkNet.Server/Controllers/Commerce/PurchaseCampaignController.cs diff --git a/DorkNet.Server/Controllers/API/Compatibility/CompatibilityFeatureController.cs b/DorkNet.Server/Controllers/API/Compatibility/CompatibilityFeatureController.cs index 330320f..eac001d 100644 --- a/DorkNet.Server/Controllers/API/Compatibility/CompatibilityFeatureController.cs +++ b/DorkNet.Server/Controllers/API/Compatibility/CompatibilityFeatureController.cs @@ -60,16 +60,34 @@ public class CompatibilityFeatureController(DorkNetDbContext db) : ControllerBas .ExecuteDeleteAsync(); } - // 2020.12 deserializer for this response expects `subscription` to be a - // nested OBJECT (Subscription DTO with subscriptionId/recNetPlayerId/... - // fields), NOT a boolean. Sending a bool throws InvalidCastException - // on the client ("Unable to cast object of type 'Boolean' to type - // 'Dictionary`2'"). Send null when there's no active subscription — - // the client's generic-cast helper returns default(T) which is fine. - return Ok(new + var active = targetId == pid || await db.Subscriptions.AnyAsync(s => + s.SubscriberPlayerId == pid && s.TargetPlayerId == targetId); + var now = DateTime.UtcNow; + var subscriptionId = unchecked((pid * 397L) ^ targetId); + var subscription = new Dictionary { - subscription = (object?)null, - platformAccountSubscribedPlayerId = targetId, + ["subscriptionId"] = subscriptionId, + ["recNetPlayerId"] = pid, + ["platformAccountSubscribedPlayerId"] = targetId, + ["isActive"] = active, + ["startedAt"] = now, + ["currentPeriodEnd"] = active ? now.AddYears(10) : now, + ["renewalDate"] = active ? now.AddYears(10) : now, + ["SubscriptionId"] = subscriptionId, + ["RecNetPlayerId"] = pid, + ["PlatformAccountSubscribedPlayerId"] = targetId, + ["IsActive"] = active, + ["StartedAt"] = now, + ["CurrentPeriodEnd"] = active ? now.AddYears(10) : now, + ["RenewalDate"] = active ? now.AddYears(10) : now, + }; + + return Ok(new Dictionary + { + ["subscription"] = subscription, + ["platformAccountSubscribedPlayerId"] = targetId, + ["Subscription"] = subscription, + ["PlatformAccountSubscribedPlayerId"] = targetId, }); } diff --git a/DorkNet.Server/Controllers/API/ExternalFriendInvite/ExternalFriendInviteController.cs b/DorkNet.Server/Controllers/API/ExternalFriendInvite/ExternalFriendInviteController.cs index 30aa4e0..a43272c 100644 --- a/DorkNet.Server/Controllers/API/ExternalFriendInvite/ExternalFriendInviteController.cs +++ b/DorkNet.Server/Controllers/API/ExternalFriendInvite/ExternalFriendInviteController.cs @@ -44,6 +44,7 @@ public class ExternalFriendInviteController(DorkNetDbContext db) : ControllerBas } [HttpGet("api/externalfriendinvite/v1/getplatformreferrers")] + [HttpPost("api/externalfriendinvite/v1/getplatformreferrers")] public async Task GetPlatformReferrers() { var rows = await db.PlayerSettings @@ -54,6 +55,7 @@ public class ExternalFriendInviteController(DorkNetDbContext db) : ControllerBas } [HttpGet("api/externalfriendinvite/v1/gettextmessagereferrers")] + [HttpPost("api/externalfriendinvite/v1/gettextmessagereferrers")] public async Task GetTextMessageReferrers() { var rows = await db.PlayerSettings diff --git a/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs b/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs index 0ef329e..e596826 100644 --- a/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs +++ b/DorkNet.Server/Controllers/API/InfluencerPartnerProgram/InfluencerPartnerProgramController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using DorkNet.Models.Auth; using DorkNet.Server.Auth; using DorkNet.Server.Data; using DorkNet.Server.Data.Entities; @@ -25,7 +26,14 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle .Where(p => creatorIds.Contains(p.Id)) .OrderBy(p => p.Username) .ToListAsync(); - return Ok(players.Select(ToInfluencerWire)); + var influencers = players.Select(ToInfluencerWire).ToList(); + return Ok(new Dictionary + { + ["Influencers"] = influencers, + ["influencers"] = influencers, + ["Accounts"] = influencers, + ["accounts"] = influencers, + }); } [HttpGet("api/influencerpartnerprogram/influencer")] @@ -92,18 +100,16 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle return Ok(new { Success = true }); } - private static object ToInfluencerWire(PlayerEntity player) => new + private static RecNetAccount ToInfluencerWire(PlayerEntity player) => new() { AccountId = (int)player.Id, RawUsername = player.Username, - player.Username, + Username = player.Username, DisplayName = player.DisplayName ?? player.Username, ProfileImage = player.ProfileImageName ?? string.Empty, TreatAsJunior = false, HasBirthday = true, Platforms = 1, - IsInfluencer = true, - SupportedInfluencerId = (int?)null, - LocalSupportedInfluencerId = (int?)null, + CreatedAt = player.CreatedAt == default ? DateTime.UtcNow : player.CreatedAt, }; } diff --git a/DorkNet.Server/Controllers/API/Keepsakes/KeepsakesController.cs b/DorkNet.Server/Controllers/API/Keepsakes/KeepsakesController.cs index 0374404..026c75a 100644 --- a/DorkNet.Server/Controllers/API/Keepsakes/KeepsakesController.cs +++ b/DorkNet.Server/Controllers/API/Keepsakes/KeepsakesController.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Security.Cryptography; +using System.Text; using System.Text.Json; using DorkNet.Server.Auth; using DorkNet.Server.Data; @@ -29,12 +31,20 @@ public class KeepsakesController(DorkNetDbContext db, DomainConfig domain) : Con [HttpGet("categories")] [AllowAnonymous] - public IActionResult Categories() => Ok(new[] + public IActionResult Categories() { - new { Category = "account", DisplayName = "Account" }, - new { Category = "event", DisplayName = "Events" }, - new { Category = "room", DisplayName = "Rooms" }, - }); + var results = new[] + { + new { KeepsakeCategoryId = 0, VisualId = "account", LimitPerRoom = 0, XpValue = 0, IconOutlineImageName = string.Empty, IconFilledImageName = string.Empty }, + new { KeepsakeCategoryId = 1, VisualId = "event", LimitPerRoom = 0, XpValue = 0, IconOutlineImageName = string.Empty, IconFilledImageName = string.Empty }, + new { KeepsakeCategoryId = 2, VisualId = "room", LimitPerRoom = 64, XpValue = 0, IconOutlineImageName = string.Empty, IconFilledImageName = string.Empty }, + }; + return Ok(new + { + Results = results, + TotalResults = results.Length, + }); + } [HttpGet("events")] public async Task Events() @@ -62,16 +72,22 @@ public class KeepsakesController(DorkNetDbContext db, DomainConfig domain) : Con || EF.Functions.Like(k.EventKey, $"room/{roomIdText}/%"))) .OrderByDescending(k => k.EarnedAt) .ToListAsync(); - return Ok(rows.Select(ToWire)); + var instances = rows.Select(row => ToRoomInstanceWire(row, roomId)).ToList(); + return Ok(new + { + Instances = instances, + CollectionRecords = Array.Empty(), + KeepsakeProgressionEventIds = Array.Empty(), + }); } [HttpGet("globalconfig")] [AllowAnonymous] public IActionResult GlobalConfig() => Ok(new { - Enabled = true, - Categories = new[] { "account", "event", "room" }, - CdnBaseUrl = $"https://{domain.Sub("cdn")}/", + KeepsakeFeatureEnabled = true, + KeepsakeRoomLimit = 64, + SocialXpBoostEnabled = false, }); [HttpPost] @@ -162,6 +178,32 @@ public class KeepsakesController(DorkNetDbContext db, DomainConfig domain) : Con row.EarnedAt, }; + private static object ToRoomInstanceWire(KeepsakeEntity row, long roomId) + { + var placedByAccountId = row.PlayerId is > 0 and <= int.MaxValue + ? (int)row.PlayerId + : 0; + return new + { + KeepsakeInstanceId = StableKeepsakeInstanceId(row.Id).ToString("D"), + KeepsakeCategoryConfigId = CategoryId(row.Category), + PlacedByAccountId = placedByAccountId, + RoomId = roomId, + SubRoomId = (long?)null, + }; + } + + private static int CategoryId(string? category) => + string.Equals(category, "event", StringComparison.OrdinalIgnoreCase) ? 1 : + string.Equals(category, "room", StringComparison.OrdinalIgnoreCase) ? 2 : + 0; + + private static Guid StableKeepsakeInstanceId(long id) + { + var hash = MD5.HashData(Encoding.UTF8.GetBytes($"keepsakeInstance:{id}")); + return new Guid(hash); + } + private static string Trim(string? value, int max) { var s = (value ?? string.Empty).Trim(); diff --git a/DorkNet.Server/Controllers/API/ProgressionEvents/ProgressionEventsController.cs b/DorkNet.Server/Controllers/API/ProgressionEvents/ProgressionEventsController.cs index df3d2c6..ccac2e9 100644 --- a/DorkNet.Server/Controllers/API/ProgressionEvents/ProgressionEventsController.cs +++ b/DorkNet.Server/Controllers/API/ProgressionEvents/ProgressionEventsController.cs @@ -3,11 +3,12 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using DorkNet.Server.Auth; using DorkNet.Server.Data; +using DorkNet.Server.Services; namespace DorkNet.Server.Controllers.API.ProgressionEvents; [ApiController] -public class ProgressionEventsController(DorkNetDbContext db) : ControllerBase +public class ProgressionEventsController(DorkNetDbContext db, ServerSettingsService serverSettings) : ControllerBase { [HttpGet("api/progressionEvents")] [Authorize] @@ -28,19 +29,60 @@ public class ProgressionEventsController(DorkNetDbContext db) : ControllerBase return Ok(rows); } - [HttpGet("api/progressionEvents/active")] + [HttpGet("api/progressionEvents/event/{eventId:long}")] [AllowAnonymous] - public IActionResult Active() + public async Task Event(long eventId) { - var start = DateTime.UtcNow.Date.AddDays(-(int)DateTime.UtcNow.DayOfWeek); - var end = start.AddDays(7); + var activeId = CurrentProgressionEventId(); + if (eventId != activeId) + return NotFound(); + + var weekly = await serverSettings.GetWeeklyChallengesAsync(); + var (start, end) = CurrentWeekWindow(); return Ok(new { - EventKey = $"weekly:{start:yyyyMMdd}", + ProgressionEventId = activeId, Name = "Weekly Progression", - StartAt = start, - EndAt = end, - Active = true, + Rewards = new[] + { + new + { + ProgressionEventRewardId = activeId * 1000L, + GiftDropId = weekly.Reward.GiftDropId != 0 ? weekly.Reward.GiftDropId : activeId, + ImageName = string.Empty, + Xp = weekly.Reward.Xp, + RewardIndex = 0, + IsBonus = false, + }, + }, + KeepsakeRoomLists = Array.Empty(), + StartTime = start, + EndTime = end, + CollectionEndTime = end, + UsesBoost = false, + BoostDailyGameplayMinutesLimit = 0, + BoostXpMultiplier = 1.0, + PurchasableXpBoostId = (Guid?)null, + ActiveExperiment = string.Empty, + ChallengesIconImageName = string.Empty, + RewardsPipImageName = string.Empty, + EventInfoImageName = string.Empty, }); } + + [HttpGet("api/progressionEvents/active")] + [AllowAnonymous] + public IActionResult Active() => Ok(CurrentProgressionEventId()); + + private static long CurrentProgressionEventId() + { + var (start, _) = CurrentWeekWindow(); + return long.Parse(start.ToString("yyyyMMdd")); + } + + private static (DateTime Start, DateTime End) CurrentWeekWindow() + { + var start = DateTime.UtcNow.Date.AddDays(-(int)DateTime.UtcNow.DayOfWeek); + return (start, start.AddDays(7)); + } } diff --git a/DorkNet.Server/Controllers/API/QuickPlay/QuickPlayController.cs b/DorkNet.Server/Controllers/API/QuickPlay/QuickPlayController.cs index c8fff6d..ccbef31 100644 --- a/DorkNet.Server/Controllers/API/QuickPlay/QuickPlayController.cs +++ b/DorkNet.Server/Controllers/API/QuickPlay/QuickPlayController.cs @@ -25,15 +25,29 @@ public class QuickPlayController(DorkNetDbContext db) : ControllerBase /// immediately teleports — that's WHY users were randomly /// spawning in Paddleball etc. /// - /// Correct behaviour: return empty {} unless we actually have a - /// queued match for the caller. The /set endpoint is what - /// queues; getandclear is the consume. + /// Correct behaviour: return the full no-target launch DTO unless + /// we actually have a queued match for the caller. The /set endpoint + /// is what queues; getandclear is the consume. /// /// We don't persist queue state on a single-region private /// server (no real matchmaking pool), so always return empty. [HttpGet("api/quickPlay/v1/getandclear")] [HttpGet("api/quickPlay/v2/getandclear")] - public IActionResult GetAndClear() => Ok(new { }); + public IActionResult GetAndClear() => Ok(QuickPlayLaunchTarget.Empty); + + private sealed class QuickPlayLaunchTarget + { + public static readonly QuickPlayLaunchTarget Empty = new(); + + public bool OKCGKFJELAC { get; init; } + public string INMKAFBAOPC { get; init; } = string.Empty; + public int? FIOPJIIOCGA { get; init; } + public string ICKOEFDNOPM { get; init; } = string.Empty; + public int? KLDCJBLLDKN { get; init; } + public bool OFBMKDAONNE { get; init; } + public object? FMKHKNCEBCN { get; init; } + public long? EEFNKAFLPLG { get; init; } + } public sealed class SetQuickPlayRequest { diff --git a/DorkNet.Server/Controllers/API/RoomConsumables/RoomConsumablesController.cs b/DorkNet.Server/Controllers/API/RoomConsumables/RoomConsumablesController.cs index 9557056..bcefb8f 100644 --- a/DorkNet.Server/Controllers/API/RoomConsumables/RoomConsumablesController.cs +++ b/DorkNet.Server/Controllers/API/RoomConsumables/RoomConsumablesController.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Security.Cryptography; +using System.Text; using DorkNet.Server.Auth; using DorkNet.Server.Data; using DorkNet.Server.Data.Entities; @@ -13,8 +15,9 @@ public class RoomConsumablesController(DorkNetDbContext db, LevelService level) { [HttpGet("api/roomconsumables")] [HttpGet("api/roomconsumables/v1/roomConsumable")] + [HttpGet("api/roomconsumables/v1/roomConsumable/room/{roomId:long}")] [AllowAnonymous] - public async Task List([FromQuery] long? id = null) + public async Task List([FromRoute] long? roomId = null, [FromQuery] long? id = null) { var query = db.StoreItems .Where(i => i.IsActive && i.Category.ToLower() == "consumable"); @@ -27,6 +30,24 @@ public class RoomConsumablesController(DorkNetDbContext db, LevelService level) return Ok(rows.Select(ToWire)); } + [HttpGet("api/roomconsumables/v1/roomConsumable/room/{roomId:long}/me")] + [Authorize] + public async Task MineForRoom(long roomId) + { + var me = this.RequireCurrentPlayerId(); + var rows = await (from inventory in db.PlayerInventory + join item in db.StoreItems on inventory.ItemSlug equals item.Slug + where inventory.PlayerId == me + && inventory.Quantity > 0 + && item.IsActive + && item.Category.ToLower() == "consumable" + orderby item.DisplayName + select new { Inventory = inventory, Item = item }) + .Take(200) + .ToListAsync(); + return Ok(rows.Select(row => ToInventoryWire(row.Item, row.Inventory))); + } + [HttpPost("api/roomconsumables/v1/roomconsumable/{itemId:long}/purchase/currency")] [Authorize] public Task PurchaseCurrency(long itemId, [FromQuery] int? currencyType = null) => @@ -73,16 +94,46 @@ public class RoomConsumablesController(DorkNetDbContext db, LevelService level) }); } - private static object ToWire(StoreItemEntity item) => new + private static object ToWire(StoreItemEntity item) { - RoomConsumableId = item.Id, - ItemId = item.Id, - item.Slug, - Name = item.DisplayName, - item.Description, - item.ImageName, - item.Price, - item.CurrencyType, - item.Category, - }; + var roomConsumableId = StableRoomConsumableId(item.Id).ToString("D"); + return new + { + RoomConsumableId = roomConsumableId, + Name = item.DisplayName, + item.ImageName, + item.Description, + item.Price, + CurrencyId = (Guid?)null, + CreatedAt = DateTimeOffset.UnixEpoch, + ItemId = item.Id, + item.Slug, + item.CurrencyType, + item.Category, + }; + } + + private static object ToInventoryWire(StoreItemEntity item, PlayerInventoryEntity inventory) + { + var createdAt = inventory.AcquiredAt == default + ? DateTimeOffset.UnixEpoch + : new DateTimeOffset(DateTime.SpecifyKind(inventory.AcquiredAt, DateTimeKind.Utc)); + return new + { + Id = StableRoomConsumableId(item.Id).ToString("D"), + ConsumableItemDesc = ToWire(item), + Count = Math.Max(0, inventory.Quantity), + InitialCount = Math.Max(0, inventory.Quantity), + CreatedAt = createdAt, + ActiveDurationMinutes = 0, + IsActive = inventory.IsActive, + IsTransferable = false, + }; + } + + private static Guid StableRoomConsumableId(long itemId) + { + var hash = MD5.HashData(Encoding.UTF8.GetBytes($"roomConsumable:{itemId}")); + return new Guid(hash); + } } diff --git a/DorkNet.Server/Controllers/API/Rooms/V2/RoomsController.cs b/DorkNet.Server/Controllers/API/Rooms/V2/RoomsController.cs index 3fb1975..9e01bcd 100644 --- a/DorkNet.Server/Controllers/API/Rooms/V2/RoomsController.cs +++ b/DorkNet.Server/Controllers/API/Rooms/V2/RoomsController.cs @@ -48,12 +48,32 @@ public class RoomsController( /// TagsCsv column (e.g. `#community`, `#recroomoriginal`). /// [HttpGet("api/rooms/v1/hot")] - [HttpGet("rooms/hot")] - public async Task Hot( + public async Task HotV1( [FromQuery] string? roomScoreType, [FromQuery] string? tags) => Ok((await rooms.HotAsync(tags)).Select(RoomService.ToWireRoom).ToList()); + [HttpGet("rooms/hot")] + public async Task HotRoomServer( + [FromQuery] string? tag, + [FromQuery] string? tags, + [FromQuery] int skip = 0, + [FromQuery] int take = 100) + { + var all = await rooms.HotAsync(tag ?? tags, take: 200); + var page = all + .Skip(Math.Max(skip, 0)) + .Take(Math.Clamp(take, 1, 100)) + .Select(RoomService.ToWireRoom) + .ToList(); + + return Ok(new + { + Results = page, + TotalResults = all.Count, + }); + } + /// /// GET /roomserver/rooms/recommendations — the home-tab /// "Recommended" carousel. Wire shape is NOT a flat @@ -1543,7 +1563,6 @@ public class RoomsController( .Where(r => r.Id == roomId) .Select(r => new { r.Id, r.VisitCount, r.CheerCount, r.FavoriteCount }) .FirstOrDefaultAsync(); - if (room is null) return NotFound(); var favorited = await db.RoomBookmarks .AnyAsync(b => b.RoomId == roomId && b.PlayerId == pid.Value); @@ -1556,7 +1575,7 @@ public class RoomsController( return Ok(new { - RoomId = room.Id, + RoomId = room?.Id ?? roomId, PlayerId = pid.Value, Favorite = favorited, Favorited = favorited, @@ -1569,9 +1588,9 @@ public class RoomsController( VisitCount = visit?.VisitCount ?? 0, FirstVisitedAt = visit?.FirstVisitAt, LastVisitedAt = visit?.LastVisitAt, - RoomVisitCount = room.VisitCount, - RoomCheerCount = room.CheerCount, - RoomFavoriteCount = room.FavoriteCount, + RoomVisitCount = room?.VisitCount ?? 0, + RoomCheerCount = room?.CheerCount ?? 0, + RoomFavoriteCount = room?.FavoriteCount ?? 0, }); } @@ -1613,7 +1632,7 @@ public class RoomsController( public async Task CuratedPlaylistsCompat() { var curated = await playlists.CuratedAsync(); - return Ok(curated.Select(BuildPlaylistUnionEntry).ToList()); + return Ok(curated.Select(p => p.Id).ToList()); } [HttpGet("clubhousesearch/mostactivenow")] @@ -1725,17 +1744,25 @@ public class RoomsController( /// shape here throws KeyNotFoundException on /// the watch's group-id lookup. [HttpGet("featuredrooms/current")] - public async Task FeaturedRoomsCurrent() => Ok(new + public async Task FeaturedRoomsCurrent() { - FeaturedRoomGroupId = 1L, - Name = "Featured", - // NMPFCIJPODA.PPGFHEDFBEA (NMPFCIJPODA.txt:100-125) reads - // 3 strict keys, not 2 — FeaturedRoomGroupId, Name, AND - // Rooms (List). Returning without the third - // key throws KeyNotFoundException on the watch and the - // Featured carousel stays empty. - Rooms = await rooms.FeaturedAgRoomIdsAsync(12), - }); + var ids = await rooms.FeaturedAgRoomIdsAsync(12); + var featuredRooms = await db.Rooms + .Where(r => ids.Contains(r.Id)) + .ToListAsync(); + var byId = featuredRooms.ToDictionary(r => r.Id); + var wireRooms = ids + .Select(id => byId.TryGetValue(id, out var room) ? RoomService.ToWireRoom(room) : null) + .Where(room => room is not null) + .Cast() + .ToList(); + return Ok(new + { + FeaturedRoomGroupId = 1L, + Name = "Featured", + Rooms = wireRooms, + }); + } /// POST api/rooms/v1/bookmark — toggle bookmark /// state for a room. Body: RoomId + optional Bookmark diff --git a/DorkNet.Server/Controllers/Commerce/PurchaseCampaignController.cs b/DorkNet.Server/Controllers/Commerce/PurchaseCampaignController.cs new file mode 100644 index 0000000..d220ea9 --- /dev/null +++ b/DorkNet.Server/Controllers/Commerce/PurchaseCampaignController.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace DorkNet.Server.Controllers.Commerce; + +[ApiController] +public class PurchaseCampaignController : ControllerBase +{ + [HttpGet("/purchasecampaign/allcurrent/v2")] + [HttpGet("/purchasecampaign/allcurrent")] + [AllowAnonymous] + public IActionResult AllCurrent() => Ok(Array.Empty()); +} diff --git a/DorkNet.Server/Controllers/Match/MatchController.cs b/DorkNet.Server/Controllers/Match/MatchController.cs index 9890601..967881f 100644 --- a/DorkNet.Server/Controllers/Match/MatchController.cs +++ b/DorkNet.Server/Controllers/Match/MatchController.cs @@ -103,6 +103,28 @@ public class MatchController( }); } + [HttpGet("/photon_access_token")] + public IActionResult PhotonAccessToken() + { + var pid = this.RequireCurrentPlayerId(); + var appId = config["Photon:AppId"] ?? string.Empty; + var voiceAppId = config["Photon:VoiceAppId"] ?? string.Empty; + var region = (config["Photon:CloudRegion"] ?? "us").ToLowerInvariant(); + return Ok(new Dictionary + { + ["ResultCode"] = 1, + ["Message"] = string.Empty, + ["UserId"] = pid.ToString(System.Globalization.CultureInfo.InvariantCulture), + ["PhotonAppId"] = appId, + ["PhotonVoiceAppId"] = voiceAppId, + ["AppId"] = appId, + ["VoiceAppId"] = voiceAppId, + ["CloudRegion"] = region, + ["Region"] = region, + ["Token"] = string.Empty, + }); + } + [HttpPost("/matchmake/dorm")] public async Task MatchmakeDorm() {