mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
Refactor configuration endpoints and update client installation scripts
- Removed Photon configuration fields from dorknet-clientmod.json.template. - Added new backtrace and Azure Speech configuration endpoints in ConfigController. - Updated response format for IsCreationEnabled and IsRenderingEnabled endpoints in CustomAvatarItemsController. - Enhanced InfluencerPartnerProgramController to include additional player properties. - Implemented RoomKeepsakes endpoint in KeepsakesController to retrieve keepsakes by room ID. - Modified ReportsController to standardize response for Hile reporting. - Added PlayerDataForMe and RoomsRequiring endpoints in RoomsController for enhanced player data retrieval. - Introduced new dorm matchmaking methods in MatchController for player session management. - Updated MatchPlayerController to handle exclusive login functionality. - Revised install scripts to reflect changes in Photon AppId handling and patching process. - Added new patch-client.ps1 script for applying static byte patches to the Rec Room client.
This commit is contained in:
@@ -21,6 +21,102 @@ public class ConfigController(ConfigService configService) : ControllerBase
|
||||
[HttpGet("amplitude")]
|
||||
public ActionResult<object> GetAmplitude() => Ok(new { AmplitudeKey = string.Empty });
|
||||
|
||||
/// <summary>
|
||||
/// GET <c>api/config/v1/backtrace</c> — 2023 boot downloads this before
|
||||
/// audio/core initialization. Returning 404 leaves the static backtrace
|
||||
/// config null and later crashes <c>ConfigSettings</c> consumers. Keep
|
||||
/// crash upload/deobfuscation disabled locally while preserving the
|
||||
/// object shape and readable config keys the client inspects.
|
||||
/// </summary>
|
||||
[HttpGet("backtrace")]
|
||||
public ActionResult<object> GetBacktrace(
|
||||
[FromQuery(Name = "platformType")] string? platformType,
|
||||
[FromQuery(Name = "allocate")] bool? allocate)
|
||||
{
|
||||
var baseUrl = $"{Request.Scheme}://{Request.Host}";
|
||||
var submissionUrl = $"{baseUrl}/backtrace/submit";
|
||||
var minidumpSubmissionUrl = $"{baseUrl}/backtrace/minidump";
|
||||
var config = new Dictionary<string, object>
|
||||
{
|
||||
["Backtrace.SampleRate"] = 0.0,
|
||||
["Backtrace.ReportBudget"] = 0,
|
||||
["Backtrace.deobfuscationRate"] = 0.0,
|
||||
["Backtrace.Deobfuscate"] = false,
|
||||
["Backtrace.DeobfuscationUrl"] = string.Empty,
|
||||
["Backtrace.Enabled"] = false,
|
||||
["Backtrace.PlatformType"] = platformType ?? string.Empty,
|
||||
["Backtrace.Allocate"] = allocate ?? false,
|
||||
};
|
||||
|
||||
return Ok(new Dictionary<string, object>
|
||||
{
|
||||
["MaxMessagesPerMinute"] = 0,
|
||||
["MaxReportsPerMinute"] = 0,
|
||||
["SampleRate"] = 0.0,
|
||||
["ReportBudget"] = 0,
|
||||
["ErrorReportBudget"] = 0,
|
||||
["WarningReportBudget"] = 0,
|
||||
["LogReportBudget"] = 0,
|
||||
["SubmissionUrl"] = submissionUrl,
|
||||
["MinidumpSubmissionUrl"] = minidumpSubmissionUrl,
|
||||
["ServerUrl"] = submissionUrl,
|
||||
["DatabasePath"] = "backtrace/database",
|
||||
["Config"] = config,
|
||||
["maxMessagesPerMinute"] = 0,
|
||||
["maxReportsPerMinute"] = 0,
|
||||
["sampleRate"] = 0.0,
|
||||
["reportBudget"] = 0,
|
||||
["errorReportBudget"] = 0,
|
||||
["warningReportBudget"] = 0,
|
||||
["logReportBudget"] = 0,
|
||||
["submissionUrl"] = submissionUrl,
|
||||
["minidumpSubmissionUrl"] = minidumpSubmissionUrl,
|
||||
["serverUrl"] = submissionUrl,
|
||||
["databasePath"] = "backtrace/database",
|
||||
["config"] = config,
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("azurespeech")]
|
||||
public IActionResult GetAzureSpeech()
|
||||
{
|
||||
return Ok(new Dictionary<string, object>
|
||||
{
|
||||
["Enabled"] = false,
|
||||
["SpeechRecognitionEnabled"] = false,
|
||||
["SpeechSynthesisEnabled"] = false,
|
||||
["Region"] = string.Empty,
|
||||
["SubscriptionKey"] = string.Empty,
|
||||
["TokenEndpoint"] = string.Empty,
|
||||
["SpeechRecognitionEndpoint"] = string.Empty,
|
||||
["SpeechSynthesisEndpoint"] = string.Empty,
|
||||
["enabled"] = false,
|
||||
["speechRecognitionEnabled"] = false,
|
||||
["speechSynthesisEnabled"] = false,
|
||||
["region"] = string.Empty,
|
||||
["subscriptionKey"] = string.Empty,
|
||||
["tokenEndpoint"] = string.Empty,
|
||||
["speechRecognitionEndpoint"] = string.Empty,
|
||||
["speechSynthesisEndpoint"] = string.Empty,
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("/voice/config")]
|
||||
public IActionResult GetVoiceConfig()
|
||||
{
|
||||
return Ok(new Dictionary<string, object>
|
||||
{
|
||||
["ToxMod.Enabled"] = false,
|
||||
["ToxMod.SampleRate"] = 0.0,
|
||||
["ToxMod.SessionRecordingEnabled"] = false,
|
||||
["ToxMod.Endpoint"] = string.Empty,
|
||||
["ToxMod.ApiKey"] = string.Empty,
|
||||
["Enabled"] = false,
|
||||
["enabled"] = false,
|
||||
["toxModEnabled"] = false,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>GET <c>api/config/v1/freegiftbutton</c> — the
|
||||
/// 2020.12 client deserializes this endpoint as a raw Boolean.
|
||||
/// This server does not run the timed free-gift campaign, so the
|
||||
|
||||
@@ -187,11 +187,11 @@ public class CustomAvatarItemsController(
|
||||
|
||||
[HttpGet("isCreationEnabled")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult IsCreationEnabled() => Ok(new { IsCreationEnabled = true, Enabled = true });
|
||||
public IActionResult IsCreationEnabled() => Content("true", "application/json");
|
||||
|
||||
[HttpGet("isRenderingEnabled")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult IsRenderingEnabled() => Ok(new { IsRenderingEnabled = true, Enabled = true });
|
||||
public IActionResult IsRenderingEnabled() => Content("true", "application/json");
|
||||
|
||||
[HttpGet("minPriceForPublicItem")]
|
||||
[AllowAnonymous]
|
||||
|
||||
+8
-1
@@ -95,8 +95,15 @@ public class InfluencerPartnerProgramController(DorkNetDbContext db) : Controlle
|
||||
private static object ToInfluencerWire(PlayerEntity player) => new
|
||||
{
|
||||
AccountId = (int)player.Id,
|
||||
RawUsername = player.Username,
|
||||
player.Username,
|
||||
DisplayName = player.DisplayName,
|
||||
DisplayName = player.DisplayName ?? player.Username,
|
||||
ProfileImage = player.ProfileImageName ?? string.Empty,
|
||||
TreatAsJunior = false,
|
||||
HasBirthday = true,
|
||||
Platforms = 1,
|
||||
IsInfluencer = true,
|
||||
SupportedInfluencerId = (int?)null,
|
||||
LocalSupportedInfluencerId = (int?)null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,6 +46,25 @@ public class KeepsakesController(DorkNetDbContext db, DomainConfig domain) : Con
|
||||
return Ok(rows.Select(ToWire));
|
||||
}
|
||||
|
||||
[HttpGet("rooms/{roomId:long}")]
|
||||
public async Task<IActionResult> RoomKeepsakes(long roomId)
|
||||
{
|
||||
var roomExists = await db.Rooms.AsNoTracking().AnyAsync(r => r.Id == roomId);
|
||||
if (!roomExists) return NotFound();
|
||||
|
||||
var roomIdText = roomId.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
var rows = await db.Keepsakes
|
||||
.Where(k => k.Category == "room"
|
||||
&& (k.EventKey == $"room:{roomIdText}"
|
||||
|| k.EventKey == $"room/{roomIdText}"
|
||||
|| k.EventKey == roomIdText
|
||||
|| EF.Functions.Like(k.EventKey, $"room:{roomIdText}:%")
|
||||
|| EF.Functions.Like(k.EventKey, $"room/{roomIdText}/%")))
|
||||
.OrderByDescending(k => k.EarnedAt)
|
||||
.ToListAsync();
|
||||
return Ok(rows.Select(ToWire));
|
||||
}
|
||||
|
||||
[HttpGet("globalconfig")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult GlobalConfig() => Ok(new
|
||||
|
||||
@@ -202,7 +202,7 @@ public class ReportsController(DorkNetDbContext db) : ControllerBase
|
||||
private async Task<IActionResult> SaveHileAsync(string? rawDetail, int? type, long? gameSessionId)
|
||||
{
|
||||
var pid = this.CurrentPlayerId();
|
||||
if (pid is not long me) return Ok(new { success = true });
|
||||
if (pid is not long me) return HileResult();
|
||||
var detail = (rawDetail ?? string.Empty).Trim();
|
||||
if (type is int hileType)
|
||||
detail = detail.Length == 0 ? $"Type={hileType}" : $"Type={hileType}; {detail}";
|
||||
@@ -216,6 +216,13 @@ public class ReportsController(DorkNetDbContext db) : ControllerBase
|
||||
Category = "hile",
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
return Ok(new { success = true });
|
||||
return HileResult();
|
||||
}
|
||||
|
||||
private static IActionResult HileResult() => new ContentResult
|
||||
{
|
||||
Content = "true",
|
||||
ContentType = "application/json",
|
||||
StatusCode = StatusCodes.Status200OK,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1532,6 +1532,144 @@ public class RoomsController(
|
||||
[HttpGet("api/rooms/v2/myrecent")]
|
||||
public IActionResult MyOtherTabs() => Ok(Array.Empty<object>());
|
||||
|
||||
[HttpGet("rooms/{roomId:long}/playerdata/me")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> PlayerDataForMe(long roomId)
|
||||
{
|
||||
var pid = CurrentPlayerId;
|
||||
if (pid is null) return Unauthorized();
|
||||
|
||||
var room = await db.Rooms.AsNoTracking()
|
||||
.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);
|
||||
var cheered = await db.Cheers
|
||||
.AnyAsync(c => c.TargetRoomId == roomId && c.FromPlayerId == pid.Value);
|
||||
var visit = await db.RoomVisits.AsNoTracking()
|
||||
.Where(v => v.RoomId == roomId && v.PlayerId == pid.Value)
|
||||
.Select(v => new { v.VisitCount, v.FirstVisitAt, v.LastVisitAt })
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
RoomId = room.Id,
|
||||
PlayerId = pid.Value,
|
||||
Favorite = favorited,
|
||||
Favorited = favorited,
|
||||
IsFavorite = favorited,
|
||||
Cheer = cheered,
|
||||
Cheered = cheered,
|
||||
IsCheered = cheered,
|
||||
IsBookmarked = favorited,
|
||||
IsCheering = cheered,
|
||||
VisitCount = visit?.VisitCount ?? 0,
|
||||
FirstVisitedAt = visit?.FirstVisitAt,
|
||||
LastVisitedAt = visit?.LastVisitAt,
|
||||
RoomVisitCount = room.VisitCount,
|
||||
RoomCheerCount = room.CheerCount,
|
||||
RoomFavoriteCount = room.FavoriteCount,
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("rooms/requiring/{restriction}")]
|
||||
[HttpGet("roomserver/rooms/requiring/{restriction}")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> RoomsRequiring(string restriction)
|
||||
{
|
||||
var key = (restriction ?? string.Empty).Trim().TrimStart('#').ToLowerInvariant();
|
||||
if (key.Length == 0) return Ok(new List<object>());
|
||||
|
||||
IQueryable<RoomEntity> query = db.Rooms.AsNoTracking()
|
||||
.Where(r => !r.HiddenFromBrowse && r.State == 0);
|
||||
|
||||
query = key switch
|
||||
{
|
||||
"developer" or "studio" or "rrstudio" => query.Where(r =>
|
||||
r.IsStudioRoom
|
||||
|| r.IsRoomLinkedToRecRoomStudio
|
||||
|| EF.Functions.Like(r.TagsCsv, "%developer%")
|
||||
|| EF.Functions.Like(r.TagsCsv, "%studio%")),
|
||||
"rrplus" or "recroomplus" => query.Where(r =>
|
||||
EF.Functions.Like(r.TagsCsv, "%rrplus%")
|
||||
|| EF.Functions.Like(r.TagsCsv, "%recroomplus%")),
|
||||
_ => query.Where(r => EF.Functions.Like(r.TagsCsv, $"%{key}%")),
|
||||
};
|
||||
|
||||
var rows = await query
|
||||
.OrderByDescending(r => r.HotScore)
|
||||
.ThenBy(r => r.Name)
|
||||
.Take(100)
|
||||
.ToListAsync();
|
||||
return Ok(rows.Select(RoomService.ToWireRoom).ToList());
|
||||
}
|
||||
|
||||
[HttpGet("rooms/curated_playlists")]
|
||||
[HttpGet("roomserver/rooms/curated_playlists")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> CuratedPlaylistsCompat()
|
||||
{
|
||||
var curated = await playlists.CuratedAsync();
|
||||
return Ok(curated.Select(BuildPlaylistUnionEntry).ToList());
|
||||
}
|
||||
|
||||
[HttpGet("clubhousesearch/mostactivenow")]
|
||||
[HttpGet("roomserver/clubhousesearch/mostactivenow")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> MostActiveClubhouses()
|
||||
{
|
||||
var rows = await db.Clubs.AsNoTracking()
|
||||
.Where(c => c.State == 0 && c.ClubhouseRoomId != null)
|
||||
.GroupJoin(
|
||||
db.ClubMemberships.AsNoTracking(),
|
||||
c => c.Id,
|
||||
m => m.ClubId,
|
||||
(club, memberships) => new
|
||||
{
|
||||
Club = club,
|
||||
MemberCount = memberships.Count(),
|
||||
})
|
||||
.Join(
|
||||
db.Rooms.AsNoTracking(),
|
||||
c => c.Club.ClubhouseRoomId!.Value,
|
||||
r => r.Id,
|
||||
(c, room) => new
|
||||
{
|
||||
c.Club,
|
||||
c.MemberCount,
|
||||
Room = room,
|
||||
})
|
||||
.OrderByDescending(x => x.MemberCount)
|
||||
.ThenByDescending(x => x.Room.HotScore)
|
||||
.Take(50)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(rows.Select(x => new
|
||||
{
|
||||
ClubId = x.Club.Id,
|
||||
x.Club.Name,
|
||||
x.Club.Description,
|
||||
MainImageName = x.Club.ImageName,
|
||||
ImageName = x.Club.ImageName,
|
||||
State = x.Club.State,
|
||||
CreatorAccountId = x.Club.CreatorPlayerId,
|
||||
Category = x.Club.Category,
|
||||
Visibility = x.Club.Visibility,
|
||||
Joinability = x.Club.Joinability,
|
||||
x.Club.AllowJuniors,
|
||||
MemberCount = x.MemberCount,
|
||||
x.Club.IsRRO,
|
||||
x.Club.ClubhouseRoomId,
|
||||
x.Club.ClubType,
|
||||
Room = RoomService.ToWireRoom(x.Room),
|
||||
RoomId = x.Room.Id,
|
||||
RoomName = x.Room.Name,
|
||||
}).ToList());
|
||||
}
|
||||
|
||||
// ── Bookmark mutations ───────────────────────────────────────────────
|
||||
|
||||
[HttpPost("api/rooms/v1/bookmark/{roomId:long}")]
|
||||
|
||||
Reference in New Issue
Block a user