This commit is contained in:
Exception
2026-05-09 14:31:53 -04:00
parent ad3fa51fd9
commit 1f113298e0
251 changed files with 100454 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CampusCardController : ControllerBase
{
private readonly jwt _jwt;
public CampusCardController(jwt __jwt)
{
_jwt = __jwt;
}
[HttpPost("v1/UpdateAndGetSubscription")]
public IActionResult getMySub()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"]);
if (accountId == null) return Unauthorized();
return Ok(new
{
CanBuySubscription = true,
PlatformAccountSubscribedPlayerId = accountId,
Subscription = new
{
CreatedAt = DateTime.UtcNow,
ExpirationDate = DateTime.UtcNow.AddDays(67),
IsActive = true,
IsAutoRenewing = true,
Level = 0,
ModifiedAt = DateTime.UtcNow.AddHours(1),
Period = 0,
PlatformId = "67",
PlatformPurchaseId = "0",
PlatformType = 0,
RecNetPlayerId = accountId,
SubscriptionId = 0
}
});
}
}
}
+55
View File
@@ -0,0 +1,55 @@
using DeluxeNET.Models.ServerConfiguration;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("/")]
[ApiController]
public class NameServerController : ControllerBase
{
private string BaseURL = "https://localhost";
[HttpGet]
public ActionResult<NameServerModel> NameServer()
{
return Ok(new NameServerModel
{
Accounts = BaseURL,
API = BaseURL,
Auth = BaseURL,
BugReporting = BaseURL,
Cards = BaseURL,
CDN = BaseURL+"/cdnserver",
Chat = BaseURL,
Clubs = BaseURL,
CMS = BaseURL,
Commerce = BaseURL,
Data = BaseURL,
DataCollection = BaseURL,
Discovery = BaseURL,
Econ = BaseURL,
GameLogs = BaseURL,
Geo = BaseURL,
Images = BaseURL+"/imageserver",
Leaderboard = BaseURL,
Link = BaseURL,
Lists = BaseURL,
Matchmaking = BaseURL,
Moderation = BaseURL,
Notifications = BaseURL,
PlatformNotifications = BaseURL,
PlayerSettings = BaseURL,
RoomComments = BaseURL,
Rooms = BaseURL+"/roomserver",
Storage = BaseURL+"/cdnserver",
Strings = BaseURL,
StringsCDN = BaseURL+"/cdnserver",
Studio = BaseURL,
Thorn = BaseURL,
Videos = BaseURL,
WWW = BaseURL
});
}
}
}
+34
View File
@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PlayerReportingController : ControllerBase
{
[HttpGet("v1/moderationBlockDetails")]
public IActionResult modblockdetails()
{
return Ok(new
{
ReportCategory = 0,
Duration = 0,
GameSessionId = 0,
Message = ""
});
}
[HttpPost("v1/hile")]
public IActionResult hile()
{
return Ok(false);
}
[HttpGet("v1/voteToKickReasons")]
public IActionResult vtkr()
{
return Ok(new List<object>());
}
}
}
+72
View File
@@ -0,0 +1,72 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class accountController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
public accountController(AppDbContext db, jwt __jwt)
{
_db = db;
_jwt = __jwt;
}
[HttpGet("bulk")]
public async Task<IActionResult> BulkAccountDetails([FromQuery] List<long> id)
{
var accounts = await _db.Accounts
.Where(x => id.Contains(x.accountId))
.ToListAsync();
return Ok(accounts);
}
[HttpGet("me")]
public async Task<IActionResult> getMyAccountDetails()
{
foreach (var key in Request.Headers.Keys)
{
Console.WriteLine($"{key} = {Request.Headers[key]}");
}
Console.WriteLine(Request.Headers["Authorization"].ToString());
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
var userdetails = await _db.Accounts
.FirstOrDefaultAsync(x => x.accountId == accountId);
return Ok(userdetails);
}
[HttpGet("{playerid}/bio")]
public async Task<IActionResult> getPlayerBio([FromRoute] long playerid)
{
var player = await _db.Accounts
.FirstOrDefaultAsync(x => x.accountId == playerid);
return Ok(new
{
accountId = playerid,
bio = player.bio ?? null
});
}
}
}
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class accountprivacysettingsController : ControllerBase
{
[HttpGet("{playerid}")]
public IActionResult getAccountPrivacy([FromRoute] long playerid)
{
return Ok(new
{
accountId = playerid,
isRecentHistoryVisible = true
});
}
}
}
+17
View File
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class announcementController : ControllerBase
{
[HttpGet("v1/get")]
public IActionResult v1g()
{
return Ok(new List<object>());
}
}
}
+17
View File
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class announcementsController : ControllerBase
{
[HttpGet("v2/mine/unread")]
[HttpGet("v2/subscription/mine/unread")]
public IActionResult fjweiio()
{
return Ok(new List<object>());
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using DeluxeNET.Data;
using DeluxeNET.Jsons;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System.Reflection.Metadata.Ecma335;
using System.Threading.Tasks;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class avatarController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
public avatarController(AppDbContext db, jwt jwt)
{
_db = db;
_jwt = jwt;
}
[HttpGet("v1/defaultunlocked")]
public IActionResult getDefaultUnlockedAvatarITems()
{
return Ok(new List<object>());
}
[HttpGet("v1/defaultbaseavataritems")]
public IActionResult getDefaultBaseItems()
{
return Ok(new List<object>());
}
[HttpGet("v4/items")]
public IActionResult getUnlockedAvatarItems()
{
var clothingfile = System.IO.File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "Jsons", "clothing.json"));
var clothing = JsonConvert.DeserializeObject<List<avatarItem>>(clothingfile);
return Ok(clothing);
}
[HttpGet("v2")]
public async Task<IActionResult> getMyAvatar()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"]);
if (accountId == null) return Unauthorized();
var avatardetails = await _db.Avatars
.FirstOrDefaultAsync(x => x.accountId == accountId);
if (avatardetails == null)
{
_db.Avatars.Add(new avatar
{
accountId = accountId
});
await _db.SaveChangesAsync();
avatardetails = new avatar
{
Id = 67,
accountId = accountId,
OutfitSelections = "",
FaceFeatures = "",
SkinColor = "",
HairColor = ""
};
}
return Ok(avatardetails);
}
[HttpGet("v3/saved")]
public IActionResult getsavedoutfits()
{
return Ok(new List<object>());
}
[HttpGet("v2/gifts")]
public IActionResult getGifts()
{
return Ok(new List<object>());
}
[HttpPost("v2/set")]
public IActionResult setAvatar()
{
return Ok();
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using DeluxeNET.Data;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class cachedloginController : ControllerBase
{
private readonly AppDbContext _db;
public cachedloginController(AppDbContext db)
{
_db = db;
}
[HttpGet("forplatformid/{platform}/{platformid}")]
public async Task<IActionResult> GetCachedLogins([FromRoute] int platform, [FromRoute] string platformid)
{
var cachedlogins = await _db.CachedLogins
.Where(x => x.platformId == platformid && x.platform == platform)
.ToListAsync();
return Ok(cachedlogins);
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class cdnserverController : ControllerBase
{
[HttpGet("config/LoadingScreenTipData")]
public IActionResult getthestupideitiowetiewj()
{
return Ok(new List<object>());
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class checklistController : ControllerBase
{
[HttpGet("v1/current")]
public IActionResult getMyStfehfowoji()
{
return Ok(new List<object>());
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class communityboardController : ControllerBase
{
[HttpGet("v2/current")]
public async Task<IActionResult> getcb()
{
var j = JsonConvert.DeserializeObject(await System.IO.File.ReadAllTextAsync(Path.Combine(Directory.GetCurrentDirectory(), "Jsons", "communityboard.json")));
return Ok(j);
}
}
}
+55
View File
@@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class configController : ControllerBase
{
[HttpGet("v1/amplitude")]
public IActionResult getAmpl()
{
return Ok(new
{
AmplitudeKey = "7b69edb8ca6d2934989599a4ca9f7ca5"
});
}
[HttpGet("v1/all")]
public IActionResult getAllConf()
{
return Ok(new List<object>());
}
[HttpGet("v1/backtrace")]
public IActionResult backtrace()
{
return Ok(new
{
ReportBudget = 0,
FilterType = 0,
SampleRate = 0.025f,
LogLineCount = 50,
CaptureNativeCrashes = 1,
ANRThresholdMs = 0,
MessageCount = 1000,
MessageRegex = "^Cannot set the parent of the GameObject .* while its new parent|^\\\u003E\\x2010x\\:\\x20|\\'LabelTheme\\' contains missing PaletteTheme reference on",
VersionRegex = ".*"
});
}
[HttpGet("v2")]
public async Task<IActionResult> getconfv2()
{
var p = Path.Combine(Directory.GetCurrentDirectory(), "Jsons", "configv2.json");
var rawj = await System.IO.File.ReadAllTextAsync(p);
//var j = JsonConvert.DeserializeObject(rawj);
return Ok(rawj);
}
}
}
+136
View File
@@ -0,0 +1,136 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;
using DeluxeNET.Security;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class connectController : ControllerBase
{
private string steamkey = "Change to a valid steam id!";
private readonly jwt _jwt;
public connectController(jwt __jwt)
{
_jwt = __jwt;
}
[HttpPost("token")]
public async Task<IActionResult> genTokenByAuth()
{
Console.WriteLine("=== Incoming Request ===");
foreach (var key in Request.Form.Keys)
{
var value = Request.Form[key];
Console.WriteLine($"{key} = {value}");
}
var platAuth = JsonConvert.DeserializeObject<platform_auth>(Request.Form["platform_auth"]);
if (platAuth == null)
{
Console.WriteLine("platform_auth is null or failed to deserialize");
return Unauthorized();
}
if (platAuth.AppId != "471710")
{
Console.WriteLine($"Invalid AppId: {platAuth.AppId}");
return Unauthorized();
}
if (string.IsNullOrEmpty(platAuth.Ticket))
{
Console.WriteLine("Ticket is null or empty");
return Unauthorized();
}
var url = $"https://api.steampowered.com/ISteamUserAuth/AuthenticateUserTicket/v1/" +
$"?key={steamkey}&appid={platAuth.AppId}&ticket={platAuth.Ticket}";
Console.WriteLine("Sending request to Steam...");
using var client = new HttpClient();
var response = await client.GetStringAsync(url);
Console.WriteLine($"Steam response: {response}");
var json = JsonDocument.Parse(response);
var root = json.RootElement;
if (!root.TryGetProperty("response", out var responseObj))
{
Console.WriteLine("Missing 'response' in Steam reply");
return Unauthorized();
}
if (!responseObj.TryGetProperty("params", out var paramsObj))
{
Console.WriteLine("Missing 'params' in Steam reply");
return Unauthorized();
}
if (!paramsObj.TryGetProperty("steamid", out var steamdIdElement))
{
Console.WriteLine("Missing 'steamid' in Steam reply");
return Unauthorized();
}
var steamid = steamdIdElement.GetString();
Console.WriteLine($"SteamID from Steam: {steamid}");
var clientPlatformId = Request.Form["platform_id"].ToString();
if (clientPlatformId != steamid)
{
Console.WriteLine($"platform_id mismatch. Client: {clientPlatformId}, Steam: {steamid}");
return Unauthorized();
}
var accountId = Request.Form["account_id"].ToString();
if (string.IsNullOrEmpty(accountId))
{
Console.WriteLine("account_id is missing");
return Unauthorized();
}
var token = _jwt.GenerateToken(accountId);
Console.WriteLine($"JWT generated for account_id: {accountId}");
var resp = new
{
access_token = token,
error_description = "",
error = "",
refresh = token,
refresh_token = token,
key = ""
};
Console.WriteLine(JsonConvert.SerializeObject(resp));
return Ok(resp);
}
public class platform_auth
{
public required string Ticket { get; set; }
public required string AppId { get; set; }
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class consumablesController : ControllerBase
{
[HttpGet("v2/getUnlocked")]
public IActionResult getUnlockedCons()
{
return Ok(new List<object>());
}
}
}
@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class customAvatarItemsController : ControllerBase
{
[HttpGet("v1/isCreationAllowedForAccount")]
public IActionResult caf()
{
return Ok(new
{
success = true,
value = ""
});
}
[HttpGet("v1/isRenderingEnabled")]
public IActionResult ire()
{
return Ok(true);
}
[HttpGet("v1/isCreationEnabled")]
public IActionResult ice()
{
return Ok(true);
}
[HttpGet("v2/fromcreator/{playerid}")]
public IActionResult getCustomAvatarItemsFromCreator()
{
return Ok(new
{
Results = new List<object>(),
TotalResults = 0
});
}
}
}
+39
View File
@@ -0,0 +1,39 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class dataController : ControllerBase
{
private readonly jwt _jwt;
private readonly AppDbContext _db;
public dataController(jwt __jwt, AppDbContext __db)
{
_jwt = __jwt;
_db = __db;
}
[HttpPost("heartbeat")]
public async Task<IActionResult> getmypresnece()
{
//var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
//if (accountId == null) return Unauthorized();
//var heartbeatdata = await _db.Heartbeats
// .FirstOrDefaultAsync(x => x.PlayerId == accountId);
//if (heartbeatdata == null) return NotFound();
return Ok(new
{
Success = true
});
}
}
}
+29
View File
@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class eacController : ControllerBase
{
private bool enable2022 = false;
private bool enable2021 = true;
[HttpGet("challenge")]
public IActionResult getChal()
{
if (enable2021)
{
return Ok("\"9dcc9707-e722-4126-b1f8-9dc45a3a6605\"");
}
if (enable2022)
{
return Ok("\"AQAAAHsg7mW5FQEE9HVl9EKMWXrqDzQxUCdgV/IPuQfbRgTx+cGnQqhhAgv1RvpihEC77gQ29JdoGFn2806Q+QPEj7nYg9C8pynbaiSVO8rKLJPvROsHuSXVJpQMv3TD8KyK3Y+n5bb86vAb5kRdZGD//uC8HY+D9jJLlEfTUlU=\"");
}
return Ok("\"AQAAAGd9O3h2ynQW6Y/1MhdZC8VoHygxyTzmiRvAfpiRtJEBQ+NVaXMStRTsYQk42H1hbB7NGKhIpgfShk+ADtRW9EU/YF5320eGmINJZAqkm3pyX9QF/w1QT4IB2EQfOqTfpryQ3QFchXYqDgg/SbX+/X9mgzssbflIw3OAK+c=\"");
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class econController : ControllerBase
{
[HttpGet("customAvatarItems/v1/owned")]
public IActionResult getMyOwnedCustomAvatarItems()
{
return Ok(new
{
Results = new List<object>(),
TotalResults = 0
});
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class equipmentController : ControllerBase
{
[HttpGet("v2/getUnlocked")]
public IActionResult giwejigwioeg()
{
return Ok(new List<object>());
}
}
}
+55
View File
@@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class gameconfigsController : ControllerBase
{
[HttpGet("v1/amplitude")]
public IActionResult getAmpl()
{
return Ok(new
{
AmplitudeKey = "7b69edb8ca6d2934989599a4ca9f7ca5"
});
}
[HttpGet("v1/all")]
public IActionResult getAllConf()
{
return Ok(new List<object>());
}
[HttpGet("v1/backtrace")]
public IActionResult backtrace()
{
return Ok(new
{
ReportBudget = 0,
FilterType = 0,
SampleRate = 0.025f,
LogLineCount = 50,
CaptureNativeCrashes = 1,
ANRThresholdMs = 0,
MessageCount = 1000,
MessageRegex = "^Cannot set the parent of the GameObject .* while its new parent|^\\\u003E\\x2010x\\:\\x20|\\'LabelTheme\\' contains missing PaletteTheme reference on",
VersionRegex = ".*"
});
}
[HttpGet("v2")]
public async Task<IActionResult> getconfv2()
{
var p = Path.Combine(Directory.GetCurrentDirectory(), "Jsons", "configv2.json");
var rawj = await System.IO.File.ReadAllTextAsync(p);
//var j = JsonConvert.DeserializeObject(rawj);
return Ok(rawj);
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class gamerewardsController : ControllerBase
{
[HttpGet("v1/pending")]
public IActionResult getpendingrewards()
{
return Ok(new List<object>());
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class inventionsController : ControllerBase
{
[HttpGet("v2/mine")]
public IActionResult getMyInvetions()
{
return Ok(new List<object>());
}
}
}
+447
View File
@@ -0,0 +1,447 @@
using DeluxeNET.Data;
using DeluxeNET.Hubs;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
namespace DeluxeNET.Controllers
{
[Route("/")]
[ApiController]
public class matchmakeController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
private readonly NotificationHub _signalr;
public matchmakeController(AppDbContext db, jwt _jwt, NotificationHub __signalr)
{
_db = db;
this._jwt = _jwt;
_signalr = __signalr;
}
[HttpPost("matchmake/none")]
public async Task<ActionResult> MatchmakeNone()
{
var token = HttpContext?.Request.Headers["Authorization"].ToString();
if (string.IsNullOrEmpty(token) || !token.StartsWith("Bearer "))
return Unauthorized();
token = token["Bearer ".Length..].Trim();
long? playerIdNullable;
try
{
playerIdNullable = _jwt.VerifyToken(token);
}
catch
{
return Unauthorized();
}
if (!playerIdNullable.HasValue)
return Unauthorized();
long playerId = playerIdNullable.Value;
var heartbeat = await _db.Heartbeats
.FirstOrDefaultAsync(h => h.PlayerId == playerId);
if (heartbeat == null)
{
heartbeat = new Heartbeat
{
PlayerId = playerId,
IsOnline = true,
LastOnline = DateTime.UtcNow,
StatusVisibility = 0,
Platform = 0,
DeviceClass = 0,
VrMovementMode = 0,
AppVersion = "20230406"
};
_db.Heartbeats.Add(heartbeat);
}
heartbeat.RoomInstance = null;
heartbeat.RoomInstanceId = null;
heartbeat.IsOnline = true;
heartbeat.LastOnline = DateTime.UtcNow;
await _db.SaveChangesAsync();
await _signalr.SendAll(JsonSerializer.Serialize(new
{
Id = "PresenceUpdate",
Msg = heartbeat
}));
var newtoken = _jwt.GenerateToken(playerId.ToString());
return Ok(new
{
access_token = newtoken,
error_description = "",
error = "",
refresh_token = newtoken,
key = ""
});
}
[HttpPost("matchmake/{room}")]
public async Task<ActionResult> Matchmake([FromRoute] string room)
{
var token = HttpContext?.Request.Headers["Authorization"].ToString();
if (string.IsNullOrEmpty(token) || !token.StartsWith("Bearer "))
return Unauthorized();
token = token["Bearer ".Length..].Trim();
long? playerIdNullable;
try
{
playerIdNullable = _jwt.VerifyToken(token);
}
catch
{
return Unauthorized();
}
if (!playerIdNullable.HasValue)
return Unauthorized();
long playerId = playerIdNullable.Value;
var heartbeat = await _db.Heartbeats
.Include(h => h.RoomInstance)
.FirstOrDefaultAsync(h => h.PlayerId == playerId);
if (heartbeat == null)
{
heartbeat = new Heartbeat
{
PlayerId = playerId,
IsOnline = true,
LastOnline = DateTime.UtcNow,
StatusVisibility = 0,
Platform = 0,
DeviceClass = 0,
VrMovementMode = 0,
AppVersion = "20230406"
};
_db.Heartbeats.Add(heartbeat);
}
var candidates = await _db.Heartbeats
.Include(h => h.RoomInstance)
.Where(h =>
h.RoomInstance != null &&
h.RoomInstance.Name == room &&
!h.RoomInstance.IsPrivate)
.ToListAsync();
var roomInstance = candidates
.GroupBy(h => h.RoomInstanceId)
.Select(g => new
{
Room = g.First().RoomInstance,
Count = g.Count()
})
.FirstOrDefault(x =>
x.Room != null &&
x.Count < x.Room.MaxCapacity)?
.Room;
if (roomInstance == null)
{
roomInstance = new RoomInstance
{
Name = room,
RoomId = 0,
SubRoomId = 0,
Location = "76d98498-60a1-430c-ab76-b54a29b7a163",
RoomInstanceType = 0,
PhotonRegionId = "us",
PhotonRegion = "us",
PhotonRoomId = Guid.NewGuid().ToString(),
MaxCapacity = 10,
IsFull = false,
IsPrivate = false,
IsInProgress = false,
MatchmakingPolicy = 0
};
}
heartbeat.RoomInstance = roomInstance;
heartbeat.RoomInstanceId = roomInstance.RoomInstanceId;
heartbeat.IsOnline = true;
heartbeat.LastOnline = DateTime.UtcNow;
await _db.SaveChangesAsync();
await _signalr.SendAll(JsonSerializer.Serialize(new
{
Id = "PresenceUpdate",
Msg = heartbeat
}));
return Ok(new
{
errorCode = 0,
roomInstance
});
}
[HttpPost("goto/room/{room}")]
public async Task<ActionResult> MatchmakeOLD([FromRoute] string room)
{
var auth = HttpContext.Request.Headers["Authorization"].ToString();
if (string.IsNullOrWhiteSpace(auth) || !auth.StartsWith("Bearer "))
return Unauthorized();
var token = auth["Bearer ".Length..].Trim();
long playerId;
try
{
var id = _jwt.VerifyToken(token);
if (!id.HasValue) return Unauthorized();
playerId = id.Value;
}
catch
{
return Unauthorized();
}
var heartbeat = await _db.Heartbeats
.FirstOrDefaultAsync(h => h.PlayerId == playerId);
if (heartbeat == null)
{
heartbeat = new Heartbeat
{
PlayerId = playerId,
StatusVisibility = 0,
Platform = 0,
DeviceClass = 0,
VrMovementMode = 0,
IsOnline = true,
LastOnline = DateTime.UtcNow,
AppVersion = "20230406"
};
_db.Heartbeats.Add(heartbeat);
await _db.SaveChangesAsync();
}
RoomInstance? instance = null;
if (heartbeat.RoomInstanceId.HasValue)
{
instance = await _db.Set<RoomInstance>()
.FirstOrDefaultAsync(r => r.RoomInstanceId == heartbeat.RoomInstanceId.Value);
}
if (instance == null)
{
var template = await _db.Set<RoomInstance>()
.FirstOrDefaultAsync(r => r.RoomId == 1);
if (template == null)
return StatusCode(500, "Missing RoomId=1 template");
instance = new RoomInstance
{
RoomId = template.RoomId,
SubRoomId = template.SubRoomId,
Location = template.Location,
RoomInstanceType = template.RoomInstanceType,
PhotonRegionId = template.PhotonRegionId,
PhotonRegion = template.PhotonRegion,
PhotonRoomId = Guid.NewGuid().ToString(),
Name = room,
MaxCapacity = template.MaxCapacity,
IsFull = false,
IsPrivate = false,
IsInProgress = false,
MatchmakingPolicy = template.MatchmakingPolicy
};
_db.Set<RoomInstance>().Add(instance);
await _db.SaveChangesAsync();
heartbeat.RoomInstanceId = instance.RoomInstanceId;
await _db.SaveChangesAsync();
}
var playersInRoom = await _db.Heartbeats
.Where(h => h.RoomInstanceId == instance.RoomInstanceId)
.CountAsync();
if (playersInRoom >= instance.MaxCapacity)
{
instance.IsFull = true;
await _db.SaveChangesAsync();
}
heartbeat.RoomInstanceId = instance.RoomInstanceId;
heartbeat.LastOnline = DateTime.UtcNow;
heartbeat.IsOnline = true;
await _db.SaveChangesAsync();
await _signalr.SendAll(System.Text.Json.JsonSerializer.Serialize(new
{
Id = "PresenceUpdate",
Msg = new
{
heartbeat.PlayerId,
heartbeat.StatusVisibility,
heartbeat.Platform,
heartbeat.DeviceClass,
heartbeat.RoomInstanceId,
heartbeat.VrMovementMode,
heartbeat.LastOnline,
heartbeat.IsOnline,
heartbeat.AppVersion
}
}));
return Ok(new
{
errorCode = 0,
roomInstance = new
{
instance.RoomInstanceId,
instance.RoomId,
instance.SubRoomId,
instance.Name,
instance.MaxCapacity,
instance.IsFull,
instance.IsPrivate,
instance.IsInProgress,
instance.PhotonRoomId
}
});
}
[HttpPost("room/{roomid}")]
public async Task<ActionResult> MatchmakeByName([FromRoute] long roomid)
{
var token = HttpContext?.Request.Headers["Authorization"].ToString();
if (string.IsNullOrEmpty(token) || !token.StartsWith("Bearer "))
return Unauthorized();
token = token["Bearer ".Length..].Trim();
long? playerIdNullable;
try
{
playerIdNullable = _jwt.VerifyToken(token);
}
catch
{
return Unauthorized();
}
if (!playerIdNullable.HasValue)
return Unauthorized();
long playerId = playerIdNullable.Value;
var heartbeat = await _db.Heartbeats
.Include(h => h.RoomInstance)
.FirstOrDefaultAsync(h => h.PlayerId == playerId);
if (heartbeat == null)
{
heartbeat = new Heartbeat
{
PlayerId = playerId,
IsOnline = true,
LastOnline = DateTime.UtcNow,
StatusVisibility = 0,
Platform = 0,
DeviceClass = 0,
VrMovementMode = 0,
AppVersion = "20230406"
};
_db.Heartbeats.Add(heartbeat);
}
var candidates = await _db.Heartbeats
.Include(h => h.RoomInstance)
.Where(h =>
h.RoomInstance != null &&
h.RoomInstance.RoomId == roomid &&
!h.RoomInstance.IsPrivate)
.ToListAsync();
var roomInstance = candidates
.GroupBy(h => h.RoomInstanceId)
.Select(g => new
{
Room = g.First().RoomInstance,
Count = g.Count()
})
.FirstOrDefault(x =>
x.Room != null &&
x.Count < x.Room.MaxCapacity)?
.Room;
if (roomInstance == null)
{
roomInstance = new RoomInstance
{
Name = "A Room.",
RoomId = roomid,
SubRoomId = 0,
Location = "76d98498-60a1-430c-ab76-b54a29b7a163",
RoomInstanceType = 0,
PhotonRegionId = "us",
PhotonRegion = "us",
PhotonRoomId = Guid.NewGuid().ToString(),
MaxCapacity = 10,
IsFull = false,
IsPrivate = false,
IsInProgress = false,
MatchmakingPolicy = 0
};
}
heartbeat.RoomInstance = roomInstance;
heartbeat.RoomInstanceId = roomInstance.RoomInstanceId;
heartbeat.IsOnline = true;
heartbeat.LastOnline = DateTime.UtcNow;
await _db.SaveChangesAsync();
await _signalr.SendAll(JsonSerializer.Serialize(new
{
Id = "PresenceUpdate",
Msg = heartbeat
}));
return Ok(new
{
errorCode = 0,
roomInstance
});
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class messagesController : ControllerBase
{
[HttpGet("v2/get")]
public IActionResult getmessagesjieiogio()
{
return Ok(new List<object>());
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class objectivesController : ControllerBase
{
[HttpGet("v1/myprogress")]
public IActionResult getMyProgress()
{
return Ok(new
{
Objectives = new List<object>(),
ObjectiveGroups = new List<object>()
});
}
}
}
+34
View File
@@ -0,0 +1,34 @@
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class parentalcontrolController : ControllerBase
{
private readonly jwt _jwt;
public parentalcontrolController(jwt jwt)
{
_jwt = jwt;
}
[HttpGet("me")]
public IActionResult getMyParentalControlConf()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
return Ok(new
{
accountId = accountId,
disallowInAppPurchases = false
});
}
}
}
+64
View File
@@ -0,0 +1,64 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class playerController : ControllerBase
{
private readonly jwt _jwt;
private readonly AppDbContext _db;
public playerController(jwt __jwt, AppDbContext __db)
{
_jwt = __jwt;
_db = __db;
}
[HttpPost("login")]
public IActionResult loginUser()
{
return Ok(new List<object>());
}
[HttpPost("exclusivelogin")]
public IActionResult exlogin()
{
return Ok("");
}
[HttpPut("statusvisibility")]
public IActionResult svs()
{
return Ok(new List<object>());
}
[HttpPost("heartbeat")]
public async Task<IActionResult> getmypresnece()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
var heartbeatdata = await _db.Heartbeats
.FirstOrDefaultAsync(x => x.PlayerId == accountId);
if (heartbeatdata == null) return NotFound();
Console.WriteLine("");
//if (heartbeatdata.IsRoomInstanceNull)
//{
// heartbeatdata.RoomInstance = null;
//}
return Ok(heartbeatdata);
}
[HttpPut("photonregionpings")]
public IActionResult prp()
{
return Ok(new List<object>());
}
}
}
+29
View File
@@ -0,0 +1,29 @@
using DeluxeNET.Data;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class playerReputationController : ControllerBase
{
private readonly AppDbContext _db;
public playerReputationController(AppDbContext db)
{
_db = db;
}
[HttpGet("v2/bulk")]
public async Task<IActionResult> getRepBulk([FromQuery] List<long> id)
{
var reps = await _db.Reputations
.Where(x => id.Contains(x.Id))
.ToListAsync();
return Ok(reps);
}
}
}
+20
View File
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class playereventsController : ControllerBase
{
[HttpGet("v1/all")]
public IActionResult getCurrentEvents()
{
return Ok(new
{
Created = new List<object>(),
Responses = new List<object>()
});
}
}
}
+31
View File
@@ -0,0 +1,31 @@
using DeluxeNET.Data;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class playersController : ControllerBase
{
private readonly AppDbContext _db;
public playersController(AppDbContext db)
{
_db = db;
}
[HttpGet("v2/progression/bulk")]
public async Task<IActionResult> getprogressBulk([FromQuery] List<long> id)
{
var progressions = await _db.Progressions
.Where(x => id.Contains(x.Id))
.ToListAsync();
return Ok(progressions);
}
}
}
+130
View File
@@ -0,0 +1,130 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace DeluxeNET.Controllers
{
[Route("/")]
[ApiController]
public class playersettingsController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
public playersettingsController(AppDbContext db, jwt jwt)
{
_db = db;
_jwt = jwt;
}
[HttpGet("playersettings")]
public async Task<IActionResult> getSettings()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
var settings = await _db.Settings
.Where(x => x.accountId == accountId)
.ToListAsync();
settings.Add(new setting { accountId = accountId, Key = "TUTORIAL_COMPLETED_MASK", Value = "123"});
settings.Add(new setting { accountId = accountId, Key = "HAS_COMPLETED_ORIENTATION", Value = "True" });
settings.Add(new setting { accountId = accountId, Key = "OrientationCompletionTime", Value = "2024-07-09T07:53:30.7953332Z" });
return Ok(settings);
}
[HttpGet("api/settings/v2/")]
public async Task<IActionResult> getSettingsOLD()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
var settings = await _db.Settings
.Where(x => x.accountId == accountId)
.ToListAsync();
settings.Add(new setting { accountId = accountId, Key = "TUTORIAL_COMPLETED_MASK", Value = "123" });
settings.Add(new setting { accountId = accountId, Key = "HAS_COMPLETED_ORIENTATION", Value = "True" });
settings.Add(new setting { accountId = accountId, Key = "OrientationCompletionTime", Value = "2024-07-09T07:53:30.7953332Z" });
return Ok(settings);
}
[HttpPut("playersettings")]
public async Task<IActionResult> setSetting()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
var setting = await _db.Settings
.FirstOrDefaultAsync(x => x.Key == Request.Form["Key"].ToString() && x.accountId == accountId);
if (setting == null)
{
_db.Settings.Add(new setting
{
accountId = accountId,
Key = Request.Form["Key"].ToString(),
Value = Request.Form["Value"].ToString()
});
} else
{
setting.Value = Request.Form["Value"].ToString();
}
await _db.SaveChangesAsync();
return Ok(new List<object>());
}
[HttpPost("api/settings/v2/set")]
public async Task<IActionResult> setSettingOLD()
{
//var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
//if (accountId == null) return Unauthorized();
//var setting = await _db.Settings
// .FirstOrDefaultAsync(x => x.Key == Request.Form["Key"].ToString() && x.accountId == accountId);
//if (setting == null)
//{
// _db.Settings.Add(new setting
// {
// accountId = accountId,
// Key = Request.Form["Key"].ToString(),
// Value = Request.Form["Value"].ToString()
// });
//}
//else
//{
// setting.Value = Request.Form["Value"].ToString();
//}
//await _db.SaveChangesAsync();
return Ok(new List<object>());
}
}
}
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class progressionEventsController : ControllerBase
{
[HttpGet("active")]
public IActionResult getActiveProgressionEvents()
{
return NoContent();
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class quickPlayController : ControllerBase
{
[HttpGet("v1/getandclear")]
public IActionResult getandclear()
{
return Ok(new { });
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class relationshipsController : ControllerBase
{
[HttpGet("v2/get")]
public IActionResult getReplationshgnowroighwrohgo()
{
return Ok(new List<object>());
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class roomkeysController : ControllerBase
{
[HttpGet("v1/mine")]
public IActionResult iojgwig()
{
return Ok(new List<object>());
}
}
}
+49
View File
@@ -0,0 +1,49 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class roomsController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
public roomsController(AppDbContext db, jwt jwt)
{
_db = db;
_jwt = jwt;
}
[HttpGet("v1/filters")]
public IActionResult GetFilters()
{
var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
if (accountId == null) return Unauthorized();
return Ok(new
{
PinnedFilers = new List<string>
{
"recroomoriginal","community","quest","puzzle","pvp","hangout","art","tutorial",
"fandom","performance","action","horror"
},
PopularFilters = new List<string>
{
"recroomoriginal","quest","community","import"
}
});
}
//[HttpGet("requiring/developer")]
//public IActionResult getDoesRequireDev()
//{
// return Ok(false);
//}
}
}
+166
View File
@@ -0,0 +1,166 @@
using DeluxeNET.Data;
using DeluxeNET.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class roomserverController : ControllerBase
{
private readonly AppDbContext _db;
private readonly jwt _jwt;
public roomserverController(AppDbContext db, jwt jwt)
{
_jwt = jwt;
_db = db;
}
[HttpGet("rooms")]
public async Task<IActionResult> getRoomDetails([FromQuery] string name)
{
//var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
//if (accountId == null) return Unauthorized();
var room = await _db.Rooms
.Include(x => x.Stats)
.Include(x => x.Roles)
.Include(x => x.SubRooms)
.FirstOrDefaultAsync(x => x.Name == name);
if (room == null) return NotFound();
room.PromoImages = new List<object>();
room.PromoExternalContent = new List<object>();
room.LoadScreens = new List<object>();
return Ok(room);
}
[HttpGet("rooms/{roomid}")]
public async Task<IActionResult> getRoomDetailsByID([FromRoute] int roomid)
{
//var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
//if (accountId == null) return Unauthorized();
var isZero = false;
if (roomid == 0)
{
roomid = 2;
isZero = true;
}
var room = await _db.Rooms
.Include(x => x.Stats)
.Include(x => x.Roles)
.Include(x => x.SubRooms)
.FirstOrDefaultAsync(x => x.RoomId == roomid);
if (room == null) return NotFound();
if (isZero)
{
room.RoomId = 0;
}
room.PromoImages = new List<object>();
room.PromoExternalContent = new List<object>();
room.LoadScreens = new List<object>();
return Ok(room);
}
[HttpGet("rooms/bulk")]
public async Task<IActionResult> getRoomDetailsBulkByRoomNames([FromQuery] List<string> name)
{
//var accountId = _jwt.VerifyToken(Request.Headers["Authorization"].ToString());
//if (accountId == null) return Unauthorized();
var room = await _db.Rooms
.Include(x => x.Stats)
.Include(x => x.Roles)
.Include(x => x.SubRooms)
.Where(x => name.Contains(x.Name))
.ToListAsync();
if (room == null) return NotFound();
foreach (var i in room)
{
i.PromoImages = new List<object>();
i.PromoExternalContent = new List<object>();
i.LoadScreens = new List<object>();
}
return Ok(room);
}
[HttpGet("rooms/createdby/me")]
public IActionResult getMyRoomsIMade()
{
return Ok(new List<object>());
}
[HttpGet("rooms/ownedby/{playerid}")]
public IActionResult getRoomsOwnedByID()
{
return Ok(new
{
Results = new List<object>(),
TotalResults = 0
});
}
[HttpGet("rooms/visitedby/me")]
public IActionResult visitroomsbyme()
{
return Ok(new
{
Results = new List<object>(),
TotalResults = 0
});
}
[HttpGet("rooms/hot")]
public async Task<IActionResult> getRoomsthatAreHot([FromQuery] List<string> tag,
[FromQuery] int skip = 0,
[FromQuery] int take = 100
)
{
if (take > 500) take = 100;
var room = await _db.Rooms
.Include(x => x.Stats)
.Include(x => x.Roles)
.Include(x => x.SubRooms)
.Skip(skip)
.Take(take)
.ToListAsync();
foreach (var i in room)
{
i.PromoImages = new List<object>();
i.PromoExternalContent = new List<object>();
i.LoadScreens = new List<object>();
}
return Ok(new
{
Results = room,
TotalResults = room.Count()
});
}
}
}
+16
View File
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("[controller]")]
[ApiController]
public class subscriptionController : ControllerBase
{
[HttpGet("subscriberCount/{playerid}")]
public IActionResult subscribercpuntget()
{
return Ok(0);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DeluxeNET.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class versioncheckController : ControllerBase
{
[HttpGet("v4")]
public IActionResult checkVersion([FromQuery] string v)
{
return Ok(new
{
VersionStatus = 0
});
}
}
}