More changes...

This commit is contained in:
2026-02-27 19:30:49 -08:00
parent 20fdf60665
commit b64e257b9a
36 changed files with 553 additions and 63 deletions

View File

@@ -2,9 +2,12 @@
namespace RecRoomArchive.Models.API.Activities namespace RecRoomArchive.Models.API.Activities
{ {
public class CharadesWord(string word, CharadesWordsDifficulty difficulty = CharadesWordsDifficulty.Easy) public class CharadesWord
{ {
[JsonPropertyName(name: "Difficulty")] public CharadesWordsDifficulty Difficulty { get; set; } = difficulty; [JsonPropertyName("Difficulty")]
[JsonPropertyName(name: "EN_US")] public string EN_US { get; set; } = word; public CharadesWordsDifficulty Difficulty { get; set; } = CharadesWordsDifficulty.Easy;
[JsonPropertyName("EN_US")]
public string EN_US { get; set; } = string.Empty;
} }
} }

View File

@@ -6,5 +6,6 @@ namespace RecRoomArchive.Models.API.Config
{ {
[JsonPropertyName(name: "CloudRegion")] public string CloudRegion { get; set; } = "us"; [JsonPropertyName(name: "CloudRegion")] public string CloudRegion { get; set; } = "us";
[JsonPropertyName(name: "CrcCheckEnabled")] public bool CrcCheckEnabled { get; set; } = true; [JsonPropertyName(name: "CrcCheckEnabled")] public bool CrcCheckEnabled { get; set; } = true;
[JsonPropertyName(name: "EnableServerTracingAfterDisconnect")] public bool EnableServerTracingAfterDisconnect { get; set; } = true;
} }
} }

View File

@@ -0,0 +1,21 @@
namespace RecRoomArchive.Models.API.GameSessions
{
public enum ActivityLevels
{
INVALID = -1,
DORM_ROOM = 1000,
REC_CENTER = 2000,
CHARADES = 3000,
DISC_GOLF = 4000,
DODGEBALL = 5000,
THE_LOUNGE = 6000,
PADDLEBALL = 7000,
PAINTBALL = 8000,
QUEST = 9000,
SOCCER = 10000,
ART_TESTING = 11000,
PERFORMANCE_HALL = 12000,
ROOM_CALIBRATION = 13000,
PARK = 14000
}
}

View File

@@ -0,0 +1,34 @@
using System.Text.Json.Serialization;
namespace RecRoomArchive.Models.API.GameSessions
{
public class GameSession
{
[JsonPropertyName(name: "GameSessionId")]
public long GameSessionId { get; set; } = 1;
[JsonPropertyName(name: "RegionId")]
public string RegionId { get; set; } = "us";
[JsonPropertyName(name: "RoomId")]
public string RoomId { get; set; } = "fba33a23-b4a5-4f55-a631-37028b1db7f9";
[JsonPropertyName(name: "EventId")]
public ulong? EventId { get; set; }
[JsonPropertyName(name: "ActivityLevelId")]
public string ActivityLevelId { get; set; } = "76d98498-60a1-430c-ab76-b54a29b7a163";
[JsonPropertyName(name: "Private")]
public bool Private { get; set; } = false;
[JsonPropertyName(name: "GameInProgress")]
public bool GameInProgress { get; set; } = false;
[JsonPropertyName(name: "MaxCapacity")]
public int MaxCapacity { get; set; } = 8;
[JsonPropertyName(name: "IsFull")]
public bool IsFull { get; set; } = false;
}
}

View File

@@ -0,0 +1,14 @@
namespace RecRoomArchive.Models.API.GameSessions
{
public enum JoinGameErrorCode
{
Success,
NoSuchGame,
PlayerNotOnline,
InsufficientSpace,
EventNotStarted,
EventAlreadyFinished,
EventCreatorNotReady,
Blocked
}
}

View File

