mirror of
https://github.com/CannedNet/CannedNet.git
synced 2026-10-25 23:18:54 -07:00
h
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace CannedNet.Data;
|
|
||||||
|
|
||||||
public class AppDbContext : DbContext
|
|
||||||
{
|
|
||||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbSet<Account> Accounts { get; set; }
|
|
||||||
public DbSet<CachedLogin> CachedLogins { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
|
|
||||||
// accounts
|
|
||||||
modelBuilder.Entity<Account>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.AccountId);
|
|
||||||
entity.Property(e => e.AccountId).ValueGeneratedNever();
|
|
||||||
entity.Property(e => e.Username).IsRequired();
|
|
||||||
entity.Property(e => e.DisplayName).IsRequired();
|
|
||||||
entity.ToTable("accounts");
|
|
||||||
});
|
|
||||||
|
|
||||||
// cachedlogins
|
|
||||||
modelBuilder.Entity<CachedLogin>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
|
||||||
entity.HasIndex(e => new { e.Platform, e.PlatformID }).IsUnique();
|
|
||||||
entity.ToTable("cached_logins");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
using CannedNet;
|
|
||||||
using CannedNet.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
// TODO: organize this into multiple files
|
|
||||||
// TODO: cdn stuff soon so i can not just have 0 images for this lmao
|
|
||||||
// TODO: setup signalr and get websockets running, currently should focus on notifications as logging in is being blocked by that
|
|
||||||
|
|
||||||
// needed so it won't try to auto capitalize random stuff that may be case-sensitive
|
|
||||||
builder.Services.ConfigureHttpJsonOptions(options =>
|
|
||||||
{
|
|
||||||
options.SerializerOptions.PropertyNamingPolicy = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// postgresql db, will probably have it configurable later on but for now just hardcode it in
|
|
||||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
|
|
||||||
?? "Host=localhost;Port=5432;Database=cannednet;Username=postgres;Password=postgres";
|
|
||||||
|
|
||||||
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
||||||
options.UseNpgsql(connectionString));
|
|
||||||
|
|
||||||
builder.Services.AddScoped<JwtTokenService>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
// apply db migrations on startup so we don't have to worry about it later bc i hate doing db things manually lol
|
|
||||||
using (var scope = app.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
db.Database.Migrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
var jwtService = app.Services.GetRequiredService<JwtTokenService>();
|
|
||||||
|
|
||||||
// request logging
|
|
||||||
app.Use(async (context, next) =>
|
|
||||||
{
|
|
||||||
var request = context.Request;
|
|
||||||
Console.WriteLine($"\n{request.Method} {request.Path}{request.QueryString}");
|
|
||||||
|
|
||||||
foreach (var header in request.Headers)
|
|
||||||
Console.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}");
|
|
||||||
|
|
||||||
if (request.ContentLength > 0)
|
|
||||||
{
|
|
||||||
request.EnableBuffering();
|
|
||||||
using (var reader = new StreamReader(request.Body, leaveOpen: true))
|
|
||||||
{
|
|
||||||
var body = await reader.ReadToEndAsync();
|
|
||||||
Console.WriteLine($" Body: {body}");
|
|
||||||
}
|
|
||||||
request.Body.Position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
await next(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/", () =>
|
|
||||||
{
|
|
||||||
var json = File.ReadAllText("endpoints.json");
|
|
||||||
return Results.Content(json, "application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/config/v1/amplitude", () =>
|
|
||||||
{
|
|
||||||
var config = new
|
|
||||||
{
|
|
||||||
AmplitudeKey = "fd846cd67066d19eec62fbdd00be9258",
|
|
||||||
StatSigKey = "client-mnew4Ggjuu3Fbh86Ed3tRgWUxapp0D7PPB0i3MXUEao",
|
|
||||||
RudderStackKey = "37qVlzZyXqdmZckXJ61vQeEJp8Y",
|
|
||||||
UseRudderStack = true
|
|
||||||
};
|
|
||||||
|
|
||||||
return Results.Ok(config);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/config/v2", () =>
|
|
||||||
{
|
|
||||||
var json = File.ReadAllText("configv2.json");
|
|
||||||
return Results.Content(json, "application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/versioncheck/v4", () =>
|
|
||||||
{
|
|
||||||
return Results.Content("{\"VersionStatus\":0}","application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/gameconfigs/v1/all", () =>
|
|
||||||
{
|
|
||||||
var json = File.ReadAllText("gameconfigs.json");
|
|
||||||
return Results.Content(json, "application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/photon", () =>
|
|
||||||
{
|
|
||||||
var json = File.ReadAllText("photonsettings.json");
|
|
||||||
return Results.Content(json, "application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/eac/challenge", () =>
|
|
||||||
{
|
|
||||||
var file = File.ReadAllText("eacchallenge.txt");
|
|
||||||
return Results.Content(file,"text/plain");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/playerReputation/v1/{id}", (string id) =>
|
|
||||||
{
|
|
||||||
// TODO: make rep actually work
|
|
||||||
return Results.Content($"{{\"AccountId\":{id},\"Noteriety\":0,\"CheerGeneral\":0,\"CheerHelpful\":0,\"CheerCreative\":0,\"CheerGreatHost\":0,\"CheerSportsman\":0,\"CheerCredit\":20,\"SelectedCheer\":null}}","application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/players/v1/progression/{id}", (string id) =>
|
|
||||||
{
|
|
||||||
// TODO: make progression actually work
|
|
||||||
return Results.Content($"{{\"PlayerId\":{id},\"Level\":1,\"XP\":0}}","application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/api/PlayerReporting/v1/moderationBlockDetails", () =>
|
|
||||||
{
|
|
||||||
// TODO: make this actually work
|
|
||||||
return Results.Content($"{{\"ReportCategory\":0,\"Duration\":0,\"GameSessionId\":0,\"IsHostKick\":false,\"Message\":\"\",\"PlayerIdReporter\":null,\"IsBan\":false}}","application/json");
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapPost("/player/login", () =>
|
|
||||||
{
|
|
||||||
return Results.Ok();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/cachedlogin/forplatformid/{platform}/{id}", async (string platform, string id, AppDbContext db) =>
|
|
||||||
{
|
|
||||||
var platformType = int.Parse(platform);
|
|
||||||
var logins = await db.CachedLogins
|
|
||||||
.Where(c => c.Platform == (PlatformType)platformType && c.PlatformID == id)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return Results.Json(logins.Any() ? logins : new List<object>());
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/account/me", (HttpRequest request, AppDbContext db) =>
|
|
||||||
{
|
|
||||||
var authHeader = request.Headers.Authorization.ToString();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
|
||||||
return Results.Unauthorized();
|
|
||||||
|
|
||||||
var token = authHeader.Substring("Bearer ".Length);
|
|
||||||
var accountId = jwtService.ValidateAndGetAccountId(token);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId, out var id))
|
|
||||||
return Results.Unauthorized();
|
|
||||||
|
|
||||||
var selfAccount = new SelfAccount
|
|
||||||
{
|
|
||||||
AccountId = id,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{id}",
|
|
||||||
DisplayName = $"Player{id}",
|
|
||||||
CreatedAt = DateTime.UtcNow,
|
|
||||||
Email = null,
|
|
||||||
Phone = null,
|
|
||||||
JuniorState = null,
|
|
||||||
Birthday = null,
|
|
||||||
ParentAccountId = null,
|
|
||||||
AvailableUsernameChanges = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
return Results.Ok(selfAccount);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapGet("/account/bulk", (HttpRequest request) =>
|
|
||||||
{
|
|
||||||
var ids = request.Query["id"];
|
|
||||||
var accounts = new List<Account>();
|
|
||||||
|
|
||||||
foreach (var id in ids)
|
|
||||||
{
|
|
||||||
if (int.TryParse(id, out var accountId))
|
|
||||||
{
|
|
||||||
var account = new Account
|
|
||||||
{
|
|
||||||
AccountId = accountId,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{accountId}",
|
|
||||||
DisplayName = $"Player{accountId}",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
accounts.Add(account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Results.Json(accounts);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapPost("/account/create", async (HttpRequest httpRequest, AppDbContext db) =>
|
|
||||||
{
|
|
||||||
int platform = 0;
|
|
||||||
string platformId = "";
|
|
||||||
|
|
||||||
if (httpRequest.ContentLength.HasValue && httpRequest.ContentLength > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var contentType = httpRequest.ContentType ?? "";
|
|
||||||
httpRequest.EnableBuffering();
|
|
||||||
|
|
||||||
using (var reader = new StreamReader(httpRequest.Body, leaveOpen: true))
|
|
||||||
{
|
|
||||||
var body = await reader.ReadToEndAsync();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(body))
|
|
||||||
{
|
|
||||||
if (contentType.Contains("application/x-www-form-urlencoded"))
|
|
||||||
{
|
|
||||||
var pairs = body.Split('&');
|
|
||||||
foreach (var pair in pairs)
|
|
||||||
{
|
|
||||||
var keyValue = pair.Split('=');
|
|
||||||
if (keyValue.Length == 2)
|
|
||||||
{
|
|
||||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
|
||||||
var value = Uri.UnescapeDataString(keyValue[1]);
|
|
||||||
|
|
||||||
if (key == "platform" && int.TryParse(value, out var parsedPlatform))
|
|
||||||
platform = parsedPlatform;
|
|
||||||
else if (key == "platformId")
|
|
||||||
platformId = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
httpRequest.Body.Position = 0;
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
var accountId = new Random().Next(10000, 99999);
|
|
||||||
var account = new Account
|
|
||||||
{
|
|
||||||
AccountId = accountId,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{accountId}",
|
|
||||||
DisplayName = $"Player{accountId}",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
|
|
||||||
db.Accounts.Add(account);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(platformId))
|
|
||||||
{
|
|
||||||
var loginRecord = new CachedLogin
|
|
||||||
{
|
|
||||||
AccountId = accountId,
|
|
||||||
Platform = (PlatformType)platform,
|
|
||||||
PlatformID = platformId,
|
|
||||||
LastLoginTime = DateTime.UtcNow,
|
|
||||||
RequirePassword = false
|
|
||||||
};
|
|
||||||
|
|
||||||
db.CachedLogins.Add(loginRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.SaveChangesAsync();
|
|
||||||
|
|
||||||
return Results.Ok(RecNetResultWithValue<Account>.Ok(account));
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapPost("/connect/token", async (HttpRequest httpRequest) =>
|
|
||||||
{
|
|
||||||
string accountId = "";
|
|
||||||
string platformId = "";
|
|
||||||
string platform = "";
|
|
||||||
|
|
||||||
if (httpRequest.ContentLength.HasValue && httpRequest.ContentLength > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
httpRequest.EnableBuffering();
|
|
||||||
using (var reader = new StreamReader(httpRequest.Body, leaveOpen: true))
|
|
||||||
{
|
|
||||||
var body = await reader.ReadToEndAsync();
|
|
||||||
if (!string.IsNullOrWhiteSpace(body))
|
|
||||||
{
|
|
||||||
var pairs = body.Split('&');
|
|
||||||
foreach (var pair in pairs)
|
|
||||||
{
|
|
||||||
var keyValue = pair.Split('=');
|
|
||||||
if (keyValue.Length == 2)
|
|
||||||
{
|
|
||||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
|
||||||
var value = Uri.UnescapeDataString(keyValue[1]);
|
|
||||||
|
|
||||||
if (key == "account_id")
|
|
||||||
accountId = value;
|
|
||||||
else if (key == "platform_id")
|
|
||||||
platformId = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
httpRequest.Body.Position = 0;
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
var accessToken = jwtService.GenerateToken(accountId, platformId, platform);
|
|
||||||
|
|
||||||
var response = new
|
|
||||||
{
|
|
||||||
access_token = accessToken,
|
|
||||||
expires_in = 3600,
|
|
||||||
token_type = "Bearer",
|
|
||||||
refresh_token = Guid.NewGuid().ToString("N").ToUpper() + "-1",
|
|
||||||
scope = "offline_access profile rn rn.accounts rn.accounts.gc rn.api rn.chat rn.clubs rn.commerce rn.match.read rn.match.write rn.notify rn.rooms rn.storage",
|
|
||||||
key = "8oQ+e+WQaOBPbEcakhqs3dwZZdOmmyDUmJSD9u4AHMY="
|
|
||||||
};
|
|
||||||
|
|
||||||
return Results.Json(response);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"Auth": "https://rr.lapis.codes",
|
|
||||||
"API": "https://rr.lapis.codes",
|
|
||||||
"WWW": "https://www.lapis.codes",
|
|
||||||
"Notifications": "https://rr.lapis.codes",
|
|
||||||
"Images": "https://rr.lapis.codes",
|
|
||||||
"CDN": "https://rr.lapis.codes",
|
|
||||||
"Commerce": "https://rr.lapis.codes",
|
|
||||||
"Matchmaking": "https://rr.lapis.codes",
|
|
||||||
"Storage": "https://rr.lapis.codes",
|
|
||||||
"Chat": "https://rr.lapis.codes",
|
|
||||||
"Leaderboard": "https://rr.lapis.codes",
|
|
||||||
"Accounts": "https://rr.lapis.codes",
|
|
||||||
"Link": "https://rr.lapis.codes",
|
|
||||||
"RoomComments": "https://rr.lapis.codes",
|
|
||||||
"Clubs": "https://rr.lapis.codes",
|
|
||||||
"Rooms": "https://rr.lapis.codes",
|
|
||||||
"PlatformNotifications": "https://rr.lapis.codes",
|
|
||||||
"Moderation": "https://rr.lapis.codes",
|
|
||||||
"DataCollection": "https://rr.lapis.codes",
|
|
||||||
"BugReporting": "https://rr.lapis.codes",
|
|
||||||
"Discovery": "https://rr.lapis.codes",
|
|
||||||
"PlayerSettings": "https://rr.lapis.codes",
|
|
||||||
"Rendering": "https://rr.lapis.codes",
|
|
||||||
"Launcher": "https://rr.lapis.codes"
|
|
||||||
}
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
<Solution>
|
<Solution>
|
||||||
<Folder Name="/Solution Items/" />
|
<Folder Name="/Solution Items/" />
|
||||||
<Project Path="CannedNet.API/CannedNet.API.csproj" />
|
<Project Path="CannedNet/CannedNet.csproj" />
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5005"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5002"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5003"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5004"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"Hosting": {
|
||||||
|
"Url": "http://*:5006"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace CannedNet.Data;
|
||||||
|
|
||||||
|
public class AppDbContext : DbContext
|
||||||
|
{
|
||||||
|
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<Account> Accounts { get; set; }
|
||||||
|
public DbSet<CachedLogin> CachedLogins { get; set; }
|
||||||
|
public DbSet<PlayerProgression> PlayerProgressions { get; set; }
|
||||||
|
public DbSet<PlayerSetting> PlayerSettings { get; set; }
|
||||||
|
public DbSet<AvatarItem> AvatarItems { get; set; }
|
||||||
|
public DbSet<PlayerAvatar> PlayerAvatars { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
// accounts
|
||||||
|
modelBuilder.Entity<Account>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.AccountId);
|
||||||
|
entity.Property(e => e.AccountId).ValueGeneratedNever();
|
||||||
|
entity.Property(e => e.Username).IsRequired();
|
||||||
|
entity.Property(e => e.DisplayName).IsRequired();
|
||||||
|
entity.ToTable("accounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
// cachedlogins
|
||||||
|
modelBuilder.Entity<CachedLogin>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||||
|
entity.HasIndex(e => new { e.Platform, e.PlatformID }).IsUnique();
|
||||||
|
entity.ToTable("cached_logins");
|
||||||
|
});
|
||||||
|
|
||||||
|
// player_progressions
|
||||||
|
modelBuilder.Entity<PlayerProgression>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||||
|
entity.HasIndex(e => e.PlayerId).IsUnique();
|
||||||
|
entity.ToTable("player_progressions");
|
||||||
|
});
|
||||||
|
|
||||||
|
// player_settings_kv (key-value pairs)
|
||||||
|
modelBuilder.Entity<PlayerSetting>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||||
|
entity.Property(e => e.PlayerId).IsRequired();
|
||||||
|
entity.Property(e => e.Key).IsRequired();
|
||||||
|
entity.Property(e => e.Value).IsRequired();
|
||||||
|
entity.HasIndex(e => new { e.PlayerId, e.Key }).IsUnique();
|
||||||
|
entity.ToTable("player_settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
// avatar_items
|
||||||
|
modelBuilder.Entity<AvatarItem>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||||
|
entity.Property(e => e.OwnerAccountId).IsRequired();
|
||||||
|
entity.Property(e => e.AvatarItemDesc).IsRequired();
|
||||||
|
entity.Property(e => e.FriendlyName).IsRequired();
|
||||||
|
entity.HasIndex(e => e.OwnerAccountId);
|
||||||
|
entity.ToTable("avatar_items");
|
||||||
|
});
|
||||||
|
|
||||||
|
// player_avatars
|
||||||
|
modelBuilder.Entity<PlayerAvatar>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||||
|
entity.Property(e => e.OwnerAccountId).IsRequired();
|
||||||
|
entity.HasIndex(e => e.OwnerAccountId).IsUnique();
|
||||||
|
entity.ToTable("player_avatars");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using CannedNet.Services;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace CannedNet.Hubs;
|
||||||
|
|
||||||
|
public class NotificationsHub : Hub
|
||||||
|
{
|
||||||
|
private static NotificationService _notificationService = new();
|
||||||
|
|
||||||
|
public NotificationsHub()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
_notificationService.OnConnected(Context.ConnectionId);
|
||||||
|
await Clients.Caller.SendAsync("OnConnect");
|
||||||
|
await base.OnConnectedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||||
|
{
|
||||||
|
_notificationService.OnDisconnected(Context.ConnectionId);
|
||||||
|
await base.OnDisconnectedAsync(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SubscribeToPlayers(SubscriptionList subscriptionList)
|
||||||
|
{
|
||||||
|
await _notificationService.SubscribeToPlayers(Context.ConnectionId, subscriptionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<HashSet<int>> GetSubscriptions()
|
||||||
|
{
|
||||||
|
return Task.FromResult(_notificationService.GetSubscribedPlayers(Context.ConnectionId).ToHashSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NotificationService GetNotificationService()
|
||||||
|
{
|
||||||
|
return _notificationService;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"Auth": "https://auth.lapis.codes",
|
||||||
|
"API": "https://api.lapis.codes",
|
||||||
|
"WWW": "https://www.lapis.codes",
|
||||||
|
"Notifications": "https://notify.lapis.codes",
|
||||||
|
"Images": "https://img.lapis.codes",
|
||||||
|
"CDN": "https://cdn.lapis.codes",
|
||||||
|
"Commerce": "https://commerce.lapis.codes",
|
||||||
|
"Matchmaking": "https://match.lapis.codes",
|
||||||
|
"Storage": "https://storage.lapis.codes",
|
||||||
|
"Chat": "https://chatrr.lapis.codes",
|
||||||
|
"Leaderboard": "https://rr.lapis.codes",
|
||||||
|
"Accounts": "http://localhost:5005",
|
||||||
|
"Link": "https://link.lapis.codes",
|
||||||
|
"RoomComments": "https://roomcomments.lapis.codes",
|
||||||
|
"Clubs": "https://clubs.lapis.codes",
|
||||||
|
"Rooms": "https://rooms.lapis.codes",
|
||||||
|
"PlatformNotifications": "https://api.lapis.codes",
|
||||||
|
"Moderation": "https://api.lapis.codes",
|
||||||
|
"DataCollection": "https://api.lapis.codes",
|
||||||
|
"BugReporting": "https://api.lapis.codes",
|
||||||
|
"Discovery": "https://api.lapis.codes",
|
||||||
|
"PlayerSettings": "https://api.lapis.codes",
|
||||||
|
"Rendering": "https://api.lapis.codes",
|
||||||
|
"Launcher": "https://rr.lapis.codes"
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20260331191343_InitialCreate")]
|
||||||
|
partial class InitialCreate
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.Account", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "createdAt");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "displayName");
|
||||||
|
|
||||||
|
b.Property<int?>("IdentityFlags")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "identityFlags");
|
||||||
|
|
||||||
|
b.Property<bool>("IsJunior")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "isJunior");
|
||||||
|
|
||||||
|
b.Property<int?>("PersonalPronouns")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "personalPronouns");
|
||||||
|
|
||||||
|
b.Property<int?>("Platforms")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platforms");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileImage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "profileImage");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "username");
|
||||||
|
|
||||||
|
b.HasKey("AccountId");
|
||||||
|
|
||||||
|
b.ToTable("accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.CachedLogin", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLoginTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "lastLoginTime");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platform");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformId");
|
||||||
|
|
||||||
|
b.Property<bool>("RequirePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "requirePassword");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("cached_logins", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class InitialCreate : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "accounts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
AccountId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
ProfileImage = table.Column<string>(type: "text", nullable: true),
|
||||||
|
IsJunior = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
Platforms = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
PersonalPronouns = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
IdentityFlags = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
Username = table.Column<string>(type: "text", nullable: false),
|
||||||
|
DisplayName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_accounts", x => x.AccountId);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "cached_logins",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
AccountId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Platform = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
PlatformID = table.Column<string>(type: "text", nullable: false),
|
||||||
|
LastLoginTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
RequirePassword = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_cached_logins", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_cached_logins_Platform_PlatformID",
|
||||||
|
table: "cached_logins",
|
||||||
|
columns: new[] { "Platform", "PlatformID" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "accounts");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "cached_logins");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20260401002616_AddPlayerProgressions")]
|
||||||
|
partial class AddPlayerProgressions
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.Account", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "createdAt");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "displayName");
|
||||||
|
|
||||||
|
b.Property<int?>("IdentityFlags")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "identityFlags");
|
||||||
|
|
||||||
|
b.Property<bool>("IsJunior")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "isJunior");
|
||||||
|
|
||||||
|
b.Property<int?>("PersonalPronouns")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "personalPronouns");
|
||||||
|
|
||||||
|
b.Property<int?>("Platforms")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platforms");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileImage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "profileImage");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "username");
|
||||||
|
|
||||||
|
b.HasKey("AccountId");
|
||||||
|
|
||||||
|
b.ToTable("accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.CachedLogin", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLoginTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "lastLoginTime");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platform");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformId");
|
||||||
|
|
||||||
|
b.Property<bool>("RequirePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "requirePassword");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("cached_logins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerProgression", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "level");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<int>("Xp")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "xp");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_progressions", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPlayerProgressions : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "player_progressions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
PlayerId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Level = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Xp = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_player_progressions", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_progressions_PlayerId",
|
||||||
|
table: "player_progressions",
|
||||||
|
column: "PlayerId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "player_progressions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20260401123437_AddPlayerSettings")]
|
||||||
|
partial class AddPlayerSettings
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.Account", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "createdAt");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "displayName");
|
||||||
|
|
||||||
|
b.Property<int?>("IdentityFlags")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "identityFlags");
|
||||||
|
|
||||||
|
b.Property<bool>("IsJunior")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "isJunior");
|
||||||
|
|
||||||
|
b.Property<int?>("PersonalPronouns")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "personalPronouns");
|
||||||
|
|
||||||
|
b.Property<int?>("Platforms")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platforms");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileImage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "profileImage");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "username");
|
||||||
|
|
||||||
|
b.HasKey("AccountId");
|
||||||
|
|
||||||
|
b.ToTable("accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.CachedLogin", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLoginTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "lastLoginTime");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platform");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformId");
|
||||||
|
|
||||||
|
b.Property<bool>("RequirePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "requirePassword");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("cached_logins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerProgression", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "level");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<int>("Xp")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "xp");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_progressions", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "key");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId", "Key")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_settings", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPlayerSettings : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "player_settings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
PlayerId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Key = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Value = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_player_settings", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_settings_PlayerId_Key",
|
||||||
|
table: "player_settings",
|
||||||
|
columns: new[] { "PlayerId", "Key" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "player_settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
[Migration("20260401125651_AddPlayerAvatars")]
|
||||||
|
partial class AddPlayerAvatars
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.Account", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "createdAt");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "displayName");
|
||||||
|
|
||||||
|
b.Property<int?>("IdentityFlags")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "identityFlags");
|
||||||
|
|
||||||
|
b.Property<bool>("IsJunior")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "isJunior");
|
||||||
|
|
||||||
|
b.Property<int?>("PersonalPronouns")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "personalPronouns");
|
||||||
|
|
||||||
|
b.Property<int?>("Platforms")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platforms");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileImage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "profileImage");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "username");
|
||||||
|
|
||||||
|
b.HasKey("AccountId");
|
||||||
|
|
||||||
|
b.ToTable("accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.AvatarItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AvatarItemDesc")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "avatarItemDesc");
|
||||||
|
|
||||||
|
b.Property<int>("AvatarItemType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "avatarItemType");
|
||||||
|
|
||||||
|
b.Property<string>("FriendlyName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "friendlyName");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerAccountId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PlatformMask")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformMask");
|
||||||
|
|
||||||
|
b.Property<int>("Rarity")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "rarity");
|
||||||
|
|
||||||
|
b.Property<string>("Tooltip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "tooltip");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerAccountId");
|
||||||
|
|
||||||
|
b.ToTable("avatar_items", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.CachedLogin", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLoginTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "lastLoginTime");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platform");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformId");
|
||||||
|
|
||||||
|
b.Property<bool>("RequirePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "requirePassword");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("cached_logins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerAvatar", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("FaceFeatures")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "FaceFeatures");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "HairColor");
|
||||||
|
|
||||||
|
b.Property<string>("OutfitSelections")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "OutfitSelections");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerAccountId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "SkinColor");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerAccountId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_avatars", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerProgression", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "level");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<int>("Xp")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "xp");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_progressions", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "key");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId", "Key")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_settings", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPlayerAvatars : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "avatar_items",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
AvatarItemType = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
AvatarItemDesc = table.Column<string>(type: "text", nullable: false),
|
||||||
|
PlatformMask = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
FriendlyName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Tooltip = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Rarity = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
OwnerAccountId = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_avatar_items", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "player_avatars",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
OwnerAccountId = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
OutfitSelections = table.Column<string>(type: "text", nullable: false),
|
||||||
|
FaceFeatures = table.Column<string>(type: "text", nullable: false),
|
||||||
|
SkinColor = table.Column<string>(type: "text", nullable: false),
|
||||||
|
HairColor = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_player_avatars", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_avatar_items_OwnerAccountId",
|
||||||
|
table: "avatar_items",
|
||||||
|
column: "OwnerAccountId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_avatars_OwnerAccountId",
|
||||||
|
table: "player_avatars",
|
||||||
|
column: "OwnerAccountId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "avatar_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "player_avatars");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CannedNet.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDbContext))]
|
||||||
|
partial class AppDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.Account", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "createdAt");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "displayName");
|
||||||
|
|
||||||
|
b.Property<int?>("IdentityFlags")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "identityFlags");
|
||||||
|
|
||||||
|
b.Property<bool>("IsJunior")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "isJunior");
|
||||||
|
|
||||||
|
b.Property<int?>("PersonalPronouns")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "personalPronouns");
|
||||||
|
|
||||||
|
b.Property<int?>("Platforms")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platforms");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileImage")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "profileImage");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "username");
|
||||||
|
|
||||||
|
b.HasKey("AccountId");
|
||||||
|
|
||||||
|
b.ToTable("accounts", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.AvatarItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AvatarItemDesc")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "avatarItemDesc");
|
||||||
|
|
||||||
|
b.Property<int>("AvatarItemType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "avatarItemType");
|
||||||
|
|
||||||
|
b.Property<string>("FriendlyName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "friendlyName");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerAccountId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PlatformMask")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformMask");
|
||||||
|
|
||||||
|
b.Property<int>("Rarity")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "rarity");
|
||||||
|
|
||||||
|
b.Property<string>("Tooltip")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "tooltip");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerAccountId");
|
||||||
|
|
||||||
|
b.ToTable("avatar_items", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.CachedLogin", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AccountId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "accountId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastLoginTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "lastLoginTime");
|
||||||
|
|
||||||
|
b.Property<int>("Platform")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platform");
|
||||||
|
|
||||||
|
b.Property<string>("PlatformID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "platformId");
|
||||||
|
|
||||||
|
b.Property<bool>("RequirePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "requirePassword");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Platform", "PlatformID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("cached_logins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerAvatar", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("FaceFeatures")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "FaceFeatures");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "HairColor");
|
||||||
|
|
||||||
|
b.Property<string>("OutfitSelections")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "OutfitSelections");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerAccountId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "SkinColor");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerAccountId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_avatars", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerProgression", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "level");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<int>("Xp")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "xp");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_progressions", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CannedNet.PlayerSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "key");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "playerId");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasAnnotation("Relational:JsonPropertyName", "value");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId", "Key")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player_settings", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class AvatarItem
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatarItemType")]
|
||||||
|
public int AvatarItemType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatarItemDesc")]
|
||||||
|
public string AvatarItemDesc { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("platformMask")]
|
||||||
|
public int PlatformMask { get; set; } = -1;
|
||||||
|
|
||||||
|
[JsonPropertyName("friendlyName")]
|
||||||
|
public string FriendlyName { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("tooltip")]
|
||||||
|
public string Tooltip { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("rarity")]
|
||||||
|
public int Rarity { get; set; } = 0;
|
||||||
|
|
||||||
|
public int OwnerAccountId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class NotificationMessage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("notificationId")]
|
||||||
|
public string? NotificationId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("notificationType")]
|
||||||
|
public string? NotificationType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("fromAccountId")]
|
||||||
|
public int? FromAccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("toAccountId")]
|
||||||
|
public int? ToAccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("createdAt")]
|
||||||
|
public DateTime? CreatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("data")]
|
||||||
|
public Dictionary<string, object>? Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubscriptionUpdateProfile
|
||||||
|
{
|
||||||
|
[JsonPropertyName("accountId")]
|
||||||
|
public int? AccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("profileImage")]
|
||||||
|
public string? ProfileImage { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("displayName")]
|
||||||
|
public string? DisplayName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public string? Username { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubscriptionUpdatePresence
|
||||||
|
{
|
||||||
|
[JsonPropertyName("accountId")]
|
||||||
|
public int? AccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("presence")]
|
||||||
|
public string? Presence { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("currentRoomId")]
|
||||||
|
public string? CurrentRoomId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("currentWorldId")]
|
||||||
|
public string? CurrentWorldId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("lastSeen")]
|
||||||
|
public DateTime? LastSeen { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubscriptionUpdateGameSession
|
||||||
|
{
|
||||||
|
[JsonPropertyName("gameSessionId")]
|
||||||
|
public string? GameSessionId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("roomId")]
|
||||||
|
public string? RoomId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("worldId")]
|
||||||
|
public string? WorldId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("players")]
|
||||||
|
public List<int>? Players { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubscriptionUpdateRoom
|
||||||
|
{
|
||||||
|
[JsonPropertyName("roomId")]
|
||||||
|
public string? RoomId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("worldId")]
|
||||||
|
public string? WorldId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("roomName")]
|
||||||
|
public string? RoomName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("version")]
|
||||||
|
public string? Version { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RelationshipChangedNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("accountId")]
|
||||||
|
public int? AccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("relationshipType")]
|
||||||
|
public string? RelationshipType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("status")]
|
||||||
|
public string? Status { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PresenceHeartbeatResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("currentRoomId")]
|
||||||
|
public string? CurrentRoomId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("currentWorldId")]
|
||||||
|
public string? CurrentWorldId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("presence")]
|
||||||
|
public string? Presence { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModerationNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("reason")]
|
||||||
|
public string? Reason { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("duration")]
|
||||||
|
public int? Duration { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("moderatedBy")]
|
||||||
|
public string? ModeratedBy { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("message")]
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gameSessionId")]
|
||||||
|
public string? GameSessionId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GiftPackageNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("giftPackageId")]
|
||||||
|
public string? GiftPackageId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("fromAccountId")]
|
||||||
|
public int? FromAccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("giftType")]
|
||||||
|
public string? GiftType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StorefrontBalanceNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("balance")]
|
||||||
|
public decimal? Balance { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("currency")]
|
||||||
|
public string? Currency { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("purchaseId")]
|
||||||
|
public string? PurchaseId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConsumableMappingNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("mappingId")]
|
||||||
|
public string? MappingId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("consumableId")]
|
||||||
|
public string? ConsumableId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("quantity")]
|
||||||
|
public int? Quantity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerEventNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("eventId")]
|
||||||
|
public string? EventId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("eventName")]
|
||||||
|
public string? EventName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("eventType")]
|
||||||
|
public string? EventType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("worldId")]
|
||||||
|
public string? WorldId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("responseStatus")]
|
||||||
|
public string? ResponseStatus { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("state")]
|
||||||
|
public string? State { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChatMessageNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("channelId")]
|
||||||
|
public string? ChannelId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("fromAccountId")]
|
||||||
|
public int? FromAccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("messageId")]
|
||||||
|
public string? MessageId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("message")]
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("channelType")]
|
||||||
|
public string? ChannelType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommunityBoardNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("boardId")]
|
||||||
|
public string? BoardId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("announcementId")]
|
||||||
|
public string? AnnouncementId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("title")]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("content")]
|
||||||
|
public string? Content { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InventionModerationNotification
|
||||||
|
{
|
||||||
|
[JsonPropertyName("inventionId")]
|
||||||
|
public string? InventionId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("moderationState")]
|
||||||
|
public string? ModerationState { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public enum PushNotificationId
|
||||||
|
{
|
||||||
|
RelationshipChanged = 1,
|
||||||
|
MessageReceived = 2,
|
||||||
|
MessageDeleted = 3,
|
||||||
|
PresenceHeartbeatResponse = 4,
|
||||||
|
RefreshLogin = 5,
|
||||||
|
Logout = 6,
|
||||||
|
SubscriptionUpdateProfile = 11,
|
||||||
|
SubscriptionUpdatePresence = 12,
|
||||||
|
SubscriptionUpdateGameSession = 13,
|
||||||
|
SubscriptionUpdateRoom = 15,
|
||||||
|
ModerationQuitGame = 20,
|
||||||
|
ModerationUpdateRequired = 21,
|
||||||
|
ModerationKick = 22,
|
||||||
|
ModerationKickAttemptFailed = 23,
|
||||||
|
ModerationRoomBan = 24,
|
||||||
|
ServerMaintenance = 25,
|
||||||
|
GiftPackageReceived = 30,
|
||||||
|
GiftPackageReceivedImmediate = 31,
|
||||||
|
ProfileJuniorStatusUpdate = 40,
|
||||||
|
RelationshipsInvalid = 50,
|
||||||
|
StorefrontBalanceAdd = 60,
|
||||||
|
StorefrontBalanceUpdate = 61,
|
||||||
|
StorefrontBalancePurchase = 62,
|
||||||
|
ConsumableMappingAdded = 70,
|
||||||
|
ConsumableMappingRemoved = 71,
|
||||||
|
PlayerEventCreated = 80,
|
||||||
|
PlayerEventUpdated = 81,
|
||||||
|
PlayerEventDeleted = 82,
|
||||||
|
PlayerEventResponseChanged = 83,
|
||||||
|
PlayerEventResponseDeleted = 84,
|
||||||
|
PlayerEventStateChanged = 85,
|
||||||
|
ChatMessageReceived = 90,
|
||||||
|
CommunityBoardUpdate = 95,
|
||||||
|
CommunityBoardAnnouncementUpdate = 96,
|
||||||
|
InventionModerationStateChanged = 100
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class PlayerAvatar
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int OwnerAccountId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("OutfitSelections")]
|
||||||
|
public string OutfitSelections { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("FaceFeatures")]
|
||||||
|
public string FaceFeatures { get; set; } = "{}";
|
||||||
|
|
||||||
|
[JsonPropertyName("SkinColor")]
|
||||||
|
public string SkinColor { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("HairColor")]
|
||||||
|
public string HairColor { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class PlayerProgression
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
[JsonPropertyName("playerId")]
|
||||||
|
public int PlayerId { get; set; }
|
||||||
|
[JsonPropertyName("level")]
|
||||||
|
public int Level { get; set; }
|
||||||
|
[JsonPropertyName("xp")]
|
||||||
|
public int Xp { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerProgressionBulkResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("playerId")]
|
||||||
|
public int PlayerId { get; set; }
|
||||||
|
[JsonPropertyName("level")]
|
||||||
|
public int Level { get; set; }
|
||||||
|
[JsonPropertyName("xp")]
|
||||||
|
public int Xp { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class PlayerSetting
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
[JsonPropertyName("playerId")]
|
||||||
|
public int PlayerId { get; set; }
|
||||||
|
[JsonPropertyName("key")]
|
||||||
|
public string Key { get; set; }
|
||||||
|
[JsonPropertyName("value")]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class SettingPayload
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CannedNet;
|
||||||
|
|
||||||
|
public class SubscriptionList
|
||||||
|
{
|
||||||
|
[JsonPropertyName("playerIds")]
|
||||||
|
public List<int>? PlayerIds { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using CannedNet;
|
||||||
|
using CannedNet.Services;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
var apps = new List<(WebApplication App, ServiceRegistry Service)>();
|
||||||
|
|
||||||
|
foreach (var service in Services.All)
|
||||||
|
{
|
||||||
|
var builder = WebApplication.CreateBuilder();
|
||||||
|
|
||||||
|
service.ConfigureBuilder(builder);
|
||||||
|
builder.WebHost.UseUrls($"http://*:{service.Port}");
|
||||||
|
builder.Configuration.AddJsonFile($"AppConfigs/appsettings.{service.Name}.json", optional: true, reloadOnChange: true);
|
||||||
|
|
||||||
|
apps.Add((builder.Build(), service));
|
||||||
|
}
|
||||||
|
|
||||||
|
using var scope = apps[0].App.Services.CreateScope();
|
||||||
|
scope.ServiceProvider.GetRequiredService<CannedNet.Data.AppDbContext>().Database.Migrate();
|
||||||
|
var jwtService = scope.ServiceProvider.GetRequiredService<JwtTokenService>();
|
||||||
|
|
||||||
|
foreach (var (app, service) in apps)
|
||||||
|
service.MapEndpoints(app, jwtService);
|
||||||
|
|
||||||
|
await Task.WhenAll(apps.Select(t => t.App.RunAsync()));
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
using CannedNet;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class APIService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
var jwtService = app.Services.GetRequiredService<JwtTokenService>();
|
||||||
|
|
||||||
|
app.MapGet("/api/config/v1/amplitude", () => Results.Ok(new
|
||||||
|
{
|
||||||
|
AmplitudeKey = "fd846cd67066d19eec62fbdd00be9258",
|
||||||
|
StatSigKey = "client-mnew4Ggjuu3Fbh86Ed3tRgWUxapp0D7PPB0i3MXUEao",
|
||||||
|
RudderStackKey = "37qVlzZyXqdmZckXJ61vQeEJp8Y",
|
||||||
|
UseRudderStack = false
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.MapGet("/api/config/v2", () => Results.Content(File.ReadAllText("JSON/configv2.json"), "application/json"));
|
||||||
|
app.MapGet("/api/versioncheck/v4", () => Results.Content("{\"VersionStatus\":0}", "application/json"));
|
||||||
|
app.MapGet("/api/gameconfigs/v1/all", () => Results.Content(File.ReadAllText("JSON/gameconfigs.json"), "application/json"));
|
||||||
|
|
||||||
|
app.MapGet("/api/relationships/v2/get", () => Results.Content("[]", "application/json"));
|
||||||
|
app.MapGet("/api/messages/v2/get", () => Results.Content("[]", "application/json"));
|
||||||
|
|
||||||
|
app.MapGet("/api/playerReputation/v1/{id}", (string id) =>
|
||||||
|
Results.Content($"{{\"AccountId\":{id},\"Noteriety\":0,\"CheerGeneral\":0,\"CheerHelpful\":0,\"CheerCreative\":0,\"CheerGreatHost\":0,\"CheerSportsman\":0,\"CheerCredit\":20,\"SelectedCheer\":null}}", "application/json"));
|
||||||
|
|
||||||
|
app.MapGet("/api/players/v1/progression/{id}", (string id) =>
|
||||||
|
Results.Content($"{{\"PlayerId\":{id},\"Level\":1,\"XP\":0}}", "application/json"));
|
||||||
|
|
||||||
|
app.MapPost("/api/players/v1/progression/bulk", async (HttpRequest httpRequest, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var ids = new List<int>();
|
||||||
|
|
||||||
|
if (httpRequest.ContentLength.HasValue && httpRequest.ContentLength > 0)
|
||||||
|
{
|
||||||
|
httpRequest.EnableBuffering();
|
||||||
|
using var reader = new StreamReader(httpRequest.Body, leaveOpen: true);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(body))
|
||||||
|
{
|
||||||
|
foreach (var pair in body.Split('&'))
|
||||||
|
{
|
||||||
|
var keyValue = pair.Split('=');
|
||||||
|
if (keyValue.Length == 2 && keyValue[0] == "Ids")
|
||||||
|
{
|
||||||
|
var idString = Uri.UnescapeDataString(keyValue[1]);
|
||||||
|
foreach (var id in idString.Split(','))
|
||||||
|
if (int.TryParse(id, out var parsedId))
|
||||||
|
ids.Add(parsedId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpRequest.Body.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ids.Any())
|
||||||
|
return Results.Json(new List<PlayerProgressionBulkResponse>());
|
||||||
|
|
||||||
|
var progressions = await db.PlayerProgressions
|
||||||
|
.Where(p => ids.Contains(p.PlayerId))
|
||||||
|
.Select(p => new PlayerProgressionBulkResponse { PlayerId = p.PlayerId, Level = p.Level, Xp = p.Xp })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return Results.Json(progressions);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/avatar/v4/items", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var items = await db.AvatarItems
|
||||||
|
.Where(i => i.OwnerAccountId == id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return Results.Json(items);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/avatar/v2", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var avatar = await db.PlayerAvatars
|
||||||
|
.FirstOrDefaultAsync(a => a.OwnerAccountId == id);
|
||||||
|
|
||||||
|
if (avatar == null)
|
||||||
|
{
|
||||||
|
avatar = new PlayerAvatar
|
||||||
|
{
|
||||||
|
OwnerAccountId = id,
|
||||||
|
OutfitSelections = "",
|
||||||
|
FaceFeatures = "{}",
|
||||||
|
SkinColor = "",
|
||||||
|
HairColor = ""
|
||||||
|
};
|
||||||
|
db.PlayerAvatars.Add(avatar);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Json(avatar);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/api/avatar/v2/set", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
request.EnableBuffering();
|
||||||
|
var avatarUpdate = await System.Text.Json.JsonSerializer.DeserializeAsync<PlayerAvatar>(request.Body);
|
||||||
|
|
||||||
|
if (avatarUpdate == null)
|
||||||
|
return Results.BadRequest();
|
||||||
|
|
||||||
|
var avatar = await db.PlayerAvatars
|
||||||
|
.FirstOrDefaultAsync(a => a.OwnerAccountId == id);
|
||||||
|
|
||||||
|
if (avatar == null)
|
||||||
|
{
|
||||||
|
avatar = new PlayerAvatar { OwnerAccountId = id };
|
||||||
|
db.PlayerAvatars.Add(avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatar.OutfitSelections = avatarUpdate.OutfitSelections;
|
||||||
|
avatar.FaceFeatures = avatarUpdate.FaceFeatures;
|
||||||
|
avatar.SkinColor = avatarUpdate.SkinColor;
|
||||||
|
avatar.HairColor = avatarUpdate.HairColor;
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
return Results.Ok(avatar);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/api/PlayerReporting/v1/moderationBlockDetails", () =>
|
||||||
|
Results.Content("{\"ReportCategory\":0,\"Duration\":0,\"GameSessionId\":0,\"IsHostKick\":false,\"Message\":\"\",\"PlayerIdReporter\":null,\"IsBan\":false}", "application/json"));
|
||||||
|
|
||||||
|
app.MapGet("/api/settings/v2" +
|
||||||
|
"", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var settings = await db.PlayerSettings
|
||||||
|
.Where(s => s.PlayerId == id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return Results.Json(settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/api/settings/v2/set", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
request.EnableBuffering();
|
||||||
|
request.Body.Position = 0;
|
||||||
|
using var reader = new StreamReader(request.Body);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
var settings = new List<PlayerSetting>();
|
||||||
|
|
||||||
|
if (body.TrimStart().StartsWith("["))
|
||||||
|
{
|
||||||
|
settings = System.Text.Json.JsonSerializer.Deserialize<List<PlayerSetting>>(body) ?? [];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var single = System.Text.Json.JsonSerializer.Deserialize<PlayerSetting>(body);
|
||||||
|
if (single != null) settings.Add(single);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.Any())
|
||||||
|
return Results.BadRequest("No settings provided");
|
||||||
|
|
||||||
|
db.PlayerSettings.RemoveRange(db.PlayerSettings.Where(s => s.PlayerId == id));
|
||||||
|
|
||||||
|
foreach (var setting in settings)
|
||||||
|
{
|
||||||
|
setting.PlayerId = id;
|
||||||
|
db.PlayerSettings.Add(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
return Results.Ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
using CannedNet.Data;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class AccountsService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app, JwtTokenService jwtService)
|
||||||
|
{
|
||||||
|
app.MapGet("/", (HttpRequest request) =>
|
||||||
|
{
|
||||||
|
return Results.Ok("FUCKL MYSJDIOJD");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/account/me", (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var selfAccount = new SelfAccount
|
||||||
|
{
|
||||||
|
AccountId = id,
|
||||||
|
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = false,
|
||||||
|
Platforms = 0,
|
||||||
|
PersonalPronouns = 0,
|
||||||
|
IdentityFlags = 0,
|
||||||
|
Username = $"Player{id}",
|
||||||
|
DisplayName = $"Player{id}",
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
Email = null,
|
||||||
|
Phone = null,
|
||||||
|
JuniorState = null,
|
||||||
|
Birthday = null,
|
||||||
|
ParentAccountId = null,
|
||||||
|
AvailableUsernameChanges = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return Results.Ok(selfAccount);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/account/bulk", (HttpRequest request) =>
|
||||||
|
{
|
||||||
|
var ids = request.Query["id"];
|
||||||
|
var accounts = new List<Account>();
|
||||||
|
|
||||||
|
foreach (var id in ids)
|
||||||
|
{
|
||||||
|
if (int.TryParse(id, out var accountId))
|
||||||
|
{
|
||||||
|
accounts.Add(new Account
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = false,
|
||||||
|
Platforms = 0,
|
||||||
|
PersonalPronouns = 0,
|
||||||
|
IdentityFlags = 0,
|
||||||
|
Username = $"Player{accountId}",
|
||||||
|
DisplayName = $"Player{accountId}",
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Json(accounts);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/account/create", async (HttpRequest httpRequest, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
int platform = 0;
|
||||||
|
string platformId = "";
|
||||||
|
|
||||||
|
if (httpRequest.ContentLength.HasValue && httpRequest.ContentLength > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var contentType = httpRequest.ContentType ?? "";
|
||||||
|
httpRequest.EnableBuffering();
|
||||||
|
|
||||||
|
using var reader = new StreamReader(httpRequest.Body, leaveOpen: true);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(body) && contentType.Contains("application/x-www-form-urlencoded"))
|
||||||
|
{
|
||||||
|
foreach (var pair in body.Split('&'))
|
||||||
|
{
|
||||||
|
var keyValue = pair.Split('=');
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||||
|
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||||
|
|
||||||
|
if (key == "platform" && int.TryParse(value, out var parsedPlatform))
|
||||||
|
platform = parsedPlatform;
|
||||||
|
else if (key == "platformId")
|
||||||
|
platformId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpRequest.Body.Position = 0;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountId = new Random().Next(10000, 99999);
|
||||||
|
var account = new Account
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = false,
|
||||||
|
Platforms = 0,
|
||||||
|
PersonalPronouns = 0,
|
||||||
|
IdentityFlags = 0,
|
||||||
|
Username = $"Player{accountId}",
|
||||||
|
DisplayName = $"Player{accountId}",
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
db.Accounts.Add(account);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(platformId))
|
||||||
|
{
|
||||||
|
db.CachedLogins.Add(new CachedLogin
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
Platform = (PlatformType)platform,
|
||||||
|
PlatformID = platformId,
|
||||||
|
LastLoginTime = DateTime.UtcNow,
|
||||||
|
RequirePassword = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Results.Ok(RecNetResultWithValue<Account>.Ok(account));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using CannedNet;
|
||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class AuthService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
var jwtService = app.Services.GetRequiredService<JwtTokenService>();
|
||||||
|
|
||||||
|
app.MapGet("/eac/challenge", () =>
|
||||||
|
{
|
||||||
|
var file = File.ReadAllText("JSON/eacchallenge.txt");
|
||||||
|
return Results.Content(file, "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/cachedlogin/forplatformid/{platform}/{id}", async (string platform, string id, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var platformType = int.Parse(platform);
|
||||||
|
var logins = await db.CachedLogins
|
||||||
|
.Where(c => c.Platform == (PlatformType)platformType && c.PlatformID == id)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return Results.Json(logins.Any() ? logins : new List<object>());
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/connect/token", async (HttpRequest httpRequest) =>
|
||||||
|
{
|
||||||
|
string accountId = "";
|
||||||
|
string platformId = "";
|
||||||
|
string platform = "";
|
||||||
|
|
||||||
|
if (httpRequest.ContentLength.HasValue && httpRequest.ContentLength > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
httpRequest.EnableBuffering();
|
||||||
|
using var reader = new StreamReader(httpRequest.Body, leaveOpen: true);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(body))
|
||||||
|
{
|
||||||
|
foreach (var pair in body.Split('&'))
|
||||||
|
{
|
||||||
|
var keyValue = pair.Split('=');
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||||
|
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||||
|
|
||||||
|
if (key == "account_id")
|
||||||
|
accountId = value;
|
||||||
|
else if (key == "platform_id")
|
||||||
|
platformId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpRequest.Body.Position = 0;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessToken = jwtService.GenerateToken(accountId, platformId, platform);
|
||||||
|
|
||||||
|
return Results.Json(new
|
||||||
|
{
|
||||||
|
access_token = accessToken,
|
||||||
|
expires_in = 3600,
|
||||||
|
token_type = "Bearer",
|
||||||
|
refresh_token = Guid.NewGuid().ToString("N").ToUpper() + "-1",
|
||||||
|
scope = "offline_access profile rn rn.accounts rn.accounts.gc rn.api rn.chat rn.clubs rn.commerce rn.match.read rn.match.write rn.notify rn.rooms rn.storage",
|
||||||
|
key = "8oQ+e+WQaOBPbEcakhqs3dwZZdOmmyDUmJSD9u4AHMY="
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class ChatService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
app.MapGet("/thread", () => Results.Content("[]", "application/json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,8 +65,8 @@ public class JwtTokenService
|
|||||||
|
|
||||||
var handler = new JwtSecurityTokenHandler();
|
var handler = new JwtSecurityTokenHandler();
|
||||||
var token = handler.CreateJwtSecurityToken(
|
var token = handler.CreateJwtSecurityToken(
|
||||||
issuer: "https://auth.epicquest.live",
|
issuer: "https://auth.lapis.codes",
|
||||||
audience: "https://auth.epicquest.live/resources",
|
audience: "https://auth.lapis.codes/resources",
|
||||||
subject: identity,
|
subject: identity,
|
||||||
notBefore: now,
|
notBefore: now,
|
||||||
issuedAt: now,
|
issuedAt: now,
|
||||||
@@ -88,9 +88,9 @@ public class JwtTokenService
|
|||||||
ValidateIssuerSigningKey = true,
|
ValidateIssuerSigningKey = true,
|
||||||
IssuerSigningKey = _securityKey,
|
IssuerSigningKey = _securityKey,
|
||||||
ValidateIssuer = true,
|
ValidateIssuer = true,
|
||||||
ValidIssuer = "https://auth.epicquest.live",
|
ValidIssuer = "https://auth.lapis.codes",
|
||||||
ValidateAudience = true,
|
ValidateAudience = true,
|
||||||
ValidAudience = "https://auth.epicquest.live/resources",
|
ValidAudience = "https://auth.lapis.codes/resources",
|
||||||
ValidateLifetime = true,
|
ValidateLifetime = true,
|
||||||
ClockSkew = TimeSpan.Zero
|
ClockSkew = TimeSpan.Zero
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class MatchmakingService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
app.MapPost("/player/login", () => Results.Ok());
|
||||||
|
|
||||||
|
app.MapGet("/player", (HttpRequest request) =>
|
||||||
|
{
|
||||||
|
var id = request.Query["id"];
|
||||||
|
var accounts = new List<Account>();
|
||||||
|
|
||||||
|
if (int.TryParse(id, out var accountId))
|
||||||
|
{
|
||||||
|
accounts.Add(new Account
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = false,
|
||||||
|
Platforms = 0,
|
||||||
|
PersonalPronouns = 0,
|
||||||
|
IdentityFlags = 0,
|
||||||
|
Username = $"Player{accountId}",
|
||||||
|
DisplayName = $"Player{accountId}",
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Json(accounts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using CannedNet.Hubs;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class NSService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
app.MapGet("/", () =>
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText("JSON/endpoints.json");
|
||||||
|
return Results.Content(json, "application/json");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/photon", () =>
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText("JSON/photonsettings.json");
|
||||||
|
return Results.Content(json, "application/json");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class NotificationService
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, HashSet<int>> _connectionSubscriptions = new();
|
||||||
|
private readonly ConcurrentDictionary<int, HashSet<string>> _playerConnections = new();
|
||||||
|
|
||||||
|
public void OnConnected(string connectionId)
|
||||||
|
{
|
||||||
|
_connectionSubscriptions.TryAdd(connectionId, new HashSet<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDisconnected(string connectionId)
|
||||||
|
{
|
||||||
|
if (_connectionSubscriptions.TryRemove(connectionId, out var subscriptions))
|
||||||
|
{
|
||||||
|
foreach (var playerId in subscriptions)
|
||||||
|
{
|
||||||
|
if (_playerConnections.TryGetValue(playerId, out var connections))
|
||||||
|
{
|
||||||
|
connections.Remove(connectionId);
|
||||||
|
if (connections.Count == 0)
|
||||||
|
{
|
||||||
|
_playerConnections.TryRemove(playerId, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SubscribeToPlayers(string connectionId, SubscriptionList subscriptionList)
|
||||||
|
{
|
||||||
|
var oldSubscriptions = _connectionSubscriptions.GetValueOrDefault(connectionId, new HashSet<int>());
|
||||||
|
var newPlayerIds = subscriptionList.PlayerIds ?? new List<int>();
|
||||||
|
|
||||||
|
_connectionSubscriptions[connectionId] = new HashSet<int>(newPlayerIds);
|
||||||
|
|
||||||
|
foreach (var playerId in newPlayerIds)
|
||||||
|
{
|
||||||
|
_playerConnections.AddOrUpdate(
|
||||||
|
playerId,
|
||||||
|
_ => new HashSet<string> { connectionId },
|
||||||
|
(_, existing) =>
|
||||||
|
{
|
||||||
|
existing.Add(connectionId);
|
||||||
|
return existing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var playerId in oldSubscriptions)
|
||||||
|
{
|
||||||
|
if (!newPlayerIds.Contains(playerId) && _playerConnections.TryGetValue(playerId, out var connections))
|
||||||
|
{
|
||||||
|
connections.Remove(connectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashSet<int>? GetSubscriptions(string connectionId)
|
||||||
|
{
|
||||||
|
return _connectionSubscriptions.GetValueOrDefault(connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> GetConnectionsForPlayer(int playerId)
|
||||||
|
{
|
||||||
|
if (_playerConnections.TryGetValue(playerId, out var connections))
|
||||||
|
{
|
||||||
|
return connections.ToList();
|
||||||
|
}
|
||||||
|
return Enumerable.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<int> GetSubscribedPlayers(string connectionId)
|
||||||
|
{
|
||||||
|
if (_connectionSubscriptions.TryGetValue(connectionId, out var subscriptions))
|
||||||
|
{
|
||||||
|
return subscriptions.ToList();
|
||||||
|
}
|
||||||
|
return Enumerable.Empty<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendNotificationToPlayer(string callerConnectionId, IHubContext hubContext, int playerId, NotificationMessage notification)
|
||||||
|
{
|
||||||
|
var connections = GetConnectionsForPlayer(playerId);
|
||||||
|
foreach (var connectionId in connections)
|
||||||
|
{
|
||||||
|
if (connectionId == callerConnectionId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await hubContext.Clients.Client(connectionId).SendAsync("Notification", notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task BroadcastNotification(IHubContext hubContext, NotificationMessage notification)
|
||||||
|
{
|
||||||
|
await hubContext.Clients.All.SendAsync("Notification", notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationMessage CreateNotification(string notificationType, int? id = null, int? fromAccountId = null, int? toAccountId = null, Dictionary<string, object>? data = null)
|
||||||
|
{
|
||||||
|
return new NotificationMessage
|
||||||
|
{
|
||||||
|
NotificationId = Guid.NewGuid().ToString("N"),
|
||||||
|
NotificationType = notificationType,
|
||||||
|
Id = id,
|
||||||
|
FromAccountId = fromAccountId,
|
||||||
|
ToAccountId = toAccountId,
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
Data = data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using CannedNet.Hubs;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class NotifyService
|
||||||
|
{
|
||||||
|
public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
|
|
||||||
|
public void MapEndpoints(WebApplication app)
|
||||||
|
{
|
||||||
|
app.MapHub<NotificationsHub>("/hub/v1");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using CannedNet.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public static class ServiceExtensions
|
||||||
|
{
|
||||||
|
public static void ConfigureRecNetServices(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||||
|
options.SerializerOptions.PropertyNamingPolicy = null);
|
||||||
|
|
||||||
|
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
|
||||||
|
?? "Host=localhost;Port=5432;Database=cannednet;Username=postgres;Password=postgres";
|
||||||
|
|
||||||
|
builder.Services.AddDbContext<AppDbContext>(options =>
|
||||||
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
|
builder.Services.AddScoped<JwtTokenService>();
|
||||||
|
builder.Services.AddSingleton<NotificationService>();
|
||||||
|
builder.Services.AddSignalR();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ConfigureHostUrl(this WebApplicationBuilder builder, string defaultUrl)
|
||||||
|
{
|
||||||
|
var url = builder.Configuration["Hosting:Url"];
|
||||||
|
builder.WebHost.UseUrls(string.IsNullOrWhiteSpace(url) ? defaultUrl : url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebApplicationBuilder CreateRecNetBuilder(string[]? args) =>
|
||||||
|
WebApplication.CreateBuilder(args ?? []);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
|
public class ServiceRegistry
|
||||||
|
{
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required int Port { get; init; }
|
||||||
|
public required Type ServiceType { get; init; }
|
||||||
|
public required Action<WebApplicationBuilder> ConfigureBuilder { get; init; }
|
||||||
|
public required Action<WebApplication, JwtTokenService> MapEndpoints { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Services
|
||||||
|
{
|
||||||
|
public static readonly List<ServiceRegistry> All =
|
||||||
|
[
|
||||||
|
new() { Name = "NS", Port = 5001, ServiceType = typeof(NSService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, _) => new NSService().MapEndpoints(app) },
|
||||||
|
new() { Name = "API", Port = 5000, ServiceType = typeof(APIService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, _) => new APIService().MapEndpoints(app) },
|
||||||
|
new() { Name = "Auth", Port = 5002, ServiceType = typeof(AuthService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, jwt) => new AuthService().MapEndpoints(app) },
|
||||||
|
new() { Name = "Chat", Port = 5003, ServiceType = typeof(ChatService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, _) => new ChatService().MapEndpoints(app) },
|
||||||
|
new() { Name = "Match", Port = 5004, ServiceType = typeof(MatchmakingService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, _) => new MatchmakingService().MapEndpoints(app) },
|
||||||
|
new() { Name = "Accounts", Port = 5005, ServiceType = typeof(AccountsService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, jwt) => new AccountsService().MapEndpoints(app, jwt) },
|
||||||
|
new() { Name = "Notify", Port = 5006, ServiceType = typeof(NotifyService), ConfigureBuilder = b => b.ConfigureRecNetServices(), MapEndpoints = (app, _) => new NotifyService().MapEndpoints(app) }
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Host=localhost;Port=5432;Database=cannednet;Username=postgres;Password=postgres"
|
"DefaultConnection": "Host=localhost;Port=5432;Database=cannednet;Username=postgres;Password=postgres"
|
||||||
},
|
},
|
||||||
|
"Ports": {
|
||||||
|
"API": 5000,
|
||||||
|
"NS": 5001
|
||||||
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information"
|
"Default": "Information"
|
||||||
@@ -6,7 +6,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Data Source=game.db;Cache=Shared"
|
"DefaultConnection": "Host=localhost;Port=5432;Database=cannednet;Username=postgres;Password=postgres"
|
||||||
|
},
|
||||||
|
"Ports": {
|
||||||
|
"Primary": 5000,
|
||||||
|
"Secondary": 5001
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user