Initialize repository
Added basic info to get in game for like...August 2016 ;-; It's not much but it's a start
This commit is contained in:
10
RecRoomArchive.Models/API/Activities/CharadesWord.cs
Normal file
10
RecRoomArchive.Models/API/Activities/CharadesWord.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Activities
|
||||
{
|
||||
public class CharadesWord(string word, CharadesWordsDifficulty difficulty = CharadesWordsDifficulty.Easy)
|
||||
{
|
||||
[JsonPropertyName(name: "Difficulty")] public CharadesWordsDifficulty Difficulty { get; set; } = difficulty;
|
||||
[JsonPropertyName(name: "EN_US")] public string EN_US { get; set; } = word;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace RecRoomArchive.Models.API.Activities
|
||||
{
|
||||
public enum CharadesWordsDifficulty
|
||||
{
|
||||
Easy,
|
||||
Hard
|
||||
}
|
||||
}
|
||||
23
RecRoomArchive.Models/API/Avatar/PlayerAvatar.cs
Normal file
23
RecRoomArchive.Models/API/Avatar/PlayerAvatar.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Avatar
|
||||
{
|
||||
/// <summary>
|
||||
/// The avatar of the player
|
||||
/// </summary>
|
||||
public class PlayerAvatar
|
||||
{
|
||||
/// <summary>
|
||||
/// The outfit that the player has on. This includes data like their hair model, torso, hats, glasses, torso, etc...
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "OutfitSelections")] public string OutfitSelections { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The skin color guid of the player
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "SkinColor")] public string SkinColor { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The hair color guid of the player
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "HairColor")] public string HairColor { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
10
RecRoomArchive.Models/API/Config/DailyObjective.cs
Normal file
10
RecRoomArchive.Models/API/Config/DailyObjective.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class DailyObjective
|
||||
{
|
||||
[JsonPropertyName(name: "type")] public ObjectiveType Type { get; set; }
|
||||
[JsonPropertyName(name: "score")] public int Score { get; set; }
|
||||
}
|
||||
}
|
||||
10
RecRoomArchive.Models/API/Config/GameConfig.cs
Normal file
10
RecRoomArchive.Models/API/Config/GameConfig.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class GameConfig
|
||||
{
|
||||
[JsonPropertyName(name: "Key")] public required string Key { get; set; }
|
||||
[JsonPropertyName(name: "Value")] public required string Value { get; set; }
|
||||
}
|
||||
}
|
||||
10
RecRoomArchive.Models/API/Config/LevelProgressionMap.cs
Normal file
10
RecRoomArchive.Models/API/Config/LevelProgressionMap.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class LevelProgressionMap(int level, int requiredXp)
|
||||
{
|
||||
[JsonPropertyName(name: "Level")] public int Level { get; set; } = level;
|
||||
[JsonPropertyName(name: "RequiredXp")] public int RequiredXp { get; set; } = requiredXp;
|
||||
}
|
||||
}
|
||||
10
RecRoomArchive.Models/API/Config/MatchmakingParams.cs
Normal file
10
RecRoomArchive.Models/API/Config/MatchmakingParams.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class MatchmakingParams
|
||||
{
|
||||
[JsonPropertyName(name: "PreferFullRoomsFrequency")] public float PreferFullRoomsFrequency { get; set; } = 1.0f;
|
||||
[JsonPropertyName(name: "PreferEmptyRoomsFrequency")] public float PreferEmptyRoomsFrequency { get; set; } = 0.0f;
|
||||
}
|
||||
}
|
||||
139
RecRoomArchive.Models/API/Config/ObjectiveType.cs
Normal file
139
RecRoomArchive.Models/API/Config/ObjectiveType.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public enum ObjectiveType
|
||||
{
|
||||
Default = -1,
|
||||
FirstSessionOfDay = 1,
|
||||
AddAFriend,
|
||||
PartyUp,
|
||||
AllOtherChallenges,
|
||||
LevelUp,
|
||||
CheerAPlayer,
|
||||
PointedAtPlayer,
|
||||
CheerARoom,
|
||||
SubscribeToPlayer,
|
||||
DailyObjective1,
|
||||
DailyObjective2,
|
||||
DailyObjective3,
|
||||
AllDailyObjectives,
|
||||
CompleteAnyDaily,
|
||||
CompleteAnyWeekly,
|
||||
OOBE_GoToLockerRoom = 20,
|
||||
OOBE_GoToActivity,
|
||||
OOBE_FinishActivity,
|
||||
NUX_PunchcardObjective = 25,
|
||||
NUX_AllPunchcardObjectives,
|
||||
GoToRecCenter = 30,
|
||||
FinishActivity,
|
||||
VisitACustomRoom,
|
||||
CreateACustomRoom,
|
||||
ScoreBasketInRecCenter = 35,
|
||||
UploadPhotoToRecNet,
|
||||
UpdatePlayerBio,
|
||||
SaveOutfitSlot,
|
||||
PurchaseClothingItem,
|
||||
PurchaseNonClothingItem,
|
||||
DrinkWater,
|
||||
ColorOnWhiteboard,
|
||||
SetBasketballSkin,
|
||||
ThrowBasketball,
|
||||
PlaceInventionInDorm,
|
||||
ChangeDormRoomSkin,
|
||||
ToggleOwnedClothes,
|
||||
EquipHat,
|
||||
LoadOutfit,
|
||||
SaveNewOutfitSlot,
|
||||
SpawnCamera,
|
||||
TakeSelfie,
|
||||
PrintSelfie,
|
||||
TakePictureOfPlayer,
|
||||
PrintPictureOfPlayer,
|
||||
PublishSelfieWithPlayer,
|
||||
SpawnFoodWithOtherPlayers,
|
||||
EmoteInRecCenter,
|
||||
SendRoomChatInRecCenter,
|
||||
UseFrendotron,
|
||||
GoToDormRoom,
|
||||
VisitSpecificRoom,
|
||||
VisitPublicRRO,
|
||||
VisitPublicRoomBySource,
|
||||
FavoriteARoom,
|
||||
TakePhotoWithFilter,
|
||||
OpenYourPlayerProfile,
|
||||
OpenOnlineStatusModal,
|
||||
ChangeProfilePicture,
|
||||
ChangePlayerDisplayName,
|
||||
ChangePlayerDescriptionText,
|
||||
OpenPlayerPronounsModal,
|
||||
OpenOtherPlayersProfile,
|
||||
VisitPlayersPortfolio,
|
||||
FavoriteAFriend,
|
||||
CharadesGames = 100,
|
||||
CharadesWinsPerformer,
|
||||
CharadesWinsGuesser,
|
||||
DiscGolfWins = 200,
|
||||
DiscGolfGames,
|
||||
DiscGolfHolesUnderPar,
|
||||
DodgeballWins = 300,
|
||||
DodgeballGames,
|
||||
DodgeballHits,
|
||||
PaddleballGames = 400,
|
||||
PaddleballWins,
|
||||
PaddleballScores,
|
||||
PaintballAnyModeGames = 500,
|
||||
PaintballAnyModeWins,
|
||||
PaintballAnyModeHits,
|
||||
PaintballCTFWins = 600,
|
||||
PaintballCTFGames,
|
||||
PaintballCTFHits,
|
||||
PaintballFlagCaptures,
|
||||
PaintballTeamBattleWins = 700,
|
||||
PaintballTeamBattleGames,
|
||||
PaintballTeamBattleHits,
|
||||
PaintballFreeForAllWins = 710,
|
||||
PaintballFreeForAllGames,
|
||||
PaintballFreeForAllHits,
|
||||
SoccerWins = 800,
|
||||
SoccerGames,
|
||||
SoccerGoals,
|
||||
BowlingGames = 900,
|
||||
BowlingWins,
|
||||
BowlingStrike,
|
||||
QuestGames = 1000,
|
||||
QuestWins,
|
||||
QuestPlayerRevives,
|
||||
QuestEnemyKills,
|
||||
QuestGames_Goblin1 = 1010,
|
||||
QuestWins_Goblin1,
|
||||
QuestPlayerRevives_Goblin1,
|
||||
QuestEnemyKills_Goblin1,
|
||||
QuestGames_Goblin2 = 1020,
|
||||
QuestWins_Goblin2,
|
||||
QuestPlayerRevives_Goblin2,
|
||||
QuestEnemyKills_Goblin2,
|
||||
QuestGames_Scifi1 = 1030,
|
||||
QuestWins_Scifi1,
|
||||
QuestPlayerRevives_Scifi1,
|
||||
QuestEnemyKills_Scifi1,
|
||||
QuestGames_Pirate1 = 1040,
|
||||
QuestWins_Pirate1,
|
||||
QuestPlayerRevives_Pirate1,
|
||||
QuestEnemyKills_Pirate1,
|
||||
QuestGames_Dracula1 = 1050,
|
||||
QuestWins_Dracula1,
|
||||
QuestPlayerRevives_Dracula1,
|
||||
QuestEnemyKills_Dracula1,
|
||||
ArenaGames = 2000,
|
||||
ArenaWins,
|
||||
ArenaPlayerRevives,
|
||||
ArenaHeroTags,
|
||||
ArenaBotTags,
|
||||
RecRoyaleGames = 3000,
|
||||
RecRoyaleWins,
|
||||
RecRoyaleTags,
|
||||
StuntRunnerGames = 4000,
|
||||
StuntRunnerWins,
|
||||
RecRallyGames = 5000,
|
||||
RecRallyWins
|
||||
}
|
||||
}
|
||||
10
RecRoomArchive.Models/API/Config/PhotonConfig.cs
Normal file
10
RecRoomArchive.Models/API/Config/PhotonConfig.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class PhotonConfig
|
||||
{
|
||||
[JsonPropertyName(name: "CloudRegion")] public string CloudRegion { get; set; } = "us";
|
||||
[JsonPropertyName(name: "CrcCheckEnabled")] public bool CrcCheckEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
16
RecRoomArchive.Models/API/Config/RecRoomConfig.cs
Normal file
16
RecRoomArchive.Models/API/Config/RecRoomConfig.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Config
|
||||
{
|
||||
public class RecRoomConfig
|
||||
{
|
||||
[JsonPropertyName(name: "MessageOfTheDay")] public string MessageOfTheDay { get; set; } = string.Empty;
|
||||
[JsonPropertyName(name: "CdnBaseUri")] public string CdnBaseUri { get; set; } = string.Empty;
|
||||
[JsonPropertyName(name: "MatchmakingParams")] public required MatchmakingParams MatchmakingParams { get; set; }
|
||||
[JsonPropertyName(name: "LevelProgressionMaps")] public required List<LevelProgressionMap> LevelProgressionMaps { get; set; }
|
||||
[JsonPropertyName(name: "DailyObjectives")] public required DailyObjective[][] DailyObjectives { get; set; }
|
||||
[JsonPropertyName(name: "PhotonConfig")] public required PhotonConfig PhotonConfig { get; set; }
|
||||
[JsonPropertyName(name: "ConfigTable")] public required List<GameConfig> ConfigTable { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace RecRoomArchive.Models.API.Messages
|
||||
{
|
||||
public enum GameInviteResponseDetails
|
||||
{
|
||||
Declined,
|
||||
Accepted,
|
||||
ComeToMe,
|
||||
GiveMe2,
|
||||
GiveMe5,
|
||||
GiveMe10
|
||||
}
|
||||
}
|
||||
9
RecRoomArchive.Models/API/Messages/MessageType.cs
Normal file
9
RecRoomArchive.Models/API/Messages/MessageType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace RecRoomArchive.Models.API.Messages
|
||||
{
|
||||
public enum MessageType
|
||||
{
|
||||
GameInvite,
|
||||
GameInviteResponse,
|
||||
GameJoinFailed
|
||||
}
|
||||
}
|
||||
21
RecRoomArchive.Models/API/Platform/PlatformMask.cs
Normal file
21
RecRoomArchive.Models/API/Platform/PlatformMask.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace RecRoomArchive.Models.API.Platform
|
||||
{
|
||||
/// <summary>
|
||||
/// The types of platforms that Rec Room has support for...as a mask!
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum PlatformMask
|
||||
{
|
||||
None = 0,
|
||||
Steam = 1,
|
||||
Oculus = 2,
|
||||
PlayStation = 4,
|
||||
Xbox = 8,
|
||||
RecNet = 16,
|
||||
IOS = 32,
|
||||
GooglePlay = 64,
|
||||
Standalone = 128,
|
||||
Pico = 256,
|
||||
All = -1
|
||||
}
|
||||
}
|
||||
19
RecRoomArchive.Models/API/Platform/PlatformType.cs
Normal file
19
RecRoomArchive.Models/API/Platform/PlatformType.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace RecRoomArchive.Models.API.Platform
|
||||
{
|
||||
/// <summary>
|
||||
/// The types of platforms that Rec Room has support for
|
||||
/// </summary>
|
||||
public enum PlatformType
|
||||
{
|
||||
All = -1,
|
||||
Steam,
|
||||
Oculus,
|
||||
PlayStation,
|
||||
Xbox,
|
||||
RecNet,
|
||||
IOS,
|
||||
GooglePlay,
|
||||
Standalone,
|
||||
Pico
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using RecRoomArchive.Models.API.Platform;
|
||||
|
||||
namespace RecRoomArchive.Models.API.PlatformLogin.Requests
|
||||
{
|
||||
public class BaseLoginRequest
|
||||
{
|
||||
public required PlatformType Platform { get; set; }
|
||||
public required string PlatformId { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public required long ClientTimestamp { get; set; }
|
||||
public required string DeviceId { get; set; }
|
||||
public required long BuildTimestamp { get; set; }
|
||||
public required string AuthParams { get; set; }
|
||||
public required string Verify { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.PlatformLogin.Responses
|
||||
{
|
||||
public class BaseLoginResponse
|
||||
{
|
||||
[JsonPropertyName(name: "Token")]
|
||||
public string Token { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName(name: "PlayerId")]
|
||||
public ulong PlayerId { get; set; }
|
||||
}
|
||||
}
|
||||
44
RecRoomArchive.Models/API/Players/AugustProfile.cs
Normal file
44
RecRoomArchive.Models/API/Players/AugustProfile.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Players
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions of data used in August 2016 Rec Room
|
||||
/// </summary>
|
||||
public class AugustProfile : BaseProfile
|
||||
{
|
||||
public AugustProfile(BaseProfile baseProfile)
|
||||
{
|
||||
Id = baseProfile.Id;
|
||||
Username = baseProfile.Username;
|
||||
DisplayName = baseProfile.DisplayName;
|
||||
XP = baseProfile.XP;
|
||||
Level = baseProfile.Level;
|
||||
Reputation = baseProfile.Reputation;
|
||||
Developer = baseProfile.Developer;
|
||||
Bio = baseProfile.Bio;
|
||||
RegistrationStatus = baseProfile.RegistrationStatus;
|
||||
CanReceiveInvites = baseProfile.CanReceiveInvites;
|
||||
ProfileImageName = baseProfile.ProfileImageName;
|
||||
JuniorProfile = baseProfile.JuniorProfile;
|
||||
ForceJuniorImages = baseProfile.ForceJuniorImages;
|
||||
PendingJunior = baseProfile.PendingJunior;
|
||||
HasBirthday = baseProfile.HasBirthday;
|
||||
HasEmail = baseProfile.HasEmail;
|
||||
AvoidJuniors = baseProfile.AvoidJuniors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in early versions of Rec Room from 2016 as the players DisplayName
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Name")] public string Name => DisplayName;
|
||||
/// <summary>
|
||||
/// The SteamID of the local player, used in 2016
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "SteamID")] public ulong SteamID { get; set; }
|
||||
/// <summary>
|
||||
/// The..gender?? of the local player, this isn't used by Rec Room at all so I'm guessing whoever made their webmanager just added this to add it
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Gender")] public string Gender { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
84
RecRoomArchive.Models/API/Players/BaseProfile.cs
Normal file
84
RecRoomArchive.Models/API/Players/BaseProfile.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Players
|
||||
{
|
||||
/// <summary>
|
||||
/// The profile of the player from 2016-2019
|
||||
/// </summary>
|
||||
public class BaseProfile
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique id of the player
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Id")] public ulong Id { get; set; }
|
||||
/// <summary>
|
||||
/// The username of the player. This usually doesn't show up in game until around 2017...
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Username")] public string Username { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The display name of the player, this is what's most commonly used in game and is seen on the players nametag
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "DisplayName")] public string DisplayName { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The XP of the player, this determines how much XP is required until the next level up but because this is a local server, who gaf
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "XP")] public int XP { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// The level of the player, usually in a range from 1-30 or 1-50 depending on your time period
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Level")] public int Level { get; set; } = 1;
|
||||
/// <summary>
|
||||
/// The internal reputation of the player, reputation works in mysterious ways so I'm not too sure about this one...
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Reputation")] public float Reputation { get; set; } = 1.0f;
|
||||
/// <summary>
|
||||
/// If the player has a verified email on their Rec Room account (which they always will)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Verified")] public bool Verified => RegistrationStatus == RegistrationStatus.Registered;
|
||||
/// <summary>
|
||||
/// If the player is a developer of Rec Room (they always will be)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Developer")] public bool Developer { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The bio of the player, I need to find what build this is added in so I can add it to its model...
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Bio")] public string Bio { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The registration status of the player, determined by if they have an email
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "RegistrationStatus")] public RegistrationStatus RegistrationStatus { get; set; } = RegistrationStatus.Registered;
|
||||
/// <summary>
|
||||
/// If the local player is allowed to recieve invites (junior restriction?)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "CanReceiveInvites")] public bool CanReceiveInvites { get; set; } = true;
|
||||
/// <summary>
|
||||
/// The image name of the player
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "ProfileImageName")] public string ProfileImageName { get; set; } = "DefaultProfileImage";
|
||||
/// <summary>
|
||||
/// If the player is allowed to recieve invites (junior restriction?)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "JuniorProfile")] public bool JuniorProfile { get; set; } = false;
|
||||
/// <summary>
|
||||
/// If the player is forced to only see alt images like a junior player
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "ForceJuniorImages")] public bool ForceJuniorImages { get; set; } = false;
|
||||
/// <summary>
|
||||
/// If the player is about to become a junior
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "PendingJunior")] public bool PendingJunior { get; set; } = false;
|
||||
/// <summary>
|
||||
/// If the player has a birthday on their account
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "HasBirthday")] public bool HasBirthday { get; set; } = true;
|
||||
/// <summary>
|
||||
/// If the player has an email on their account
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "HasEmail")] public bool HasEmail { get; set; } = true;
|
||||
/// <summary>
|
||||
/// If the player perfers to not matchmake with junior players, can be null
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull), JsonPropertyName(name: "AvoidJuniors")] public bool? AvoidJuniors { get; set; }
|
||||
}
|
||||
}
|
||||
9
RecRoomArchive.Models/API/Players/BlockDurationDTO.cs
Normal file
9
RecRoomArchive.Models/API/Players/BlockDurationDTO.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Players
|
||||
{
|
||||
public class BlockDurationDTO
|
||||
{
|
||||
[JsonPropertyName(name: "BlockedDuration")] public int BlockedDuration { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
9
RecRoomArchive.Models/API/Players/PhoneNumberDTO.cs
Normal file
9
RecRoomArchive.Models/API/Players/PhoneNumberDTO.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Players
|
||||
{
|
||||
public class PhoneNumberDTO
|
||||
{
|
||||
[JsonPropertyName(name: "PhoneNumber")] public string PhoneNumber { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
21
RecRoomArchive.Models/API/Players/RegistrationStatus.cs
Normal file
21
RecRoomArchive.Models/API/Players/RegistrationStatus.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace RecRoomArchive.Models.API.Players
|
||||
{
|
||||
/// <summary>
|
||||
/// The status of the players registration to Rec Room
|
||||
/// </summary>
|
||||
public enum RegistrationStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// This player has no email entered for Rec Room and may be prompted to enter one
|
||||
/// </summary>
|
||||
Unregistered,
|
||||
/// <summary>
|
||||
/// This player has a pending email from Rec Room that they have not accepted yet
|
||||
/// </summary>
|
||||
PendingEmailVerification,
|
||||
/// <summary>
|
||||
/// This player has a verified Rec Room Profile!
|
||||
/// </summary>
|
||||
Registered
|
||||
}
|
||||
}
|
||||
19
RecRoomArchive.Models/API/Setting/Setting.cs
Normal file
19
RecRoomArchive.Models/API/Setting/Setting.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.API.Setting
|
||||
{
|
||||
/// <summary>
|
||||
/// The players local settings and preferences
|
||||
/// </summary>
|
||||
public class Setting
|
||||
{
|
||||
/// <summary>
|
||||
/// The key of the setting (ex: DebugGuiEnabled)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Key")] public required string Key { get; set; }
|
||||
/// <summary>
|
||||
/// The value related to the key (ex: true)
|
||||
/// </summary>
|
||||
[JsonPropertyName(name: "Value")] public required string Value { get; set; }
|
||||
}
|
||||
}
|
||||
13
RecRoomArchive.Models/Common/OkResponse.cs
Normal file
13
RecRoomArchive.Models/Common/OkResponse.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RecRoomArchive.Models.Common
|
||||
{
|
||||
public class OkResponse
|
||||
{
|
||||
public static OkResponse Ok(string? message = null) => new() { Success = true, Message = message };
|
||||
public static OkResponse Fail(string message) => new() { Success = false, Message = message };
|
||||
|
||||
[JsonPropertyName("Success")] public bool Success { get; set; }
|
||||
[JsonPropertyName("Message")] public string? Message { get; set; }
|
||||
}
|
||||
}
|
||||
9
RecRoomArchive.Models/RecRoomArchive.Models.csproj
Normal file
9
RecRoomArchive.Models/RecRoomArchive.Models.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
4
RecRoomArchive.slnx
Normal file
4
RecRoomArchive.slnx
Normal file
@@ -0,0 +1,4 @@
|
||||
<Solution>
|
||||
<Project Path="RecRoomArchive.Models/RecRoomArchive.Models.csproj" />
|
||||
<Project Path="RecRoomArchive/RecRoomArchive.csproj" />
|
||||
</Solution>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Activities;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Activities.Charades.V1
|
||||
{
|
||||
[Route(template: "api/[controller]/charades/v1")]
|
||||
[ApiController]
|
||||
public class ActivitiesController(MessageOfTheDayService motdService) : ControllerBase
|
||||
{
|
||||
// TODO: Move out of MOTD service
|
||||
[HttpGet(template: "words")]
|
||||
public async Task<ActionResult<List<CharadesWord>>> GetCharadesWords()
|
||||
{
|
||||
return Ok(await motdService.GetCharadesWordsList());
|
||||
}
|
||||
}
|
||||
}
|
||||
41
RecRoomArchive/Controllers/API/Avatar/V2/AvatarController.cs
Normal file
41
RecRoomArchive/Controllers/API/Avatar/V2/AvatarController.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Avatar;
|
||||
using RecRoomArchive.Services;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Avatar.V2
|
||||
{
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class AvatarController(FileService fileService) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<PlayerAvatar>> GetAvatar()
|
||||
{
|
||||
var avatarData = fileService.GetData("avatar.json");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(avatarData))
|
||||
{
|
||||
var baseAvatar = new PlayerAvatar();
|
||||
fileService.SetData("avatar.json", JsonSerializer.Serialize(baseAvatar));
|
||||
return Ok(baseAvatar);
|
||||
}
|
||||
|
||||
var avatar = JsonSerializer.Deserialize<PlayerAvatar>(avatarData);
|
||||
return Ok(avatar);
|
||||
}
|
||||
|
||||
[HttpGet(template: "gifts")]
|
||||
public async Task<ActionResult<List<object>>> GetPendingGifts()
|
||||
{
|
||||
return Ok(new List<object>());
|
||||
}
|
||||
|
||||
[HttpPost(template: "set")]
|
||||
public async Task<ActionResult<PlayerAvatar>> SetAvatar(PlayerAvatar avatar)
|
||||
{
|
||||
fileService.SetData("avatar.json", JsonSerializer.Serialize(avatar));
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
16
RecRoomArchive/Controllers/API/Avatar/V3/AvatarController.cs
Normal file
16
RecRoomArchive/Controllers/API/Avatar/V3/AvatarController.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Avatar.V3
|
||||
{
|
||||
[Route(template: "api/[controller]/v3")]
|
||||
[ApiController]
|
||||
public class AvatarController() : ControllerBase
|
||||
{
|
||||
// TODO: Implement
|
||||
[HttpGet(template: "items")]
|
||||
public async Task<ActionResult<List<object>>> GetUnlockedAvatarItems()
|
||||
{
|
||||
return Ok(new List<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
34
RecRoomArchive/Controllers/API/Config/V1/ConfigController.cs
Normal file
34
RecRoomArchive/Controllers/API/Config/V1/ConfigController.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Config.V1
|
||||
{
|
||||
/// <summary>
|
||||
/// Configs that control Rec Room. These configs include data like Amplitude, MessageOfTheDay, Objectives, etc...
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]/v1")]
|
||||
[ApiController]
|
||||
public class ConfigController(MessageOfTheDayService motdService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the legacy version of the Message of the Day, to display on the Dorm Room bulletin board, or to show on the login screen in pre-Dorm Room versions of the game
|
||||
/// </summary>
|
||||
/// <returns>A basic string to display in game, related to the Message of the Day</returns>
|
||||
[HttpGet(template: "motd")]
|
||||
public async Task<ActionResult<string>> GetMessageOfTheDay()
|
||||
{
|
||||
var messageOfTheDay = await motdService.GetMessageOfTheDay();
|
||||
return Ok(messageOfTheDay);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current daily objectives to use before config/v2 existed
|
||||
/// </summary>
|
||||
/// <returns>A list of objectives</returns>
|
||||
[HttpGet(template: "objectives")]
|
||||
public async Task<ActionResult<List<object>>> GetDailyObjectives()
|
||||
{
|
||||
return Ok(new List<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
25
RecRoomArchive/Controllers/API/Config/V2/ConfigController.cs
Normal file
25
RecRoomArchive/Controllers/API/Config/V2/ConfigController.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Config;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Config.V2
|
||||
{
|
||||
/// <summary>
|
||||
/// Configs that control Rec Room. These configs include data like Amplitude, MessageOfTheDay, Objectives, etc...
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class ConfigController(ConfigService configService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the RecRoomConfig, containing lots of data on how the game should function
|
||||
/// </summary>
|
||||
/// <returns>RecRoomConfig</returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<RecRoomConfig>> GetRecRoomConfig()
|
||||
{
|
||||
var recRoomConfig = await configService.GetRecRoomConfig();
|
||||
return Ok(recRoomConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
RecRoomArchive/Controllers/API/Images/V2/ImagesController.cs
Normal file
31
RecRoomArchive/Controllers/API/Images/V2/ImagesController.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Players;
|
||||
using RecRoomArchive.Services;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Images.V2
|
||||
{
|
||||
[Route("api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class ImagesController(FileService fileService, ImageService imageService) : ControllerBase
|
||||
{
|
||||
[HttpPost(template: "profile")]
|
||||
public async Task<ActionResult> SetProfileImage(IFormFile image)
|
||||
{
|
||||
using var stream = image.OpenReadStream();
|
||||
var imageName = await imageService.SaveImageAsync(stream);
|
||||
|
||||
var profileData = fileService.GetData("profile.json");
|
||||
if (profileData == null)
|
||||
return BadRequest("Profile is not populated");
|
||||
|
||||
var profile = JsonSerializer.Deserialize<BaseProfile>(profileData)!;
|
||||
|
||||
profile.ProfileImageName = imageName;
|
||||
|
||||
fileService.SetData("profile.json", JsonSerializer.Serialize(profile));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Messages.V2
|
||||
{
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class MessagesController : ControllerBase
|
||||
{
|
||||
[HttpGet(template: "get")]
|
||||
public async Task<ActionResult<List<object>>> GetMessages()
|
||||
{
|
||||
return new List<object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.PlatformLogin.Requests;
|
||||
using RecRoomArchive.Models.API.PlatformLogin.Responses;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.PlatformLogin.V2
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to login to accounts on Rec Room
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[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([FromHeader(Name = "X-Rec-Room-Version")] string appVersion, [FromForm] BaseLoginRequest loginRequest)
|
||||
{
|
||||
var username = loginRequest.Name ?? string.Empty;
|
||||
|
||||
var buildTimestamp = loginRequest.BuildTimestamp;
|
||||
|
||||
// We are going to store the appVersion on login now...
|
||||
await appVersionService.StoreAppVersion(appVersion);
|
||||
await appVersionService.StoreBuildTimestamp(buildTimestamp);
|
||||
|
||||
// See if a profile exists yet...
|
||||
if(!accountService.AccountExists())
|
||||
{
|
||||
// ...if not, create it!
|
||||
accountService.CreateAccount(username);
|
||||
}
|
||||
|
||||
var accountId = accountService.GetSelfAccount()!.Id;
|
||||
|
||||
return Ok(new BaseLoginResponse
|
||||
{
|
||||
Token = authorizationService.GenerateToken(accountId),
|
||||
PlayerId = accountId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
75
RecRoomArchive/Controllers/API/Players/PlayersController.cs
Normal file
75
RecRoomArchive/Controllers/API/Players/PlayersController.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Players;
|
||||
using RecRoomArchive.Services;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Players
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in August 2016 RecNet
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]")]
|
||||
[ApiController]
|
||||
public class PlayersController(AccountService accountService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the profile tied to a SteamID (If it exists)
|
||||
/// </summary>
|
||||
/// <param name="steamId">The SteamID of the player we are trying to get the profile of</param>
|
||||
/// <returns>The profile of the player, if it exists</returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<AugustProfile>> GetProfile([Required, FromQuery] ulong steamId)
|
||||
{
|
||||
var baseProfile = accountService.GetSelfAccount();
|
||||
if (baseProfile == null)
|
||||
return NotFound();
|
||||
|
||||
var profile = new AugustProfile(baseProfile)
|
||||
{
|
||||
SteamID = steamId
|
||||
};
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a profile and links it to a SteamID if the player does not already exist
|
||||
/// </summary>
|
||||
/// <param name="steamId">The SteamID of the player that we are creating a profile for</param>
|
||||
/// <param name="username">The Steam username of the player that we are creating a profile for</param>
|
||||
/// <returns>A new AugustProfile</returns>
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<AugustProfile>> CreateProfile(
|
||||
[Required, FromForm(Name = "SteamID")] ulong steamId,
|
||||
[Required, FromForm(Name = "Name")] string username)
|
||||
{
|
||||
if (!accountService.AccountExists())
|
||||
{
|
||||
accountService.CreateAccount(username);
|
||||
}
|
||||
|
||||
var baseProfile = accountService.GetSelfAccount();
|
||||
if (baseProfile == null)
|
||||
return NotFound();
|
||||
|
||||
var profile = new AugustProfile(baseProfile)
|
||||
{
|
||||
SteamID = steamId
|
||||
};
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores data related to the player onto the server
|
||||
/// </summary>
|
||||
/// <param name="profileId">The Id of the Profile we are storing data for</param>
|
||||
/// <param name="model">The data the client posts...it happens to be an entire profile but we can take only the data we need :)</param>
|
||||
/// <returns>A successful response, likely will just return the updated profile</returns>
|
||||
[HttpPut(template: "{profileId:long}")]
|
||||
public async Task<ActionResult<AugustProfile>> UpdateProfile([Required] ulong profileId, [FromBody] AugustProfile model)
|
||||
{
|
||||
return (AugustProfile)accountService.GetSelfAccount()!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Config;
|
||||
using RecRoomArchive.Models.API.Platform;
|
||||
using RecRoomArchive.Models.API.Players;
|
||||
using RecRoomArchive.Services;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Players.V1
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to get accounts / profiles in 2016-2020 although gets phased out as time goes on...
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]/v1")]
|
||||
[ApiController]
|
||||
public class PlayersController(AccountService accountService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the profile of this ID (If it exists)
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the player we are trying to get the profile of</param>
|
||||
/// <returns>The profile of the player, if it exists</returns>
|
||||
[HttpGet(template: "{id:long}")]
|
||||
public async Task<ActionResult<BaseProfile>> GetProfile([Required] ulong id)
|
||||
{
|
||||
return accountService.GetSelfAccount()!;
|
||||
}
|
||||
|
||||
[HttpPost(template: "listByPlatformId")]
|
||||
public async Task<ActionResult<List<object>>> GetFromServer([FromForm] PlatformType platform, [FromForm] List<ulong> platformIds)
|
||||
{
|
||||
return Ok(new List<object>());
|
||||
}
|
||||
|
||||
[HttpGet(template: "search/{query}")]
|
||||
public async Task<ActionResult<List<BaseProfile>>> SearchForProfiles(string query)
|
||||
{
|
||||
return Ok(new List<BaseProfile>());
|
||||
}
|
||||
|
||||
[HttpGet(template: "phoneLastFour")]
|
||||
public async Task<ActionResult<PhoneNumberDTO>> GetPhoneLastFour()
|
||||
{
|
||||
return Ok(new PhoneNumberDTO());
|
||||
}
|
||||
|
||||
[HttpGet(template: "blockDuration")]
|
||||
public async Task<ActionResult<BlockDurationDTO>> GetBlockDuration()
|
||||
{
|
||||
return Ok(new BlockDurationDTO());
|
||||
}
|
||||
|
||||
[HttpPost(template: "objectives")]
|
||||
public async Task<ActionResult> CompleteObjectives(object objective)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Players;
|
||||
using RecRoomArchive.Models.Common;
|
||||
using RecRoomArchive.Services;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Players.V2
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to modify accounts / profiles in 2017-2019 although gets phased out as time goes on...
|
||||
/// </summary>
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class PlayersController(FileService fileService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the players displayName
|
||||
/// </summary>
|
||||
/// <param name="name">The displayName the player is requesting</param>
|
||||
/// <returns>OkResponse</returns>
|
||||
[HttpPost(template: "displayName")]
|
||||
public async Task<ActionResult<OkResponse>> SetDisplayName([FromForm(Name = "Name")] string name)
|
||||
{
|
||||
var profileData = fileService.GetData("profile.json");
|
||||
if (profileData == null)
|
||||
return BadRequest("Profile is not populated");
|
||||
|
||||
var profile = JsonSerializer.Deserialize<BaseProfile>(profileData)!;
|
||||
|
||||
profile.DisplayName = name;
|
||||
|
||||
fileService.SetData("profile.json", JsonSerializer.Serialize(profile));
|
||||
|
||||
return Ok(OkResponse.Ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Relationships.V2
|
||||
{
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class RelationshipsController : ControllerBase
|
||||
{
|
||||
[HttpGet(template: "get")]
|
||||
public async Task<ActionResult<List<object>>> GetRelationships()
|
||||
{
|
||||
return new List<object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Models.API.Avatar;
|
||||
using RecRoomArchive.Models.API.Setting;
|
||||
using RecRoomArchive.Services;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.Settings.V2
|
||||
{
|
||||
[Route(template: "api/[controller]/v2")]
|
||||
[ApiController]
|
||||
public class SettingsController(FileService fileService) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<Setting>>> GetSettings()
|
||||
{
|
||||
var settingsData = fileService.GetData("settings.json");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(settingsData))
|
||||
{
|
||||
return Ok(new List<Setting>());
|
||||
}
|
||||
|
||||
var settings = JsonSerializer.Deserialize<List<Setting>>(settingsData);
|
||||
return Ok(settings);
|
||||
}
|
||||
|
||||
[HttpPost(template: "set")]
|
||||
public async Task<ActionResult> SetSetting(Setting setting)
|
||||
{
|
||||
var settingsData = fileService.GetData("settings.json");
|
||||
|
||||
var settings = string.IsNullOrWhiteSpace(settingsData) ? [] : JsonSerializer.Deserialize<List<Setting>>(settingsData) ?? [];
|
||||
|
||||
settings.RemoveAll(x => x.Key == setting.Key);
|
||||
settings.Add(setting);
|
||||
|
||||
fileService.SetData("settings.json", JsonSerializer.Serialize(settings));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers.API.VersionCheck.V1
|
||||
{
|
||||
/// <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]/v1")]
|
||||
[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>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>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> CheckVersion([FromHeader(Name = "X-Rec-Room-Version")] string appVersion)
|
||||
{
|
||||
if (appVersion == null)
|
||||
return Forbid();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
RecRoomArchive/Controllers/Images/RootController.cs
Normal file
22
RecRoomArchive/Controllers/Images/RootController.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Services;
|
||||
using System.Net.Mime;
|
||||
|
||||
namespace RecRoomArchive.Controllers.Images
|
||||
{
|
||||
[Route("img")]
|
||||
[ApiController]
|
||||
public class RootController(ImageService imageService) : ControllerBase
|
||||
{
|
||||
[HttpGet(template: "{imageName}")]
|
||||
public async Task<IActionResult> GetImage(string imageName)
|
||||
{
|
||||
var image = await imageService.GetImage(imageName);
|
||||
|
||||
if (image == null)
|
||||
return NotFound();
|
||||
|
||||
return File(image, MediaTypeNames.Image.Png);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RecRoomArchive/Controllers/RootController.cs
Normal file
23
RecRoomArchive/Controllers/RootController.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Only exists for pre-RecNet versions of Rec Room to be able to fetch a Message of the Day from the server...
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
public class RootController(MessageOfTheDayService motdService) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the legacy version of the Message of the Day, to display on the login screen in pre-Dorm Room versions of the game
|
||||
/// </summary>
|
||||
/// <returns>A basic string to display in game, related to the Message of the Day</returns>
|
||||
[HttpGet(template: "motd")]
|
||||
public async Task<ActionResult<string>> GetMessageOfTheDay()
|
||||
{
|
||||
var messageOfTheDay = await motdService.GetMessageOfTheDay();
|
||||
return Ok(messageOfTheDay);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
RecRoomArchive/Program.cs
Normal file
40
RecRoomArchive/Program.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
using RecRoomArchive.Services;
|
||||
|
||||
namespace RecRoomArchive
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
#region Services
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
builder.Services.AddScoped<AccountService>();
|
||||
builder.Services.AddScoped<AppVersionService>();
|
||||
builder.Services.AddScoped<AuthorizationService>();
|
||||
builder.Services.AddScoped<ConfigService>();
|
||||
builder.Services.AddScoped<FileService>();
|
||||
builder.Services.AddScoped<ImageService>();
|
||||
builder.Services.AddScoped<MessageOfTheDayService>();
|
||||
#endregion
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RecRoomArchive/Properties/launchSettings.json
Normal file
23
RecRoomArchive/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5090",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7040;http://localhost:5090",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
RecRoomArchive/RecRoomArchive.csproj
Normal file
18
RecRoomArchive/RecRoomArchive.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RecRoomArchive.Models\RecRoomArchive.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
6
RecRoomArchive/RecRoomArchive.http
Normal file
6
RecRoomArchive/RecRoomArchive.http
Normal file
@@ -0,0 +1,6 @@
|
||||
@RecRoomArchive_HostAddress = http://localhost:5090
|
||||
|
||||
GET {{RecRoomArchive_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
72
RecRoomArchive/Services/AccountService.cs
Normal file
72
RecRoomArchive/Services/AccountService.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using RecRoomArchive.Models.API.Players;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
public class AccountService
|
||||
{
|
||||
public bool AccountExists()
|
||||
{
|
||||
return File.Exists("data/profile.json");
|
||||
}
|
||||
|
||||
public bool CreateAccount(string? username = null)
|
||||
{
|
||||
PopulateServerData();
|
||||
|
||||
if (string.IsNullOrEmpty(username))
|
||||
{
|
||||
username = GetRandomUsername();
|
||||
}
|
||||
|
||||
Console.WriteLine($"Creating account for {username}");
|
||||
|
||||
var profile = new BaseProfile
|
||||
{
|
||||
Id = (ulong)RandomNumberGenerator.GetInt32(1000, 9999999),
|
||||
Username = username,
|
||||
DisplayName = username
|
||||
};
|
||||
|
||||
File.WriteAllText("data/profile.json", JsonSerializer.Serialize(profile));
|
||||
return File.Exists("data/profile.json");
|
||||
}
|
||||
|
||||
public BaseProfile? GetSelfAccount()
|
||||
{
|
||||
return JsonSerializer.Deserialize<BaseProfile>(File.ReadAllText("data/profile.json"));
|
||||
}
|
||||
|
||||
private static string GetRandomUsername()
|
||||
{
|
||||
int randomFourDigits = RandomNumberGenerator.GetInt32(1000, 9999);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
RecRoomArchive/Services/AppVersionService.cs
Normal file
85
RecRoomArchive/Services/AppVersionService.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to get the appVersion from the client to determine how to run the server
|
||||
/// </summary>
|
||||
public class AppVersionService
|
||||
{
|
||||
/// <summary>
|
||||
/// AppVersion reference
|
||||
/// </summary>
|
||||
private static string? AppVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The AppVersion as it would want to be seen by the game
|
||||
/// </summary>
|
||||
private static string? FullAppVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The BuildTimestamp of the build, this is a long that when converted to ticks, will be the accurate time at which the game was built.
|
||||
/// This only exists on some builds so I wouldn't rely on it too much
|
||||
/// </summary>
|
||||
private static DateTime? BuildTimestamp { get; set; }
|
||||
/// <summary>
|
||||
/// The BuildTimestamp as it would want to be seen by the game
|
||||
/// </summary>
|
||||
private static long? FullBuildTimestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// To store the AppVersion of the current build
|
||||
/// </summary>
|
||||
/// <param name="appVersion">The version of the game</param>
|
||||
/// <returns>If the operation was a success</returns>
|
||||
public async Task<bool> StoreAppVersion(string appVersion)
|
||||
{
|
||||
if (appVersion == null)
|
||||
return false;
|
||||
|
||||
// To remove any _EA's or .01's or just any weird Rec Room bullshit from the build's name
|
||||
var standardizedAppVersion = await ParseAppVersion(appVersion);
|
||||
|
||||
// idrk if storing both of these is overkill
|
||||
FullAppVersion = appVersion;
|
||||
AppVersion = standardizedAppVersion;
|
||||
|
||||
Console.WriteLine($"appVersion: {FullAppVersion}, standardizedAppVersion: {AppVersion}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To store the BuildTimestamp of the current build
|
||||
/// </summary>
|
||||
/// <param name="buildTimestamp">The BuildTimestamp of the game</param>
|
||||
/// <returns>If the operation was a success</returns>
|
||||
public async Task<bool> StoreBuildTimestamp(long buildTimestamp)
|
||||
{
|
||||
if (buildTimestamp == 0)
|
||||
return false;
|
||||
|
||||
DateTime buildTimestampDateTime = new(buildTimestamp);
|
||||
|
||||
// same here
|
||||
FullBuildTimestamp = buildTimestamp;
|
||||
BuildTimestamp = buildTimestampDateTime;
|
||||
|
||||
Console.WriteLine($"buildTimestamp: {FullBuildTimestamp}, buildTimestampDateTime: {BuildTimestamp}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the appVersion to "remove any _EA's or .01's or just any weird Rec Room bullshit from the build's name"
|
||||
/// </summary>
|
||||
/// <param name="appVersion">The version of the game</param>
|
||||
/// <returns>The standardized string of the appVersion</returns>
|
||||
public async Task<string> ParseAppVersion(string appVersion)
|
||||
{
|
||||
// To remove any _EA's or .01's or just any weird Rec Room bullshit from the build's name
|
||||
int index = appVersion.IndexOfAny(['_', '.']);
|
||||
string standardizedAppVersion = index >= 0 ? appVersion[..index] : appVersion;
|
||||
|
||||
return standardizedAppVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
RecRoomArchive/Services/AuthorizationService.cs
Normal file
34
RecRoomArchive/Services/AuthorizationService.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
public class AuthorizationService
|
||||
{
|
||||
private static readonly string Key = "hello diddy blud. you need to replace me. or not, really it doesnt matter...I forgot how long a token like this has to be so I'm just gonna run my mouth. Hi. This is RecRoomArchive. You may wonder why we have JWT tokens in a localhost server, and that's because 2020 requires it and stuff. and 2019. Especially 2021. I wonder if I will be doing 2021 or not...";
|
||||
|
||||
public string GenerateToken(ulong id)
|
||||
{
|
||||
JwtSecurityTokenHandler handler = new();
|
||||
|
||||
List<Claim> claims = new List<Claim>()
|
||||
{
|
||||
new(ClaimTypes.NameIdentifier, id.ToString()),
|
||||
new(ClaimTypes.Role, "gameClient")
|
||||
};
|
||||
|
||||
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor()
|
||||
{
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.UtcNow.Add(TimeSpan.FromHours(12)),
|
||||
Issuer = "https://recroomarchive.org/",
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Key)), SecurityAlgorithms.HmacSha256)
|
||||
};
|
||||
|
||||
JwtSecurityToken token = handler.CreateJwtSecurityToken(tokenDescriptor);
|
||||
return handler.WriteToken(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
188
RecRoomArchive/Services/ConfigService.cs
Normal file
188
RecRoomArchive/Services/ConfigService.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using RecRoomArchive.Models.API.Config;
|
||||
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// I don't even want to explain this one. I'm sorry
|
||||
/// </summary>
|
||||
public class ConfigService(MessageOfTheDayService motdService, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
private readonly MessageOfTheDayService _motdService = motdService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// I'm only doing this because I think that having the full Rec Room config in a controller would be very very ugly.
|
||||
/// </summary>
|
||||
/// <returns>RecRoomConfig</returns>
|
||||
public async Task<RecRoomConfig> GetRecRoomConfig()
|
||||
{
|
||||
var request = _httpContextAccessor.HttpContext?.Request;
|
||||
var host = $"{request!.Scheme}://{request.Host}";
|
||||
|
||||
return new RecRoomConfig()
|
||||
{
|
||||
MessageOfTheDay = await _motdService.GetMessageOfTheDay(),
|
||||
CdnBaseUri = host,
|
||||
MatchmakingParams = new MatchmakingParams(),
|
||||
LevelProgressionMaps =
|
||||
[
|
||||
new LevelProgressionMap(0, 0),
|
||||
new LevelProgressionMap(1, 10),
|
||||
new LevelProgressionMap(2, 10),
|
||||
new LevelProgressionMap(3, 10),
|
||||
new LevelProgressionMap(4, 20),
|
||||
new LevelProgressionMap(5, 20),
|
||||
new LevelProgressionMap(6, 20),
|
||||
new LevelProgressionMap(7, 20),
|
||||
new LevelProgressionMap(8, 20),
|
||||
new LevelProgressionMap(9, 20),
|
||||
new LevelProgressionMap(10, 20),
|
||||
new LevelProgressionMap(11, 45),
|
||||
new LevelProgressionMap(12, 45),
|
||||
new LevelProgressionMap(13, 45),
|
||||
new LevelProgressionMap(14, 45),
|
||||
new LevelProgressionMap(15, 45),
|
||||
new LevelProgressionMap(16, 45),
|
||||
new LevelProgressionMap(17, 45),
|
||||
new LevelProgressionMap(18, 45),
|
||||
new LevelProgressionMap(19, 45),
|
||||
new LevelProgressionMap(20, 45),
|
||||
new LevelProgressionMap(21, 115),
|
||||
new LevelProgressionMap(22, 115),
|
||||
new LevelProgressionMap(23, 115),
|
||||
new LevelProgressionMap(24, 115),
|
||||
new LevelProgressionMap(25, 115),
|
||||
new LevelProgressionMap(26, 115),
|
||||
new LevelProgressionMap(27, 115),
|
||||
new LevelProgressionMap(28, 115),
|
||||
new LevelProgressionMap(29, 115),
|
||||
new LevelProgressionMap(30, 115)
|
||||
],
|
||||
DailyObjectives =
|
||||
[
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestGames_Scifi1,
|
||||
Score = 1
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestEnemyKills_Scifi1,
|
||||
Score = 10
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.ArenaGames,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.PaintballCTFGames,
|
||||
Score = 2
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.FinishActivity,
|
||||
Score = 1
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.CheerAPlayer,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.DodgeballGames,
|
||||
Score = 2
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.DodgeballWins,
|
||||
Score = 2
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.CheerAPlayer,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.PaintballTeamBattleWins,
|
||||
Score = 2
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.PaintballTeamBattleGames,
|
||||
Score = 20
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.FinishActivity,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestGames_Goblin1,
|
||||
Score = 1
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestEnemyKills_Goblin1,
|
||||
Score = 10
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.CheerAPlayer,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.PaintballAnyModeGames,
|
||||
Score = 2
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.PaintballAnyModeHits,
|
||||
Score = 20
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.ArenaGames,
|
||||
Score = 1
|
||||
}
|
||||
],
|
||||
[
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestGames_Goblin2,
|
||||
Score = 1
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.QuestEnemyKills_Goblin2,
|
||||
Score = 10
|
||||
},
|
||||
new DailyObjective()
|
||||
{
|
||||
Type = ObjectiveType.FinishActivity,
|
||||
Score = 1
|
||||
}
|
||||
]
|
||||
],
|
||||
ConfigTable = [],
|
||||
PhotonConfig = new PhotonConfig()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
58
RecRoomArchive/Services/FileService.cs
Normal file
58
RecRoomArchive/Services/FileService.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
public class FileService
|
||||
{
|
||||
private static void PopulateServerData()
|
||||
{
|
||||
string basePath = "data";
|
||||
|
||||
string[] directories = ["rooms", "images", "blobs"];
|
||||
string[] files = ["rooms.json", "avatar.json", "settings.json", "profile.json"];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public string? GetData(string name)
|
||||
{
|
||||
var path = $"data/{name}";
|
||||
|
||||
if (!File.Exists(path))
|
||||
return null;
|
||||
|
||||
return File.ReadAllText(path);
|
||||
}
|
||||
|
||||
public void SetData(string name, string data)
|
||||
{
|
||||
var path = $"data/{name}";
|
||||
|
||||
File.WriteAllText(path, data);
|
||||
}
|
||||
|
||||
public bool FileExists(string name)
|
||||
{
|
||||
var path = $"data/{name}";
|
||||
|
||||
if (!File.Exists(path))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
RecRoomArchive/Services/ImageService.cs
Normal file
44
RecRoomArchive/Services/ImageService.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
public class ImageService(FileService fileService)
|
||||
{
|
||||
private static readonly HttpClient httpClient = new();
|
||||
|
||||
private readonly FileService _fileService = fileService;
|
||||
|
||||
public async Task<Stream?> GetImage(string imageName)
|
||||
{
|
||||
var path = $"images/{imageName}";
|
||||
|
||||
if (!_fileService.FileExists(path))
|
||||
{
|
||||
var response = await httpClient.GetAsync($"https://cdn.rec.net/img/{imageName}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
return await response.Content.ReadAsStreamAsync();
|
||||
}
|
||||
|
||||
return new FileStream(Path.Combine("data", path), FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
}
|
||||
|
||||
public async Task<string> SaveImageAsync(Stream imageStream)
|
||||
{
|
||||
var imageName = $"{GetRandomFileName()}.jpg";
|
||||
|
||||
var path = ("data/images");
|
||||
var fullPath = Path.Combine(path, imageName);
|
||||
|
||||
await using var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 81920, useAsync: true);
|
||||
|
||||
await imageStream.CopyToAsync(fileStream);
|
||||
|
||||
return imageName;
|
||||
}
|
||||
|
||||
private static string GetRandomFileName()
|
||||
{
|
||||
return Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('+', '-').Replace('/', '_').TrimEnd('=');
|
||||
}
|
||||
}
|
||||
}
|
||||
62
RecRoomArchive/Services/MessageOfTheDayService.cs
Normal file
62
RecRoomArchive/Services/MessageOfTheDayService.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using RecRoomArchive.Models.API.Activities;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RecRoomArchive.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service used to get the message of the day as it is used in multiple areas of the server
|
||||
/// </summary>
|
||||
public class MessageOfTheDayService
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpClient for making requests to Gitea
|
||||
/// </summary>
|
||||
private static readonly HttpClient httpClient = new HttpClient();
|
||||
|
||||
/// <summary>
|
||||
/// MessageOfTheDay reference
|
||||
/// </summary>
|
||||
private static string? MessageOfTheDay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message of the day from Gitea. If the URL cannot be resolved, it will fall back to "Welcome to RecRoomArchive!"
|
||||
/// </summary>
|
||||
/// <returns>String related to the Message of the Day</returns>
|
||||
public async Task<string> GetMessageOfTheDay(string? version = null)
|
||||
{
|
||||
// I wouldn't want to re-request the MOTD from the server a bunch of times...
|
||||
if (string.IsNullOrEmpty(MessageOfTheDay))
|
||||
{
|
||||
var motd = await httpClient.GetAsync($"https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/MOTD");
|
||||
if (!motd.IsSuccessStatusCode)
|
||||
return "Welcome to RecRoomArchive!";
|
||||
|
||||
MessageOfTheDay = await motd.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
return MessageOfTheDay;
|
||||
}
|
||||
|
||||
// move out of motdservice
|
||||
private DateTime CharadesWordsLastFetchedAt { get; set; }
|
||||
private List<CharadesWord> CachedCharadesWords { get; set; } = [];
|
||||
|
||||
public async Task <List<CharadesWord>> GetCharadesWordsList()
|
||||
{
|
||||
if (CharadesWordsLastFetchedAt - DateTime.UtcNow > TimeSpan.FromMinutes(30))
|
||||
return CachedCharadesWords;
|
||||
|
||||
var request = await httpClient.GetAsync("https://git.recroomarchive.org/RecRoomArchive/RRAC/raw/branch/main/CharadesWords");
|
||||
if (!request.IsSuccessStatusCode)
|
||||
return [];
|
||||
|
||||
var words = await request.Content.ReadAsStringAsync();
|
||||
if (words == null)
|
||||
return [];
|
||||
|
||||
CachedCharadesWords = JsonSerializer.Deserialize<List<CharadesWord>>(words)!;
|
||||
|
||||
return CachedCharadesWords;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
RecRoomArchive/appsettings.Development.json
Normal file
8
RecRoomArchive/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
RecRoomArchive/appsettings.json
Normal file
9
RecRoomArchive/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
1
RecRoomArchive/data/avatar.json
Normal file
1
RecRoomArchive/data/avatar.json
Normal file
@@ -0,0 +1 @@
|
||||
{"OutfitSelections":"e36bcd98-7e85-43fa-89f8-57e4ec33823a,,,,0;c6c08eb5-381a-4193-9722-80da95d62abe,,,,1;d0a9262f-5504-46a7-bb10-7507503db58e,,,,1;40528de7-38a3-4a7c-8f93-6d3bfa5573f2,dee70c38-7a99-4c2b-9181-665f1bf75aca,018a5c07-e956-457d-a540-a5e2cd68da09,,0","SkinColor":"2d398478-37c4-4c4a-a471-fbcbe3e5b1f5","HairColor":"5e51ac88-e365-418b-a303-8737fd2e6bc8"}
|
||||
BIN
RecRoomArchive/data/images/Mh6wZ4jA6k2bx-nwb__YnA.jpg
Normal file
BIN
RecRoomArchive/data/images/Mh6wZ4jA6k2bx-nwb__YnA.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
BIN
RecRoomArchive/data/images/VH-K69qfP0S4R7SvLq8Vtw.jpg
Normal file
BIN
RecRoomArchive/data/images/VH-K69qfP0S4R7SvLq8Vtw.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
BIN
RecRoomArchive/data/images/Wc_cH1llykak2uqyNvgY_w.jpg
Normal file
BIN
RecRoomArchive/data/images/Wc_cH1llykak2uqyNvgY_w.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
RecRoomArchive/data/images/wn5ZWdnp-Ea0inPtIOQPmg.jpg
Normal file
BIN
RecRoomArchive/data/images/wn5ZWdnp-Ea0inPtIOQPmg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
1
RecRoomArchive/data/profile.json
Normal file
1
RecRoomArchive/data/profile.json
Normal file
@@ -0,0 +1 @@
|
||||
{"Id":1775080,"Username":"splootybean","DisplayName":"city boy","XP":0,"Level":1,"Reputation":1,"Verified":true,"Developer":true,"Bio":"","RegistrationStatus":2,"CanReceiveInvites":true,"ProfileImageName":"Mh6wZ4jA6k2bx-nwb__YnA.jpg","JuniorProfile":false,"ForceJuniorImages":false,"PendingJunior":false,"HasBirthday":true,"HasEmail":true}
|
||||
1
RecRoomArchive/data/settings.json
Normal file
1
RecRoomArchive/data/settings.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"Key":"google_analytics_clientid_pref_key","Value":"JPOTDRUNb2592478225be25d5b5950fcf20d6f2601e231d2"},{"Key":"DAILY_LOGIN_DATE","Value":"57"},{"Key":"OBJECTIVE_DATE","Value":"57"},{"Key":"OBJECTIVE_PROGRESS0","Value":"1"},{"Key":"OBJECTIVE_COMPLETED0","Value":"1"},{"Key":"OBJECTIVE_PROGRESS1","Value":"0"},{"Key":"OBJECTIVE_COMPLETED1","Value":"0"},{"Key":"OBJECTIVE_PROGRESS2","Value":"0"},{"Key":"OBJECTIVE_COMPLETED2","Value":"0"},{"Key":"Recroom.OOBE","Value":"10"},{"Key":"PlayerSessionCount","Value":"10"}]
|
||||
Reference in New Issue
Block a user