@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;
namespace RecRoomArchive.Models.API.GameSessions
{
public class JoinGameSessionResponse
{
[JsonPropertyName(name: "Result")]
public JoinGameErrorCode Result { get; set; } = JoinGameErrorCode.Success;
[JsonPropertyName(name: "GameSession")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public GameSession? GameSession { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace RecRoomArchive.Models.API.GameSessions
{
public class JoinRandomGameSessionRequest
{
public required string[] ActivityLevelIds { get; set; } = [];
public ulong[] ExpectedPlayerIds { get; set; } = [];
}
}

View File

@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
namespace RecRoomArchive.Models.API.GameSessions
{
public class PresenceResponseFuckYou
{
[JsonPropertyName(name: "PlayerId")]
public ulong PlayerId { get; set; }
[JsonPropertyName(name: "IsOnline")]
public bool IsOnline { get; set; }
[JsonPropertyName(name: "GameSession")]
public GameSession? GameSession { get; set; }
}
}

View File

@@ -0,0 +1,46 @@
namespace RecRoomArchive.Models.API.Notification
{
public enum PushNotificationId
{
RelationshipChanged = 1,
MessageReceived,
MessageDeleted,
PresenceHeartbeatResponse,
RefreshLogin,
Logout,
SubscriptionUpdateProfile = 11,
SubscriptionUpdatePresence,
SubscriptionUpdateGameSession,
SubscriptionUpdateRoom = 15,
SubscriptionUpdateRoomPlaylist,
ModerationQuitGame = 20,
ModerationUpdateRequired,
ModerationKick,
ModerationKickAttemptFailed,
ModerationRoomBan,
ServerMaintenance,
GiftPackageReceived = 30,
GiftPackageReceivedImmediate,
GiftPackageRewardSelectionReceived,
ProfileJuniorStatusUpdate = 40,
RelationshipsInvalid = 50,
StorefrontBalanceAdd = 60,
StorefrontBalanceUpdate,
StorefrontBalancePurchase,
ConsumableMappingAdded = 70,
ConsumableMappingRemoved,
PlayerEventCreated = 80,
PlayerEventUpdated,
PlayerEventDeleted,
PlayerEventResponseChanged,
PlayerEventResponseDeleted,
PlayerEventStateChanged,
ChatMessageReceived = 90,
CommunityBoardUpdate = 95,
CommunityBoardAnnouncementUpdate,
InventionModerationStateChanged = 100,
FreeGiftButtonItemsAdded = 110,
LocalRoomKeyCreated = 120,
LocalRoomKeyDeleted
}
}

View File

@@ -12,5 +12,6 @@ namespace RecRoomArchive.Models.API.PlatformLogin.Requests
public required long BuildTimestamp { get; set; } public required long BuildTimestamp { get; set; }
public required string AuthParams { get; set; } public required string AuthParams { get; set; }
public required string Verify { get; set; } public required string Verify { get; set; }
public string? PlayerId { get; set; }
} }
} }

View File

@@ -4,10 +4,13 @@ namespace RecRoomArchive.Models.API.PlatformLogin.Responses
{ {
public class BaseLoginResponse public class BaseLoginResponse
{ {
[JsonPropertyName(name: "PlayerId")]
public ulong PlayerId { get; set; }
[JsonPropertyName(name: "Token")] [JsonPropertyName(name: "Token")]
public string Token { get; set; } = string.Empty; public string Token { get; set; } = string.Empty;
[JsonPropertyName(name: "PlayerId")] [JsonPropertyName(name: "Error")]
public ulong PlayerId { get; set; } public string Error { get; set; } = string.Empty;
} }
} }

View File

@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace RecRoomArchive.Models.API.VersionCheck
{
public class VersionCheckResponse(VersionStatus versionStatus = VersionStatus.ValidForPlay)
{
[JsonPropertyName(name: "VersionStatus")] public VersionStatus VersionStatus { get; set; } = versionStatus;
[JsonPropertyName(name: "ValidVersion")] public bool ValidVersion => VersionStatus == VersionStatus.ValidForPlay;
[JsonPropertyName(name: "IsValid")] public bool IsValid => VersionStatus == VersionStatus.ValidForPlay;
}
}

View File

@@ -0,0 +1,8 @@
namespace RecRoomArchive.Models.API.VersionCheck
{
public enum VersionStatus
{
ValidForPlay,
UpdateRequired
}
}

View File

@@ -0,0 +1,7 @@
namespace RecRoomArchive.Models.Common
{
public class Constants
{
public static readonly string Version = "0.0.5";
}
}

View File

@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;
namespace RecRoomArchive.Models.RRA
{
public class ServerPreferences
{
[JsonPropertyName(name: "CompletedSetup")] public bool CompletedSetup { get; set; } = false;
[JsonPropertyName(name: "OverrideNamedImages")] public bool OverrideNamedImages { get; set; } = false;
[JsonPropertyName(name: "EnableWebRequests")] public bool EnableWebRequests { get; set; } = true;
}
}

View File

@@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
namespace RecRoomArchive.Controllers.API.Equipment.V1
{
[Route(template: "api/[controller]/v1")]
[ApiController]
public class EquipmentController : ControllerBase
{
[HttpGet(template: "getUnlocked")]
public async Task<ActionResult<List<object>>> GetEquipment()
{
return new List<object>();
}
}
}

View File

@@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
namespace RecRoomArchive.Controllers.API.Events.V3
{
[Route(template: "api/[controller]/v3")]
[ApiController]
public class EventsController : ControllerBase
{
[HttpGet(template: "list")]
public async Task<ActionResult<List<object>>> GetActiveEventsList()
{
return new List<object>();
}
}
}

View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.GameSessions;
using System.Text.Json;
namespace RecRoomArchive.Controllers.API.GameSessions.V2
{
[Route("api/[controller]/v2")]
[ApiController]
public class GameSessionsController : ControllerBase
{
[HttpPost(template: "joinRandom")]
public async Task<ActionResult<JoinGameSessionResponse>> JoinRandomGameSession([FromBody] JoinRandomGameSessionRequest request)
{
Console.WriteLine(JsonSerializer.Serialize(request));
var session = new JoinGameSessionResponse()
{
GameSession = new GameSession()
};
Console.WriteLine(JsonSerializer.Serialize(session));
return Ok(session);
}
}
}

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Controllers.API.Notification;
using RecRoomArchive.Models.API.Notification;
using RecRoomArchive.Models.API.Players; using RecRoomArchive.Models.API.Players;
using RecRoomArchive.Services; using RecRoomArchive.Services;
using System.Text.Json; using System.Text.Json;
@@ -25,6 +27,8 @@ namespace RecRoomArchive.Controllers.API.Images.V2
fileService.SetData("profile.json", JsonSerializer.Serialize(profile)); fileService.SetData("profile.json", JsonSerializer.Serialize(profile));
await NotificationController.Notify(profile.Id, PushNotificationId.SubscriptionUpdateProfile, profile);
return Ok(); return Ok();
} }
} }

View File

@@ -0,0 +1,87 @@
using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.Notification;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
namespace RecRoomArchive.Controllers.API.Notification
{
[Route("api/[controller]")]
[ApiController]
public class NotificationController : ControllerBase
{
private static readonly Dictionary<ulong, WebSocket> Clients = [];
[HttpGet("v2")]
public async Task Get()
{
if (!HttpContext.WebSockets.IsWebSocketRequest)
{
HttpContext.Response.StatusCode = 400;
return;
}
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
var buffer = new byte[1024 * 4];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var handshakeJson = Encoding.UTF8.GetString(buffer, 0, result.Count);
var handshakeData = JsonSerializer.Deserialize<Dictionary<string, string>>(handshakeJson)!;
var playerId = ulong.Parse(handshakeData["PlayerId"]);
Clients[playerId] = webSocket;
var sessionResponse = JsonSerializer.Serialize(new { SessionId = playerId });
await webSocket.SendAsync(Encoding.UTF8.GetBytes(sessionResponse), WebSocketMessageType.Text, true, CancellationToken.None);
await Echo(playerId, webSocket);
Clients.Remove(playerId);
}
private static async Task Echo(ulong playerId, WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
var receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
while (!receiveResult.CloseStatus.HasValue)
{
var response = JsonSerializer.Serialize(new { SessionId = playerId }); // i think?? only for analytics tho lolololool
await webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(response)),
WebSocketMessageType.Text, true, CancellationToken.None);
/*await webSocket.SendAsync(
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
receiveResult.MessageType,
receiveResult.EndOfMessage,
CancellationToken.None);*/
receiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(
receiveResult.CloseStatus.Value,
receiveResult.CloseStatusDescription,
CancellationToken.None);
Clients.Remove(playerId);
}
public static async Task Notify(ulong playerId, PushNotificationId id, object msg)
{
if (!Clients.TryGetValue(playerId, out var socket))
return;
if (socket.State != WebSocketState.Open)
return;
var notification = new
{
Id = (int)id,
Msg = msg
};
var json = JsonSerializer.Serialize(notification);
var bytes = Encoding.UTF8.GetBytes(json);
await socket.SendAsync(bytes, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.Platform;
using RecRoomArchive.Models.API.Players;
using RecRoomArchive.Services;
namespace RecRoomArchive.Controllers.API.PlatformLogin.V1
{
[Route("api/[controller]/v1")]
[ApiController]
public class PlatformLoginController(AccountService accountService) : ControllerBase
{
[HttpPost(template: "profiles")]
public async Task<ActionResult<List<BaseProfile>>> GetProfiles([FromForm(Name = "Platform")] PlatformType platform, [FromForm(Name = "PlatformId")] ulong platformId)
{
if (!accountService.AccountExists())
{
accountService.CreateAccount();
}
var profile = accountService.GetSelfAccount();
if (profile == null)
return BadRequest("Please relaunch RRAC and re-run setup");
List<BaseProfile> profiles = [profile];
return Ok(profiles);
}
}
}

View File

@@ -34,7 +34,7 @@ namespace RecRoomArchive.Controllers.API.PlatformLogin.V2
accountService.CreateAccount(username); accountService.CreateAccount(username);
} }
var accountId = accountService.GetSelfAccount()!.Id; var accountId = accountService.GetSelfAccountId()!.Value;
return Ok(new BaseLoginResponse return Ok(new BaseLoginResponse
{ {

View File

@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.PlatformLogin.Requests;
using RecRoomArchive.Models.API.PlatformLogin.Responses;
using RecRoomArchive.Services;
namespace RecRoomArchive.Controllers.API.PlatformLogin.V5
{
/// <summary>
/// Used to login to accounts on Rec Room
/// </summary>
[Route(template: "api/[controller]/v5")]
[ApiController]
public class PlatformLoginController(AppVersionService appVersionService, AccountService accountService, AuthorizationService authorizationService) : ControllerBase
{
/// <summary>
/// Checks if the appVersion provided is allowed to play (which it most certainly will be unless its a weird build or someone messed with it)
/// </summary>
/// <returns>An Ok response if the version is valid, Forbid if it is not. Forbid will yield the client displaying "Rec Room Update Required" soo maybe don't</returns>
[HttpPost]
public async Task<ActionResult> Login([FromForm] BaseLoginRequest loginRequest)
{
var username = loginRequest.Name ?? string.Empty;
var buildTimestamp = loginRequest.BuildTimestamp;
await appVersionService.StoreBuildTimestamp(buildTimestamp);
// See if a profile exists yet...
if (!accountService.AccountExists())
{
// ...if not, create it!
accountService.CreateAccount(username);
}
var accountId = accountService.GetSelfAccountId()!.Value;
return Ok(new BaseLoginResponse
{
Token = authorizationService.GenerateToken(accountId),
PlayerId = accountId
});
}
}
}

View File

@@ -69,7 +69,13 @@ namespace RecRoomArchive.Controllers.API.Players
[HttpPut(template: "{profileId:long}")] [HttpPut(template: "{profileId:long}")]
public async Task<ActionResult<AugustProfile>> UpdateProfile([Required] ulong profileId, [FromBody] AugustProfile model) public async Task<ActionResult<AugustProfile>> UpdateProfile([Required] ulong profileId, [FromBody] AugustProfile model)
{ {
return (AugustProfile)accountService.GetSelfAccount()!; var baseProfile = accountService.GetSelfAccount();
if (baseProfile == null)
return NotFound();
var profile = new AugustProfile(baseProfile);
return profile;
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.Config;
using RecRoomArchive.Models.API.Platform; using RecRoomArchive.Models.API.Platform;
using RecRoomArchive.Models.API.Players; using RecRoomArchive.Models.API.Players;
using RecRoomArchive.Services; using RecRoomArchive.Services;

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Controllers.API.Notification;
using RecRoomArchive.Models.API.Notification;
using RecRoomArchive.Models.API.Players; using RecRoomArchive.Models.API.Players;
using RecRoomArchive.Models.Common; using RecRoomArchive.Models.Common;
using RecRoomArchive.Services; using RecRoomArchive.Services;
@@ -31,6 +33,8 @@ namespace RecRoomArchive.Controllers.API.Players.V2
fileService.SetData("profile.json", JsonSerializer.Serialize(profile)); fileService.SetData("profile.json", JsonSerializer.Serialize(profile));
await NotificationController.Notify(profile.Id, PushNotificationId.SubscriptionUpdateProfile, profile);
return Ok(OkResponse.Ok()); return Ok(OkResponse.Ok());
} }
} }

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using RecRoomArchive.Models.API.VersionCheck;
using RecRoomArchive.Services;
namespace RecRoomArchive.Controllers.API.VersionCheck.V3
{
/// <summary>
/// Endpoints used to check if the version the player is playing on is up to date enough to play Rec Room, due to this being a custom server, it doesn't really matter
/// </summary>
[Route(template: "api/[controller]/v3")]
[ApiController]
public class VersionCheckController(AppVersionService appVersionService) : ControllerBase
{
/// <summary>
/// Checks if the appVersion provided is allowed to play (which it most certainly will be unless its a weird build or someone messed with it)
/// </summary>
/// <returns>A valid VersionCheckResponse if the version is valid, an invalid VersionCheckResponse if it is not. Forbid will yield the client displaying "Rec Room Update Required" soo maybe don't</returns>
[HttpGet]
public async Task<ActionResult> CheckVersion([FromQuery(Name = "v")] string appVersion)
{
if (appVersion == null)
return BadRequest(new VersionCheckResponse(VersionStatus.UpdateRequired));
await appVersionService.StoreAppVersion(appVersion);
return Ok(new VersionCheckResponse());
}
}
}

View File

@@ -1,5 +1,6 @@
using RecRoomArchive.Models.Common;
using RecRoomArchive.Services; using RecRoomArchive.Services;
using Serilog;
namespace RecRoomArchive namespace RecRoomArchive
{ {
@@ -8,11 +9,15 @@ namespace RecRoomArchive
public static void Main(string[] args) public static void Main(string[] args)
{ {
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel();
Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
#region Services #region Services
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddOpenApi(); builder.Services.AddOpenApi();
builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpContextAccessor();
builder.Services.AddSerilog();
builder.Services.AddScoped<AccountService>(); builder.Services.AddScoped<AccountService>();
builder.Services.AddScoped<AppVersionService>(); builder.Services.AddScoped<AppVersionService>();
@@ -21,17 +26,31 @@ namespace RecRoomArchive
builder.Services.AddScoped<FileService>(); builder.Services.AddScoped<FileService>();
builder.Services.AddScoped<ImageService>(); builder.Services.AddScoped<ImageService>();
builder.Services.AddScoped<MessageOfTheDayService>(); builder.Services.AddScoped<MessageOfTheDayService>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#endregion #endregion
Console.Title = $"RRAC {Constants.Version}";
var app = builder.Build(); var app = builder.Build();
if (app.Environment.IsDevelopment()) app.MapOpenApi();
{
app.MapOpenApi(); app.UseSwagger();
} app.UseSwaggerUI();
app.UseSerilogRequestLogging();
app.UseAuthorization(); app.UseAuthorization();
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2)
};
app.UseWebSockets(webSocketOptions);
app.MapControllers(); app.MapControllers();
app.Run(); app.Run();

View File

@@ -20,4 +20,4 @@
} }
} }
} }
} }

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
@@ -8,6 +8,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="10.1.4" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
</ItemGroup> </ItemGroup>

View File

@@ -6,6 +6,8 @@ namespace RecRoomArchive.Services
{ {
public class AccountService public class AccountService
{ {
public static ulong? AccountId { get; private set; }
public bool AccountExists() public bool AccountExists()
{ {
return File.Exists("data/profile.json"); return File.Exists("data/profile.json");
@@ -13,8 +15,6 @@ namespace RecRoomArchive.Services
public bool CreateAccount(string? username = null) public bool CreateAccount(string? username = null)
{ {
PopulateServerData();
if (string.IsNullOrEmpty(username)) if (string.IsNullOrEmpty(username))
{ {
username = GetRandomUsername(); username = GetRandomUsername();
@@ -38,35 +38,25 @@ namespace RecRoomArchive.Services
return JsonSerializer.Deserialize<BaseProfile>(File.ReadAllText("data/profile.json")); return JsonSerializer.Deserialize<BaseProfile>(File.ReadAllText("data/profile.json"));
} }
public ulong? GetSelfAccountId()
{
if (AccountId.HasValue)
return AccountId;
var profile = JsonSerializer.Deserialize<BaseProfile>(File.ReadAllText("data/profile.json"));
if (profile == null)
return null;
AccountId = profile.Id;
return AccountId;
}
private static string GetRandomUsername() private static string GetRandomUsername()
{ {
int randomFourDigits = RandomNumberGenerator.GetInt32(1000, 9999); int randomFourDigits = RandomNumberGenerator.GetInt32(1000, 9999);
return $"RRA-User_{randomFourDigits}"; return $"RRA-User_{randomFourDigits}";
} }
private static void PopulateServerData()
{
string basePath = "data";
string[] directories = ["rooms", "images", "blobs"];
string[] files = [];
Directory.CreateDirectory(basePath);
foreach (var directory in directories)
{
Directory.CreateDirectory(Path.Combine(basePath, directory));
}
foreach (var file in files)
{
string fullPath = Path.Combine(basePath, file);
if (!File.Exists(fullPath))
{
File.WriteAllText(fullPath, string.Empty);
}
}
}
} }
} }

View File

@@ -1,4 +1,6 @@
namespace RecRoomArchive.Services using RecRoomArchive.Models.Common;
namespace RecRoomArchive.Services
{ {
/// <summary> /// <summary>
/// Used to get the appVersion from the client to determine how to run the server /// Used to get the appVersion from the client to determine how to run the server
@@ -63,6 +65,8 @@
FullBuildTimestamp = buildTimestamp; FullBuildTimestamp = buildTimestamp;
BuildTimestamp = buildTimestampDateTime; BuildTimestamp = buildTimestampDateTime;
Console.Title = $"RRAC {Constants.Version} - ({BuildTimestamp.Value.Year}) {BuildTimestamp.Value}";
Console.WriteLine ($"RRAC {Constants.Version} - ({BuildTimestamp.Value.Year}) {BuildTimestamp.Value}");
Console.WriteLine($"buildTimestamp: {FullBuildTimestamp}, buildTimestampDateTime: {BuildTimestamp}"); Console.WriteLine($"buildTimestamp: {FullBuildTimestamp}, buildTimestampDateTime: {BuildTimestamp}");
return true; return true;

View File

@@ -19,7 +19,7 @@ namespace RecRoomArchive.Services
new(ClaimTypes.Role, "gameClient") new(ClaimTypes.Role, "gameClient")
}; };
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor() SecurityTokenDescriptor tokenDescriptor = new()
{ {
Subject = new ClaimsIdentity(claims), Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.Add(TimeSpan.FromHours(12)), Expires = DateTime.UtcNow.Add(TimeSpan.FromHours(12)),

View File

@@ -17,12 +17,13 @@ namespace RecRoomArchive.Services
public async Task<RecRoomConfig> GetRecRoomConfig() public async Task<RecRoomConfig> GetRecRoomConfig()
{ {
var request = _httpContextAccessor.HttpContext?.Request; var request = _httpContextAccessor.HttpContext?.Request;
var host = $"{request!.Scheme}://{request.Host}"; var cdnHost = $"{request!.Scheme}://{request.Host}";
var motd = await _motdService.GetMessageOfTheDay();
return new RecRoomConfig() return new RecRoomConfig()
{ {
MessageOfTheDay = await _motdService.GetMessageOfTheDay(), MessageOfTheDay = motd,
CdnBaseUri = host, CdnBaseUri = cdnHost,
MatchmakingParams = new MatchmakingParams(), MatchmakingParams = new MatchmakingParams(),
LevelProgressionMaps = LevelProgressionMaps =
[ [

View File

@@ -1,4 +1,5 @@
using System.Xml.Linq; using RecRoomArchive.Models.RRA;
using System.Text.Json;
namespace RecRoomArchive.Services namespace RecRoomArchive.Services
{ {
@@ -9,7 +10,7 @@ namespace RecRoomArchive.Services
string basePath = "data"; string basePath = "data";
string[] directories = ["rooms", "images", "blobs"]; string[] directories = ["rooms", "images", "blobs"];
string[] files = ["rooms.json", "avatar.json", "settings.json", "profile.json"]; string[] files = ["rooms.json", "avatar.json", "settings.json", "profile.json", "avatarItems.json", "serverPreferences.json"];
Directory.CreateDirectory(basePath); Directory.CreateDirectory(basePath);
@@ -28,6 +29,17 @@ namespace RecRoomArchive.Services
} }
} }
} }
public void WriteServerPrefs(bool isComplete)
{
var preferences = new ServerPreferences
{
CompletedSetup = isComplete
};
SetData("serverPreferences.json", JsonSerializer.Serialize(preferences));
}
public string? GetData(string name) public string? GetData(string name)
{ {
var path = $"data/{name}"; var path = $"data/{name}";

View File

@@ -11,7 +11,7 @@ namespace RecRoomArchive.Services
/// <summary> /// <summary>
/// HttpClient for making requests to Gitea /// HttpClient for making requests to Gitea
/// </summary> /// </summary>
private static readonly HttpClient httpClient = new HttpClient(); private static readonly HttpClient httpClient = new();
/// <summary> /// <summary>
/// MessageOfTheDay reference /// MessageOfTheDay reference
@@ -22,16 +22,18 @@ namespace RecRoomArchive.Services
/// Gets the message of the day from Gitea. If the URL cannot be resolved, it will fall back to "Welcome to RecRoomArchive!" /// Gets the message of the day from Gitea. If the URL cannot be resolved, it will fall back to "Welcome to RecRoomArchive!"
/// </summary> /// </summary>
/// <returns>String related to the Message of the Day</returns> /// <returns>String related to the Message of the Day</returns>
public async Task<string> GetMessageOfTheDay(string? version = null) public async Task<string> GetMessageOfTheDay()
{ {
// I wouldn't want to re-request the MOTD from the server a bunch of times... // I wouldn't want to re-request the MOTD from the server a bunch of times...
if (string.IsNullOrEmpty(MessageOfTheDay)) if (string.IsNullOrEmpty(MessageOfTheDay))
{ {
var motd = await httpClient.GetAsync($"https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/MOTD"); //var motd = await httpClient.GetAsync($"https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/MOTD");
if (!motd.IsSuccessStatusCode) //if (!motd.IsSuccessStatusCode)
return "Welcome to RecRoomArchive!"; // return "Welcome to RecRoomArchive!";
MessageOfTheDay = await motd.Content.ReadAsStringAsync(); //MessageOfTheDay = await motd.Content.ReadAsStringAsync();
MessageOfTheDay = "Welcome to RecRoomArchive!";
} }
return MessageOfTheDay; return MessageOfTheDay;
@@ -46,17 +48,19 @@ namespace RecRoomArchive.Services
if (CharadesWordsLastFetchedAt - DateTime.UtcNow > TimeSpan.FromMinutes(30)) if (CharadesWordsLastFetchedAt - DateTime.UtcNow > TimeSpan.FromMinutes(30))
return CachedCharadesWords; return CachedCharadesWords;
var request = await httpClient.GetAsync("https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/CharadesWords"); //var request = await httpClient.GetAsync("https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/CharadesWords");
if (!request.IsSuccessStatusCode) //if (!request.IsSuccessStatusCode)
return []; // return [];
var words = await request.Content.ReadAsStringAsync(); //var words = await request.Content.ReadAsStringAsync();
if (words == null) //if (words == null)
return []; // return [];
CachedCharadesWords = JsonSerializer.Deserialize<List<CharadesWord>>(words)!; return [];
return CachedCharadesWords; //CachedCharadesWords = JsonSerializer.Deserialize<List<CharadesWord>>(words)!;
//return CachedCharadesWords;
} }
} }
} }