Remove old version
This commit is contained in:
parent
32a1886cf4
commit
0fd5fc7227
439
GC-local-server-rewrite/.gitignore
vendored
439
GC-local-server-rewrite/.gitignore
vendored
@ -1,439 +0,0 @@
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### VisualStudio template
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# Ignore card db since we should start from scratch
|
||||
/db/card.db3
|
@ -1,74 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>GCLocalServerRewrite</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CertificateManager" Version="1.0.8" />
|
||||
<PackageReference Include="ChoETL" Version="1.2.1.48" />
|
||||
<PackageReference Include="ConcurrentHashSet" Version="1.3.0" />
|
||||
<PackageReference Include="Config.Net" Version="5.1.3" />
|
||||
<PackageReference Include="Config.Net.Json" Version="4.19.0" />
|
||||
<PackageReference Include="EmbedIO" Version="3.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.5.22301.12" />
|
||||
<PackageReference Include="sqlite-net2" Version="2.1.0-preB" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.2" />
|
||||
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.2" />
|
||||
<PackageReference Include="Unosquare.Swan.Lite" Version="3.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="log" />
|
||||
<Folder Include="event\" />
|
||||
<None Remove="db\music.db3" />
|
||||
<None Remove="db\music4MAX465.db3" />
|
||||
<Content Include="db\music.db3">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<None Remove="static\favicon.ico" />
|
||||
<Content Include="db\music4MAX465.db3">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Include="static\favicon.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<None Remove="static\index.html" />
|
||||
<Content Include="static\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<None Remove="static\news.png" />
|
||||
<Content Include="static\news.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<None Remove="GC-local-server-rewrite.exe.config.xml" />
|
||||
<None Remove="db\music4MAX.db3" />
|
||||
<Content Include="db\music4MAX.db3">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<None Update="config.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</None>
|
||||
<None Update="db\music471.db3">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,107 +0,0 @@
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.server;
|
||||
using SQLitePCL;
|
||||
using Swan;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace GCLocalServerRewrite;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Batteries_V2.Init();
|
||||
|
||||
InitializeLogging();
|
||||
|
||||
LogConfigValues();
|
||||
|
||||
var urlPrefixes =
|
||||
args.Length > 0 ? new List<string>(args) : new List<string> { "http://+:80", "https://+:443" };
|
||||
|
||||
using (var cts = new CancellationTokenSource())
|
||||
{
|
||||
Task.WaitAll(
|
||||
RunWebServerAsync(urlPrefixes, cts.Token),
|
||||
Task.CompletedTask,
|
||||
WaitForUserBreakAsync(cts.Cancel));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
"Bye".Info(nameof(Program));
|
||||
Terminal.Flush();
|
||||
|
||||
Console.WriteLine("Press any key to exit.");
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
|
||||
private static void InitializeLogging()
|
||||
{
|
||||
if (!Directory.Exists(PathHelper.LogRootPath))
|
||||
{
|
||||
Directory.CreateDirectory(PathHelper.LogRootPath);
|
||||
}
|
||||
|
||||
Logger.RegisterLogger(new FileLogger(Path.Combine(PathHelper.LogRootPath, Configs.LOG_BASE_NAME), true));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create and run a web server.
|
||||
/// </summary>
|
||||
/// <param name="urlPrefixes"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
private static async Task RunWebServerAsync(IEnumerable<string> urlPrefixes, CancellationToken cancellationToken)
|
||||
{
|
||||
using var server = Server.CreateWebServer(urlPrefixes);
|
||||
await server.RunAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompt the user to press any key;
|
||||
/// when a key is next pressed, call the specified action to cancel operations.
|
||||
/// </summary>
|
||||
/// <param name="cancel"> Cancel Action to call </param>
|
||||
private static async Task WaitForUserBreakAsync(Action cancel)
|
||||
{
|
||||
// Be sure to run in parallel.
|
||||
await Task.Yield();
|
||||
|
||||
"Press x to stop the web server.".Info(nameof(Program));
|
||||
WaitForKeypress();
|
||||
"Stopping...".Info(nameof(Program));
|
||||
cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the console input buffer and wait for a keypress
|
||||
/// </summary>
|
||||
private static void WaitForKeypress()
|
||||
{
|
||||
ConsoleKeyInfo consoleKeyInfo;
|
||||
|
||||
do
|
||||
{
|
||||
while (Console.KeyAvailable == false)
|
||||
{
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
|
||||
consoleKeyInfo = Console.ReadKey(true);
|
||||
} while (consoleKeyInfo.Key != ConsoleKey.X);
|
||||
}
|
||||
|
||||
private static void LogConfigValues()
|
||||
{
|
||||
var paths = $"Paths: {nameof(PathHelper.HtmlRootPath)}: {PathHelper.HtmlRootPath}\n" +
|
||||
$"{nameof(PathHelper.LogRootPath)}: {PathHelper.LogRootPath}\n" +
|
||||
$"{nameof(PathHelper.DataBaseRootPath)}: {PathHelper.DataBaseRootPath}\n" +
|
||||
$"{nameof(PathHelper.ConfigFilePath)}: {PathHelper.ConfigFilePath}\n" +
|
||||
$"{nameof(PathHelper.CertRootPath)}: {PathHelper.CertRootPath}\n";
|
||||
paths.Info();
|
||||
|
||||
var configs = "Config values: \n" +
|
||||
$"{Configs.SETTINGS.Stringify()}";
|
||||
configs.Info();
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC 清单选项
|
||||
如果想要更改 Windows 用户帐户控制级别,请使用
|
||||
以下节点之一替换 requestedExecutionLevel 节点。
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
|
||||
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
|
||||
元素。
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
|
||||
Windows 版本的列表。取消评论适当的元素,
|
||||
Windows 将自动选择最兼容的环境。 -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
|
||||
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
|
||||
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
|
||||
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
|
||||
|
||||
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
|
||||
<!--
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
-->
|
||||
|
||||
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
@ -1,238 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using CertificateManager;
|
||||
using CertificateManager.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Swan;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public static class CertificateHelper
|
||||
{
|
||||
private const X509KeyUsageFlags ROOT_CA_X509_KEY_USAGE_FLAGS = X509KeyUsageFlags.KeyCertSign |
|
||||
X509KeyUsageFlags.DataEncipherment |
|
||||
X509KeyUsageFlags.KeyEncipherment |
|
||||
X509KeyUsageFlags.DigitalSignature;
|
||||
|
||||
private const X509KeyStorageFlags X509_KEY_STORAGE_FLAGS_MACHINE = X509KeyStorageFlags.PersistKeySet |
|
||||
X509KeyStorageFlags.MachineKeySet |
|
||||
X509KeyStorageFlags.Exportable;
|
||||
|
||||
private const X509KeyUsageFlags CERT_X509_KEY_USAGE_FLAGS = X509KeyUsageFlags.DataEncipherment |
|
||||
X509KeyUsageFlags.KeyEncipherment |
|
||||
X509KeyUsageFlags.DigitalSignature;
|
||||
|
||||
private static readonly DistinguishedName ROOT_CA_DISTINGUISHED_NAME = new()
|
||||
{
|
||||
CommonName = Configs.ROOT_CA_CN
|
||||
};
|
||||
|
||||
private static readonly DistinguishedName CERT_DISTINGUISHED_NAME = new()
|
||||
{
|
||||
CommonName = Configs.CERT_CN
|
||||
};
|
||||
|
||||
private static readonly BasicConstraints ROOT_CA_BASIC_CONSTRAINTS = new()
|
||||
{
|
||||
CertificateAuthority = true,
|
||||
HasPathLengthConstraint = true,
|
||||
PathLengthConstraint = 3,
|
||||
Critical = true
|
||||
};
|
||||
|
||||
public static readonly BasicConstraints CERT_BASIC_CONSTRAINTS = new()
|
||||
{
|
||||
CertificateAuthority = false,
|
||||
HasPathLengthConstraint = false,
|
||||
PathLengthConstraint = 0,
|
||||
Critical = true,
|
||||
};
|
||||
|
||||
private static readonly SubjectAlternativeName SUBJECT_ALTERNATIVE_NAME = new()
|
||||
{
|
||||
DnsName = Configs.DOMAINS,
|
||||
IpAddress = System.Net.IPAddress.Parse(Configs.SETTINGS.ServerIp)
|
||||
};
|
||||
|
||||
private static readonly ValidityPeriod VALIDITY_PERIOD = new()
|
||||
{
|
||||
ValidFrom = DateTime.UtcNow,
|
||||
ValidTo = DateTime.UtcNow.AddYears(3)
|
||||
};
|
||||
|
||||
private static readonly OidCollection OID_COLLECTION = new()
|
||||
{
|
||||
OidLookup.AnyPurpose
|
||||
};
|
||||
|
||||
public static X509Certificate2 InitializeCertificate()
|
||||
{
|
||||
if (CertificateExists())
|
||||
{
|
||||
var existingCert = GetCertificate(StoreName.My, StoreLocation.LocalMachine, Configs.CERT_CN);
|
||||
|
||||
if (existingCert != null)
|
||||
{
|
||||
return existingCert;
|
||||
}
|
||||
"Existing CN not found! Removing old certificates and genrate new ones...".Info();
|
||||
}
|
||||
|
||||
RemovePreviousCert(StoreName.My, StoreLocation.LocalMachine);
|
||||
RemovePreviousCert(StoreName.Root, StoreLocation.LocalMachine);
|
||||
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddCertificateManager().BuildServiceProvider();
|
||||
|
||||
var createCertificates = serviceProvider.GetService<CreateCertificates>();
|
||||
|
||||
if (createCertificates == null)
|
||||
{
|
||||
throw SelfCheck.Failure("Cannot initialize CreateCertificates service!");
|
||||
}
|
||||
|
||||
var rootCa = createCertificates.NewRsaSelfSignedCertificate(
|
||||
ROOT_CA_DISTINGUISHED_NAME,
|
||||
ROOT_CA_BASIC_CONSTRAINTS,
|
||||
VALIDITY_PERIOD,
|
||||
SUBJECT_ALTERNATIVE_NAME,
|
||||
OID_COLLECTION,
|
||||
ROOT_CA_X509_KEY_USAGE_FLAGS,
|
||||
new RsaConfiguration()
|
||||
);
|
||||
|
||||
var cert = createCertificates.NewRsaChainedCertificate(
|
||||
CERT_DISTINGUISHED_NAME,
|
||||
CERT_BASIC_CONSTRAINTS,
|
||||
VALIDITY_PERIOD,
|
||||
SUBJECT_ALTERNATIVE_NAME,
|
||||
rootCa,
|
||||
OID_COLLECTION,
|
||||
CERT_X509_KEY_USAGE_FLAGS,
|
||||
new RsaConfiguration()
|
||||
);
|
||||
|
||||
var exportService = serviceProvider.GetService<ImportExportCertificate>();
|
||||
|
||||
if (exportService == null)
|
||||
{
|
||||
throw SelfCheck.Failure("Cannot initialize ImportExportCertificate service!");
|
||||
}
|
||||
|
||||
var rootCaPfxBytes = exportService.ExportRootPfx(null, rootCa);
|
||||
var certPfxBytes = exportService.ExportChainedCertificatePfx(null, cert, rootCa);
|
||||
|
||||
var rootCaWithPrivateKey = new X509Certificate2(rootCaPfxBytes, (string)null!,
|
||||
X509_KEY_STORAGE_FLAGS_MACHINE);
|
||||
|
||||
var certWithPrivateKey = new X509Certificate2(certPfxBytes, (string)null!,
|
||||
X509_KEY_STORAGE_FLAGS_MACHINE);
|
||||
|
||||
|
||||
AddCertToStore(rootCaWithPrivateKey, StoreName.My, StoreLocation.LocalMachine);
|
||||
AddCertToStore(rootCaWithPrivateKey, StoreName.Root, StoreLocation.LocalMachine);
|
||||
AddCertToStore(certWithPrivateKey, StoreName.My, StoreLocation.LocalMachine);
|
||||
|
||||
Directory.CreateDirectory(PathHelper.CertRootPath);
|
||||
|
||||
File.WriteAllBytes(Path.Combine(PathHelper.CertRootPath, "root.pfx"), rootCaWithPrivateKey.Export(X509ContentType.Pfx));
|
||||
File.WriteAllBytes(Path.Combine(PathHelper.CertRootPath, "cert.pfx"), certWithPrivateKey.Export(X509ContentType.Pfx));
|
||||
|
||||
return certWithPrivateKey;
|
||||
}
|
||||
|
||||
private static void AddCertToStore(X509Certificate2 cert, StoreName storeName, StoreLocation storeLocation)
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
store.Add(cert);
|
||||
|
||||
store.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error(e.Source ?? "", e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemovePreviousCert(StoreName storeName, StoreLocation storeLocation)
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
var result = store.Certificates.Find(X509FindType.FindByIssuerName, Configs.ROOT_CA_CN, true);
|
||||
|
||||
if (result.Any())
|
||||
{
|
||||
store.RemoveRange(result);
|
||||
"Removed previous certs!".Info();
|
||||
}
|
||||
|
||||
store.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error(e.Source ?? "", e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CertificateExists()
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
|
||||
store.Open(OpenFlags.ReadOnly);
|
||||
var result = store.Certificates.Find(X509FindType.FindByIssuerName, Configs.ROOT_CA_CN, true);
|
||||
|
||||
if (result.Count == 2)
|
||||
{
|
||||
"Certificate exists!".Info();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
store.Close();
|
||||
"Certificate not found! Will generate new certs...".Info();
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error(e.Source ?? "", e.Message);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate2? GetCertificate(StoreName storeName, StoreLocation storeLocation, string commonName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
var result = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
|
||||
$"CN={commonName}", true);
|
||||
|
||||
if (result.Any())
|
||||
{
|
||||
$"Certificate CN={commonName} found!".Info();
|
||||
|
||||
return result.First();
|
||||
}
|
||||
|
||||
store.Close();
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error(e.Source ?? "", e.Message);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
using Config.Net;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public static class Configs
|
||||
{
|
||||
public const bool USE_FILE_CACHE = true;
|
||||
|
||||
public const string ROOT_CA_CN = "Taito Arcade Machine CA";
|
||||
|
||||
public const string CERT_CN = "GC local server";
|
||||
|
||||
public const string DB_FOLDER = "db";
|
||||
|
||||
public const string LOG_FOLDER = "log";
|
||||
|
||||
public const string CERT_FOLDER = "certs";
|
||||
|
||||
public const string LOG_BASE_NAME = "log";
|
||||
|
||||
public const string CONFIG_FILE_NAME = "config.json";
|
||||
|
||||
public const string STATIC_FOLDER = "static";
|
||||
|
||||
public const string WWWROOT = "wwwroot";
|
||||
|
||||
public const string API_BASE_ROUTE = "/api";
|
||||
|
||||
public const string OPTION_SERVICE_BASE_ROUTE = "/service/option";
|
||||
|
||||
public const string CARD_SERVICE_BASE_ROUTE = "/service/card";
|
||||
|
||||
public const string UPLOAD_SERVICE_BASE_ROUTE = "/service/upload";
|
||||
|
||||
public const string RESPONE_SERVICE_BASE_ROUTE = "/service/respone";
|
||||
|
||||
public const string INCOM_SERVICE_BASE_ROUTE = "/service/incom";
|
||||
|
||||
public const string UPDATE_SERVICE_BASE_ROUTE = "/update/cgi";
|
||||
|
||||
public const string RANK_BASE_ROUTE = "/ranking";
|
||||
|
||||
public const string ALIVE_BASE_ROUTE = "/alive";
|
||||
|
||||
public const string SERVER_BASE_ROUTE = "/server";
|
||||
|
||||
public const string STATIC_BASE_ROUTE = "/static";
|
||||
|
||||
public const string ROOT_XPATH = "/root";
|
||||
|
||||
public const string DATA_XPATH = $"{ROOT_XPATH}/data";
|
||||
|
||||
public const string CARD = "card";
|
||||
|
||||
public const string CARD_XPATH = $"{ROOT_XPATH}/{CARD}";
|
||||
|
||||
public const string CARD_DETAIL = "card_detail";
|
||||
|
||||
public const string CARD_DETAIL_SINGLE_XPATH = $"{ROOT_XPATH}/{CARD_DETAIL}";
|
||||
|
||||
public const string CARD_DETAIL_RECORD_XPATH = $"{CARD_DETAIL_SINGLE_XPATH}/record";
|
||||
|
||||
public const string CARD_BDATA = "card_bdata";
|
||||
|
||||
public const string CARD_BDATA_XPATH = $"{ROOT_XPATH}/{CARD_BDATA}";
|
||||
|
||||
public const string MUSIC = "music";
|
||||
|
||||
public const string MUSIC_XPATH = $"{ROOT_XPATH}/{MUSIC}/record";
|
||||
|
||||
public const string MUSIC_EXTRA = "music_extra";
|
||||
|
||||
public const string MUSIC_EXTRA_XPATH = $"{ROOT_XPATH}/{MUSIC_EXTRA}/record";
|
||||
|
||||
public const string MUSIC_AOU = "music_aou";
|
||||
|
||||
public const string MUSIC_AOU_XPATH = $"{ROOT_XPATH}/{MUSIC_AOU}/record";
|
||||
|
||||
public const string ITEM = "item";
|
||||
|
||||
public const string ITEM_XPATH = $"{ROOT_XPATH}/{ITEM}/record";
|
||||
|
||||
public const string AVATAR = "avatar";
|
||||
|
||||
public const string AVATAR_XPATH = $"{ROOT_XPATH}/{AVATAR}/record";
|
||||
|
||||
public const string SKIN = "skin";
|
||||
|
||||
public const string SKIN_XPATH = $"{ROOT_XPATH}/{SKIN}/record";
|
||||
|
||||
public const string TITLE = "title";
|
||||
|
||||
public const string TITLE_XPATH = $"{ROOT_XPATH}/{TITLE}/record";
|
||||
|
||||
public const string NAVIGATOR = "navigator";
|
||||
|
||||
public const string NAVIGATOR_XPATH = $"{ROOT_XPATH}/{NAVIGATOR}/record";
|
||||
|
||||
public const string COIN = "coin";
|
||||
|
||||
public const string COIN_XPATH = $"{ROOT_XPATH}/{COIN}";
|
||||
|
||||
public const string UNLOCK_REWARD = "unlock_reward";
|
||||
|
||||
public const string UNLOCK_REWARD_XPATH = $"{ROOT_XPATH}/{UNLOCK_REWARD}/record";
|
||||
|
||||
public const string UNLOCK_KEYNUM = "unlock_keynum";
|
||||
|
||||
public const string UNLOCK_KEYNUM_XPATH = $"{ROOT_XPATH}/{UNLOCK_KEYNUM}/record";
|
||||
|
||||
public const string SOUND_EFFECT = "sound_effect";
|
||||
|
||||
public const string SE_XPATH = $"{ROOT_XPATH}/{SOUND_EFFECT}/record";
|
||||
|
||||
public const string GET_MESSAGE = "get_message";
|
||||
|
||||
public const string TOTAL_TROPHY = "total_trophy";
|
||||
|
||||
public const string TOTAL_TROPHY_XPATH = $"{ROOT_XPATH}/{TOTAL_TROPHY}";
|
||||
|
||||
public const string EVENT_REWARD = "event_reward";
|
||||
|
||||
public const string COND = "cond";
|
||||
|
||||
public const string SESSION_XPATH = $"{ROOT_XPATH}/session";
|
||||
|
||||
public const string RANK_STATUS_XPATH = $"{ROOT_XPATH}/ranking_status";
|
||||
|
||||
public const string ONLINE_MATCHING_XPATH = $"{ROOT_XPATH}/online_matching/record";
|
||||
|
||||
public const string ONLINE_BATTLE_RESULT_XPATH = $"{ROOT_XPATH}/online_battle_result";
|
||||
|
||||
public const int FIRST_CONFIG_PCOL1 = 0;
|
||||
public const int SECOND_CONFIG_PCOL1 = 1;
|
||||
public const int CONFIG_PCOL2 = 0;
|
||||
public const int CONFIG_PCOL3 = 0;
|
||||
|
||||
public const int FAVORITE_PCOL1 = 10;
|
||||
|
||||
public const int COUNT_PCOL1 = 20;
|
||||
|
||||
public const int SCORE_PCOL1 = 21;
|
||||
|
||||
public const string MATCHING_URL_BASE = "Matching";
|
||||
|
||||
public const string START_MATCHING_URL = "Start";
|
||||
public const string UPDATE_MATCHING_URL = "Update";
|
||||
public const string FINISH_MATCHING_URL = "Finish";
|
||||
|
||||
|
||||
|
||||
public static readonly List<string> DOMAINS = new()
|
||||
{
|
||||
"localhost",
|
||||
"cert.nesys.jp",
|
||||
"nesys.taito.co.jp",
|
||||
"fjm170920zero.nesica.net"
|
||||
};
|
||||
|
||||
public static readonly IAppSettings SETTINGS =
|
||||
new ConfigurationBuilder<IAppSettings>().UseJsonConfig(PathHelper.ConfigFilePath).Build();
|
||||
|
||||
public const int DEFAULT_AVATAR_COUNT = 323;
|
||||
public const int DEFAULT_NAVIGATOR_COUNT = 94;
|
||||
public const int DEFAULT_ITEM_COUNT = 21;
|
||||
public const int DEFAULT_TITLE_COUNT = 5273;
|
||||
public const int DEFAULT_SKIN_COUNT = 21;
|
||||
public const int DEFAULT_SE_COUNT = 26;
|
||||
public const string DEFAULT_CARD_DB_NAME = "card.db3";
|
||||
public const string DEFAULT_MUSIC_DB_NAME = "music4MAX465.db3";
|
||||
public const string DEFAULT_SERVER_IP = "127.0.0.1";
|
||||
public const string DEFAULT_RELAY_SERVER = "127.0.0.1";
|
||||
public const int DEFAULT_RELAY_PORT = 54321;
|
||||
public const string DEFAULT_EVENT_FOLDER = "event";
|
||||
public const string DEFAULT_MATCHING_SERVER = "127.0.0.1:5000";
|
||||
|
||||
|
||||
public static readonly IReadOnlyList<int> DEFAULT_UNLOCKABLE_SONGS = new[]
|
||||
{
|
||||
11, 13, 149, 273, 291, 320, 321, 371, 378, 384, 464, 471, 474, 475, 492, 494, 498, 520,
|
||||
548, 551, 558, 561, 565, 570, 577, 583, 612, 615, 622, 632, 659, 666, 668, 670, 672, 676,
|
||||
680, 682, 685, 686, 697, 700, 701, 711, 720, 749, 875, 876, 877
|
||||
};
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
using GCLocalServerRewrite.models;
|
||||
using SharedProject.models;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public static class Converters
|
||||
{
|
||||
public static OnlineMatchingData ConvertFromEntry(OnlineMatchingEntry entry)
|
||||
{
|
||||
return new OnlineMatchingData
|
||||
{
|
||||
AvatarId = entry.AvatarId,
|
||||
CardId = entry.CardId,
|
||||
ClassId = entry.ClassId,
|
||||
EntryNo = entry.EntryNo,
|
||||
EntryStart = entry.EntryStart,
|
||||
EventId = entry.EventId,
|
||||
GroupId = entry.GroupId,
|
||||
MachineId = entry.MachineId,
|
||||
MatchingId = entry.MatchingId,
|
||||
MatchingRemainingTime = entry.MatchingRemainingTime,
|
||||
Pref = entry.Pref,
|
||||
Status = entry.Status,
|
||||
MatchingTimeout = entry.MatchingTimeout,
|
||||
MessageId = entry.MessageId,
|
||||
PlayerName = entry.PlayerName,
|
||||
PrefId = entry.PrefId,
|
||||
TenpoId = entry.TenpoId,
|
||||
TenpoName = entry.TenpoName,
|
||||
TitleId = entry.TitleId,
|
||||
MatchingWaitTime = entry.MatchingWaitTime
|
||||
};
|
||||
}
|
||||
|
||||
public static OnlineMatchingEntry ConvertFromData(OnlineMatchingData entry)
|
||||
{
|
||||
return new OnlineMatchingEntry
|
||||
{
|
||||
AvatarId = entry.AvatarId,
|
||||
CardId = entry.CardId,
|
||||
ClassId = entry.ClassId,
|
||||
EntryNo = entry.EntryNo,
|
||||
EntryStart = entry.EntryStart,
|
||||
EventId = entry.EventId,
|
||||
GroupId = entry.GroupId,
|
||||
MachineId = entry.MachineId,
|
||||
MatchingId = entry.MatchingId,
|
||||
MatchingRemainingTime = entry.MatchingRemainingTime,
|
||||
Pref = entry.Pref,
|
||||
Status = entry.Status,
|
||||
MatchingTimeout = entry.MatchingTimeout,
|
||||
MessageId = entry.MessageId,
|
||||
PlayerName = entry.PlayerName,
|
||||
PrefId = entry.PrefId,
|
||||
TenpoId = entry.TenpoId,
|
||||
TenpoName = entry.TenpoName,
|
||||
TitleId = entry.TitleId,
|
||||
MatchingWaitTime = entry.MatchingWaitTime
|
||||
};
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public static class DatabaseHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Static method to allow local data services to initialise their associated database conveniently.
|
||||
/// </summary>
|
||||
/// <param name="databaseName">The SQLite database name</param>
|
||||
/// <param name="tables">The SQLite database tables to create (if required)</param>
|
||||
/// <returns>An initialised SQLite database connection</returns>
|
||||
public static SQLiteConnection InitializeLocalDatabase(string databaseName, params Type[] tables)
|
||||
{
|
||||
if (!Directory.Exists(PathHelper.DataBaseRootPath))
|
||||
{
|
||||
Directory.CreateDirectory(PathHelper.DataBaseRootPath);
|
||||
}
|
||||
|
||||
var databasePath = Path.Combine(PathHelper.DataBaseRootPath, databaseName);
|
||||
|
||||
var database = new SQLiteConnection(databasePath);
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
database.CreateTable(table);
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
public static SQLiteConnection ConnectDatabase(string databaseName)
|
||||
{
|
||||
var databasePath = Path.Combine(PathHelper.DataBaseRootPath, databaseName);
|
||||
|
||||
var database = new SQLiteConnection(databasePath);
|
||||
|
||||
return database;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using Config.Net;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public interface IAppSettings
|
||||
{
|
||||
[Option(DefaultValue = Configs.DEFAULT_AVATAR_COUNT)]
|
||||
int AvatarCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_NAVIGATOR_COUNT)]
|
||||
int NavigatorCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_ITEM_COUNT)]
|
||||
int ItemCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_TITLE_COUNT)]
|
||||
int TitleCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_SKIN_COUNT)]
|
||||
int SkinCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_SE_COUNT)]
|
||||
int SeCount { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_MUSIC_DB_NAME)]
|
||||
string MusicDbName { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_CARD_DB_NAME)]
|
||||
string CardDbName { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_SERVER_IP)]
|
||||
string ServerIp { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_EVENT_FOLDER)]
|
||||
string EventFolder { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_RELAY_SERVER)]
|
||||
string RelayServer { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_RELAY_PORT)]
|
||||
int RelayPort { get; }
|
||||
|
||||
[Option(DefaultValue = false)]
|
||||
bool DownloadEvents { get; }
|
||||
|
||||
[Option(DefaultValue = Configs.DEFAULT_MATCHING_SERVER)]
|
||||
string MatchingServer { get; }
|
||||
|
||||
[Option(DefaultValue = null)]
|
||||
IEnumerable<int>? UnlockableSongIds { get; }
|
||||
|
||||
IEnumerable<IOptionServiceResponse> ResponseData { get; }
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public interface IOptionServiceResponse
|
||||
{
|
||||
string FileName { get; }
|
||||
|
||||
long NotBeforeUnixTime { get; }
|
||||
|
||||
long NotAfterUnixTime { get; }
|
||||
|
||||
string Md5 { get; }
|
||||
|
||||
int Index { get; }
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
using Swan;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace GCLocalServerRewrite.common;
|
||||
|
||||
public static class PathHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the local path of html/static files.
|
||||
/// </summary>
|
||||
public static string HtmlRootPath => Path.Combine(BasePath, Configs.STATIC_FOLDER, Configs.WWWROOT);
|
||||
|
||||
/// <summary>
|
||||
/// Root path for database, when debug, it's under source root, when release, it's the exe dir
|
||||
/// </summary>
|
||||
public static string DataBaseRootPath => Path.Combine(BasePath, Configs.DB_FOLDER);
|
||||
|
||||
public static string LogRootPath => Path.Combine(BasePath, Configs.LOG_FOLDER);
|
||||
|
||||
public static string CertRootPath => Path.Combine(BasePath, Configs.CERT_FOLDER);
|
||||
|
||||
public static string ConfigFilePath => Path.Combine(BasePath, Configs.CONFIG_FILE_NAME);
|
||||
|
||||
private static string BasePath
|
||||
{
|
||||
get
|
||||
{
|
||||
var assemblyPath = Environment.ProcessPath;
|
||||
if (assemblyPath == null)
|
||||
{
|
||||
throw SelfCheck.Failure("Cannot get assembly path!!!");
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
|
||||
var parentFullName = Directory.GetParent(assemblyPath)?.Parent?.Parent?.Parent?.FullName;
|
||||
|
||||
Debug.Assert(parentFullName != null, $"{nameof(parentFullName)} != null");
|
||||
|
||||
return parentFullName;
|
||||
#else
|
||||
var parent = Directory.GetParent(assemblyPath);
|
||||
if (parent == null)
|
||||
{
|
||||
throw SelfCheck.Failure("Cannot get assembly parent path!!!");
|
||||
}
|
||||
return parent.ToString();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
{
|
||||
"AvatarCount": 356,
|
||||
"NavigatorCount": 118,
|
||||
"ItemCount": 21,
|
||||
"SkinCount": 21,
|
||||
"SeCount": 26,
|
||||
"TitleCount": 5530,
|
||||
"CardDbName": "card.db3",
|
||||
"MusicDbName": "music471omni.db3",
|
||||
"ServerIp": "127.0.0.1",
|
||||
"EventFolder": "event",
|
||||
"DownloadEvents": false,
|
||||
"RelayServer": "127.0.0.1",
|
||||
"RelayPort": 3333,
|
||||
"MatchingServer": "127.0.0.1:5038",
|
||||
"UnlockableSongIds": [
|
||||
11,
|
||||
13,
|
||||
149,
|
||||
273,
|
||||
291,
|
||||
320,
|
||||
321,
|
||||
371,
|
||||
378,
|
||||
384,
|
||||
464,
|
||||
471,
|
||||
474,
|
||||
475,
|
||||
492,
|
||||
494,
|
||||
498,
|
||||
520,
|
||||
548,
|
||||
551,
|
||||
558,
|
||||
561,
|
||||
565,
|
||||
570,
|
||||
577,
|
||||
583,
|
||||
612,
|
||||
615,
|
||||
622,
|
||||
632,
|
||||
659,
|
||||
666,
|
||||
668,
|
||||
670,
|
||||
672,
|
||||
676,
|
||||
680,
|
||||
682,
|
||||
685,
|
||||
686,
|
||||
697,
|
||||
700,
|
||||
701,
|
||||
711,
|
||||
720,
|
||||
749,
|
||||
875,
|
||||
876,
|
||||
877
|
||||
],
|
||||
"ResponseData": [
|
||||
{
|
||||
"FileName": "/event_103_20201125.evt",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "27b503145a62e46f5f611b6f8a91e4f3",
|
||||
"Index": 0
|
||||
},
|
||||
{
|
||||
"FileName": "/event_20201125_reg.jpg",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "8e3fe25bf50dcbed13dbb54cc18b1efa",
|
||||
"Index": 1
|
||||
},
|
||||
{
|
||||
"FileName": "/event_20201125_sgreg.png",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "e0abb0503fe0c530d8a68e36994264c6",
|
||||
"Index": 2
|
||||
},
|
||||
{
|
||||
"FileName": "/news_big_20201125_0.jpg",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "4a0f66431f6449279dc046149d1dd882",
|
||||
"Index": 0
|
||||
},
|
||||
{
|
||||
"FileName": "/news_big_20201125_2.jpg",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "8e3fe25bf50dcbed13dbb54cc18b1efa",
|
||||
"Index": 2
|
||||
},
|
||||
{
|
||||
"FileName": "/news_small_20201125_1.jpg",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "e20135bcd41c98875aec2b52eb9fcd06",
|
||||
"Index": 1
|
||||
},
|
||||
{
|
||||
"FileName": "/telop_20201125.txt",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "ee228de44d6656a9ec0bb7f1a0ca64e1",
|
||||
"Index": 0
|
||||
},
|
||||
{
|
||||
"FileName": "/event_unlock_20201125.cmp",
|
||||
"NotBeforeUnixTime": 1335677127,
|
||||
"NotAfterUnixTime": 1966397127,
|
||||
"Md5": "534a253e3de8360c2beff49a5f120105",
|
||||
"Index": 8
|
||||
}
|
||||
]
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class AliveController : WebApiController
|
||||
{
|
||||
[Route(HttpVerbs.Get, "/i.php")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public string Check()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Html;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "REMOTE ADDRESS: 127.0.0.1\n" +
|
||||
"SERVER NAME:nesys.home\n" +
|
||||
"SERVER ADDR:239.1.1.1";
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/{id}/Alive.txt")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public void AliveFile()
|
||||
{
|
||||
HttpContext.Response.SetEmptyResponse((int)HttpStatusCode.OK);
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
}
|
||||
}
|
@ -1,340 +0,0 @@
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.models;
|
||||
using SharedProject.common;
|
||||
using SharedProject.enums;
|
||||
using SharedProject.models;
|
||||
using SQLite.Net2;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class ApiController : WebApiController
|
||||
{
|
||||
private readonly SQLiteConnection cardSqLiteConnection;
|
||||
|
||||
private readonly Dictionary<int, Music> musics;
|
||||
private readonly Dictionary<int, MusicExtra> musicExtras;
|
||||
|
||||
public ApiController()
|
||||
{
|
||||
cardSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.CardDbName);
|
||||
var musicSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.MusicDbName);
|
||||
musics = musicSqLiteConnection.Table<Music>().ToDictionary(music => music.MusicId);
|
||||
musicExtras = musicSqLiteConnection.Table<MusicExtra>().ToDictionary(music => music.MusicId);
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/Users")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public List<User> GetUsers()
|
||||
{
|
||||
var result = cardSqLiteConnection.Table<Card>().ToList().ConvertAll(card => new User
|
||||
{
|
||||
CardId = card.CardId,
|
||||
PlayerName = card.PlayerName
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Post, "/Users/SetPlayerName")]
|
||||
public bool SetPlayerName([JsonData] User data)
|
||||
{
|
||||
var existing = cardSqLiteConnection.Table<Card>().Where(card => card.CardId == data.CardId);
|
||||
if (!existing.Any())
|
||||
{
|
||||
$"Trying to update non existing user's name! Card id {data.CardId}".Warn();
|
||||
return false;
|
||||
}
|
||||
var user = existing.First();
|
||||
user.PlayerName = data.PlayerName;
|
||||
return cardSqLiteConnection.Update(user) == 1;
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Post, "/UserDetail/SetMusicFavorite")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public bool SetFavorite([JsonData] MusicFavoriteData data)
|
||||
{
|
||||
var existing = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == data.CardId
|
||||
&& detail.Pcol1 == Configs.FAVORITE_PCOL1
|
||||
&& detail.Pcol2 == data.MusicId);
|
||||
|
||||
if (!existing.Any())
|
||||
{
|
||||
$"Trying to update non existing song's favorite! Card id {data.CardId}, music id {data.MusicId}".Warn();
|
||||
return false;
|
||||
}
|
||||
|
||||
var cardDetail = existing.First();
|
||||
cardDetail.Fcol1 = data.IsFavorite ? 1 : 0;
|
||||
var result = cardSqLiteConnection.Update(cardDetail);
|
||||
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Post, "/UserDetail/SetPlayOption")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public bool SetPlayOption([JsonData] PlayOption data)
|
||||
{
|
||||
var firstConfig = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == data.CardId
|
||||
&& detail.Pcol1 == Configs.FIRST_CONFIG_PCOL1
|
||||
&& detail.Pcol2 == Configs.CONFIG_PCOL2
|
||||
&& detail.Pcol3 == Configs.CONFIG_PCOL3);
|
||||
|
||||
var secondConfig = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == data.CardId
|
||||
&& detail.Pcol1 == Configs.SECOND_CONFIG_PCOL1
|
||||
&& detail.Pcol2 == Configs.CONFIG_PCOL2
|
||||
&& detail.Pcol3 == Configs.CONFIG_PCOL3);
|
||||
|
||||
if (!firstConfig.Any() || !secondConfig.Any())
|
||||
{
|
||||
$"Trying to update non existing card's config! Card id {data.CardId}".Warn();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstDetail = firstConfig.First();
|
||||
firstDetail.ScoreUi1 = (long)data.FastSlowIndicator;
|
||||
firstDetail.ScoreUi2 = (long)data.FeverTrance;
|
||||
firstDetail.ScoreI1 = data.AvatarId;
|
||||
firstDetail.Fcol2 = (int)data.TitleId;
|
||||
|
||||
var secondDetail = secondConfig.First();
|
||||
secondDetail.ScoreI1 = data.NavigatorId;
|
||||
|
||||
var firstResult = cardSqLiteConnection.Update(firstDetail);
|
||||
var secondResult = cardSqLiteConnection.Update(secondDetail);
|
||||
|
||||
return firstResult == 1 && secondResult == 1;
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/UserDetail/{cardId}")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public UserDetail? GetUserDetail(long cardId)
|
||||
{
|
||||
var cardResult = cardSqLiteConnection.Table<Card>().Where(card => card.CardId == cardId);
|
||||
|
||||
if (!cardResult.Any())
|
||||
{
|
||||
$"Getting detail for non exisisting card! Card id is {cardId}".Warn();
|
||||
return null;
|
||||
}
|
||||
|
||||
var card = cardResult.First();
|
||||
|
||||
return ToUserDetail(card);
|
||||
}
|
||||
|
||||
private UserDetail? ToUserDetail(Card card)
|
||||
{
|
||||
if (!cardSqLiteConnection.Table<CardDetail>().Select(detail => detail.CardId == card.CardId).Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var userDetail = new UserDetail
|
||||
{
|
||||
CardId = card.CardId,
|
||||
PlayerName = card.PlayerName
|
||||
};
|
||||
var songPlayDataDict = new Dictionary<int, SongPlayData>();
|
||||
|
||||
ProcessCardDetail(userDetail, songPlayDataDict);
|
||||
|
||||
userDetail.SongPlayDataList = songPlayDataDict.Values.ToList();
|
||||
userDetail.TotalSongCount = musics.Count;
|
||||
userDetail.TotalStageCount = userDetail.TotalSongCount * 3 + musicExtras.Count;
|
||||
userDetail.AverageScore = (int)(userDetail.TotalScore / userDetail.PlayedStageCount);
|
||||
userDetail.PlayedSongCount = songPlayDataDict.Count;
|
||||
return userDetail;
|
||||
}
|
||||
|
||||
private void ProcessCardDetail(UserDetail userDetail, IDictionary<int, SongPlayData> songPlayDataDict)
|
||||
{
|
||||
var firstOption = cardSqLiteConnection.Table<CardDetail>()
|
||||
.FirstOrDefault(detail => detail.CardId == userDetail.CardId
|
||||
&& detail.Pcol1 == Configs.FIRST_CONFIG_PCOL1
|
||||
&& detail.Pcol2 == Configs.CONFIG_PCOL2
|
||||
&& detail.Pcol3 == Configs.CONFIG_PCOL3
|
||||
, new CardDetail
|
||||
{
|
||||
CardId = userDetail.CardId
|
||||
});
|
||||
var secondOption = cardSqLiteConnection.Table<CardDetail>()
|
||||
.FirstOrDefault(detail => detail.CardId == userDetail.CardId
|
||||
&& detail.Pcol1 == Configs.SECOND_CONFIG_PCOL1
|
||||
&& detail.Pcol2 == Configs.CONFIG_PCOL2
|
||||
&& detail.Pcol3 == Configs.CONFIG_PCOL3
|
||||
, new CardDetail
|
||||
{
|
||||
CardId = userDetail.CardId
|
||||
});
|
||||
|
||||
SetOptions(firstOption, secondOption, userDetail);
|
||||
|
||||
var songCounts = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == userDetail.CardId && detail.Pcol1 == Configs.COUNT_PCOL1);
|
||||
|
||||
foreach (var detail in songCounts)
|
||||
{
|
||||
SetCounts(detail, songPlayDataDict, userDetail);
|
||||
}
|
||||
|
||||
var songScores = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == userDetail.CardId && detail.Pcol1 == Configs.SCORE_PCOL1);
|
||||
|
||||
foreach (var detail in songScores)
|
||||
{
|
||||
SetDetails(detail, songPlayDataDict, userDetail);
|
||||
}
|
||||
|
||||
var favorites = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == userDetail.CardId && detail.Pcol1 == Configs.FAVORITE_PCOL1)
|
||||
.ToDictionary(detail => detail.Pcol2);
|
||||
|
||||
foreach (var (musicId, songPlayData) in songPlayDataDict)
|
||||
{
|
||||
songPlayData.IsFavorite = favorites[musicId].Fcol1 != 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetOptions(CardDetail firstOptionCardDetail, CardDetail secondOptionCardDetail, UserDetail userDetail)
|
||||
{
|
||||
var fastSlow = (int)firstOptionCardDetail.ScoreUi1;
|
||||
var feverTrance = (int)firstOptionCardDetail.ScoreUi2;
|
||||
|
||||
if (!Enum.IsDefined(typeof(PlayOptions.FastSlowIndicator), fastSlow))
|
||||
{
|
||||
fastSlow = (int)PlayOptions.FastSlowIndicator.NotUsed;
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(typeof(PlayOptions.FeverTranceShow), feverTrance))
|
||||
{
|
||||
feverTrance = (int)PlayOptions.FeverTranceShow.Show;
|
||||
}
|
||||
|
||||
userDetail.PlayOption = new PlayOption
|
||||
{
|
||||
CardId = firstOptionCardDetail.CardId,
|
||||
FastSlowIndicator = (PlayOptions.FastSlowIndicator)fastSlow,
|
||||
FeverTrance = (PlayOptions.FeverTranceShow)feverTrance,
|
||||
AvatarId = firstOptionCardDetail.ScoreI1,
|
||||
TitleId = firstOptionCardDetail.Fcol2,
|
||||
NavigatorId = secondOptionCardDetail.ScoreI1
|
||||
};
|
||||
}
|
||||
private void SetDetails(CardDetail cardDetail, IDictionary<int, SongPlayData> songPlayDataDict,
|
||||
UserDetail userDetail)
|
||||
{
|
||||
var musicId = cardDetail.Pcol2;
|
||||
|
||||
AddSongPlayDataIfNotExist(songPlayDataDict, musicId);
|
||||
|
||||
for (var i = 0; i < SharedConstants.DIFFICULTY_COUNT; i++)
|
||||
{
|
||||
var songPlayDetailData = songPlayDataDict[musicId].SongPlaySubDataList[i];
|
||||
songPlayDetailData.Difficulty = (Difficulty)i;
|
||||
|
||||
if (i != cardDetail.Pcol3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
songPlayDetailData.Score = (int)cardDetail.ScoreUi1;
|
||||
songPlayDetailData.MaxChain = (int)cardDetail.ScoreUi3;
|
||||
|
||||
userDetail.TotalScore += cardDetail.ScoreUi1;
|
||||
|
||||
if (cardDetail.ScoreUi1 >= SharedConstants.S_SCORE_THRESHOLD)
|
||||
{
|
||||
userDetail.SAboveStageCount++;
|
||||
}
|
||||
|
||||
if (cardDetail.ScoreUi1 >= SharedConstants.S_PLUS_SCORE_THRESHOLD)
|
||||
{
|
||||
userDetail.SPlusAboveStageCount++;
|
||||
}
|
||||
|
||||
if (cardDetail.ScoreUi1 >= SharedConstants.S_PLUS_PLUS_SCORE_THRESHOLD)
|
||||
{
|
||||
userDetail.SPlusPlusAboveStageCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCounts(CardDetail cardDetail, IDictionary<int, SongPlayData> songPlayDataDict, UserDetail userDetail)
|
||||
{
|
||||
var musicId = cardDetail.Pcol2;
|
||||
|
||||
AddSongPlayDataIfNotExist(songPlayDataDict, musicId);
|
||||
|
||||
for (var i = 0; i < SharedConstants.DIFFICULTY_COUNT; i++)
|
||||
{
|
||||
var songPlayDetailData = songPlayDataDict[musicId].SongPlaySubDataList[i];
|
||||
|
||||
songPlayDetailData.Difficulty = (Difficulty)i;
|
||||
|
||||
if (i != cardDetail.Pcol3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
songPlayDetailData.PlayCount = (int)cardDetail.ScoreUi1;
|
||||
songPlayDetailData.LastPlayTime = cardDetail.LastPlayTime;
|
||||
songPlayDetailData.ClearState = ClearState.Failed;
|
||||
userDetail.PlayedStageCount++;
|
||||
|
||||
if (cardDetail.ScoreUi2 > 0)
|
||||
{
|
||||
userDetail.ClearedStageCount++;
|
||||
songPlayDetailData.ClearState = ClearState.Clear;
|
||||
}
|
||||
|
||||
if (cardDetail.ScoreUi3 > 0)
|
||||
{
|
||||
userDetail.NoMissStageCount++;
|
||||
songPlayDetailData.ClearState = ClearState.NoMiss;
|
||||
}
|
||||
|
||||
if (cardDetail.ScoreUi4 > 0)
|
||||
{
|
||||
userDetail.FullChainStageCount++;
|
||||
songPlayDetailData.ClearState = ClearState.FullChain;
|
||||
}
|
||||
|
||||
if (cardDetail.ScoreUi6 > 0)
|
||||
{
|
||||
userDetail.PerfectStageCount++;
|
||||
songPlayDetailData.ClearState = ClearState.Perfect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSongPlayDataIfNotExist(IDictionary<int, SongPlayData> songPlayDataDict, int musicId)
|
||||
{
|
||||
if (songPlayDataDict.ContainsKey(musicId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var musicData = musics[musicId];
|
||||
var songPlayData = new SongPlayData
|
||||
{
|
||||
Artist = musicData.Artist ?? string.Empty,
|
||||
Title = musicData.Title ?? string.Empty,
|
||||
MusicId = musicId,
|
||||
SongPlaySubDataList = new SongPlayDetailData[SharedConstants.DIFFICULTY_COUNT]
|
||||
};
|
||||
|
||||
for (var i = 0; i < SharedConstants.DIFFICULTY_COUNT; i++)
|
||||
{
|
||||
songPlayData.SongPlaySubDataList[i] = new SongPlayDetailData();
|
||||
}
|
||||
songPlayDataDict[musicId] = songPlayData;
|
||||
}
|
||||
}
|
@ -1,806 +0,0 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using ChoETL;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.models;
|
||||
using SharedProject.models;
|
||||
using SQLite.Net2;
|
||||
using Swan;
|
||||
using Swan.Logging;
|
||||
using Avatar=GCLocalServerRewrite.models.Avatar;
|
||||
using Navigator=GCLocalServerRewrite.models.Navigator;
|
||||
using Title=GCLocalServerRewrite.models.Title;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class CardServiceController : WebApiController
|
||||
{
|
||||
private readonly SQLiteConnection cardSqLiteConnection;
|
||||
private readonly SQLiteConnection musicSqLiteConnection;
|
||||
|
||||
public CardServiceController()
|
||||
{
|
||||
cardSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.CardDbName);
|
||||
musicSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.MusicDbName);
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Post, "/cardn.cgi")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public async Task<string> CardService([FormField] int gid, [FormField("mac_addr")] string mac, [FormField] int type,
|
||||
[FormField("card_no")] long cardId, [FormField("data")] string xmlData, [FormField("cmd_str")] int cmdType)
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Application.Octet;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return await ProcessCommand(cmdType, mac, cardId, xmlData, type);
|
||||
}
|
||||
|
||||
private async Task<string> ProcessCommand(int cmdType, string mac, long cardId, string xmlData, int type)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(Command), cmdType))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(cmdType), cmdType, $"Cmd type is unknown!\n Data is {xmlData}");
|
||||
}
|
||||
|
||||
var command = (Command)cmdType;
|
||||
|
||||
return command switch
|
||||
{
|
||||
Command.CardReadRequest or Command.CardWriteRequest => await ProcessCardRequest(mac, cardId, xmlData, type),
|
||||
Command.ReissueRequest => ProcessReissueRequest(),
|
||||
Command.RegisterRequest => ProcessRegisterRequest(cardId, xmlData),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(command), command, "Command unknown, should never happen!")
|
||||
};
|
||||
}
|
||||
|
||||
private string ProcessRegisterRequest(long cardId, string xmlData)
|
||||
{
|
||||
$"Get card register request, data is \n{xmlData}".Info();
|
||||
Write<Card>(cardId, xmlData);
|
||||
return ConstructResponse(xmlData);
|
||||
}
|
||||
|
||||
private static string ProcessReissueRequest()
|
||||
{
|
||||
"Get reissue request, returning not reissue".Info();
|
||||
return ConstructResponse("", ReturnCode.NotReissue);
|
||||
}
|
||||
|
||||
private async Task<string> ProcessCardRequest(string mac, long cardId, string xmlData, int type)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(CardRequestType), type))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, "Card request type is unknown!");
|
||||
}
|
||||
|
||||
var requestType = (CardRequestType)type;
|
||||
|
||||
$"Getting card request, type is {requestType}".Info();
|
||||
|
||||
switch (requestType)
|
||||
{
|
||||
#region ReadRequests
|
||||
|
||||
case CardRequestType.ReadCard:
|
||||
{
|
||||
var response = Card(cardId, out var returnCode);
|
||||
|
||||
return ConstructResponse(response, returnCode);
|
||||
}
|
||||
case CardRequestType.ReadCardDetail:
|
||||
{
|
||||
var cardDetail = CardDetail(cardId, xmlData);
|
||||
return ConstructResponse(cardDetail);
|
||||
}
|
||||
case CardRequestType.ReadCardDetails:
|
||||
{
|
||||
return ConstructResponse(CardDetails(cardId));
|
||||
}
|
||||
case CardRequestType.ReadCardBData:
|
||||
{
|
||||
return ConstructResponse(CardBData(cardId));
|
||||
}
|
||||
case CardRequestType.ReadAvatar:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<Avatar>(cardId, Configs.SETTINGS.AvatarCount, Configs.AVATAR_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadItem:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<Item>(cardId, Configs.SETTINGS.ItemCount, Configs.ITEM_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadSkin:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<Skin>(cardId, Configs.SETTINGS.SkinCount, Configs.SKIN_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadTitle:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<Title>(cardId, Configs.SETTINGS.TitleCount, Configs.TITLE_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadMusic:
|
||||
{
|
||||
return ConstructResponse(MusicUnlock());
|
||||
}
|
||||
case CardRequestType.ReadEventReward:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GenerateEmptyXml(Configs.EVENT_REWARD));
|
||||
}
|
||||
case CardRequestType.ReadNavigator:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<Navigator>(cardId, Configs.SETTINGS.NavigatorCount, Configs.NAVIGATOR_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadMusicExtra:
|
||||
{
|
||||
return ConstructResponse(MusicExtra());
|
||||
}
|
||||
case CardRequestType.ReadMusicAou:
|
||||
{
|
||||
return ConstructResponse(MusicAouUnlock());
|
||||
}
|
||||
case CardRequestType.ReadCoin:
|
||||
{
|
||||
return ConstructResponse(Coin(cardId));
|
||||
}
|
||||
case CardRequestType.ReadUnlockReward:
|
||||
{
|
||||
return ConstructResponse(UnlockReward(cardId));
|
||||
}
|
||||
case CardRequestType.ReadUnlockKeynum:
|
||||
{
|
||||
return ConstructResponse(UnlockKeynum(cardId));
|
||||
}
|
||||
case CardRequestType.ReadSoundEffect:
|
||||
{
|
||||
return ConstructResponse(
|
||||
GetStaticCount<SoundEffect>(cardId, Configs.SETTINGS.SeCount, Configs.SE_XPATH));
|
||||
}
|
||||
case CardRequestType.ReadGetMessage:
|
||||
{
|
||||
return ConstructResponse(GenerateEmptyXml(Configs.GET_MESSAGE));
|
||||
}
|
||||
case CardRequestType.ReadCond:
|
||||
{
|
||||
return ConstructResponse(GenerateEmptyXml(Configs.COND));
|
||||
}
|
||||
case CardRequestType.ReadTotalTrophy:
|
||||
{
|
||||
return ConstructResponse(TotalTrophy(cardId));
|
||||
}
|
||||
case CardRequestType.StartSession:
|
||||
case CardRequestType.GetSession:
|
||||
{
|
||||
return ConstructResponse(GetSession(cardId, mac));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WriteRequests
|
||||
|
||||
case CardRequestType.WriteCard:
|
||||
{
|
||||
$"Card Write data is {xmlData}".Info();
|
||||
Write<Card>(cardId, xmlData);
|
||||
return ConstructResponse(xmlData);
|
||||
}
|
||||
case CardRequestType.WriteCardDetail:
|
||||
{
|
||||
$"Card Detail Write data is {xmlData}".Info();
|
||||
WriteCardDetail(cardId, xmlData);
|
||||
return ConstructResponse(xmlData);
|
||||
}
|
||||
case CardRequestType.WriteCardBData:
|
||||
{
|
||||
$"Card BData Write data is {xmlData}".Info();
|
||||
Write<CardBData>(cardId, xmlData);
|
||||
WriteCardPlayCount(cardId);
|
||||
return ConstructResponse(xmlData);
|
||||
}
|
||||
// TODO: Maybe one day implement these
|
||||
case CardRequestType.WriteAvatar:
|
||||
case CardRequestType.WriteItem:
|
||||
case CardRequestType.WriteTitle:
|
||||
case CardRequestType.WriteMusicDetail:
|
||||
case CardRequestType.WriteNavigator:
|
||||
case CardRequestType.WriteCoin:
|
||||
case CardRequestType.WriteSkin:
|
||||
case CardRequestType.WriteUnlockKeynum:
|
||||
case CardRequestType.WriteSoundEffect:
|
||||
{
|
||||
$"Card Write data is {xmlData}".Info();
|
||||
return ConstructResponse(xmlData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region OnlineMatching
|
||||
|
||||
case CardRequestType.StartOnlineMatching:
|
||||
{
|
||||
$"Start Online Matching, data is {xmlData}".Info();
|
||||
var resultString = await StartOnlineMatching(cardId, xmlData);
|
||||
return ConstructResponse(resultString);
|
||||
}
|
||||
|
||||
case CardRequestType.UpdateOnlineMatching:
|
||||
{
|
||||
$"Update Online Matching, data is {xmlData}".Info();
|
||||
var resultString = await UpdateOnlineMatching(cardId, xmlData);
|
||||
return ConstructResponse(resultString);
|
||||
}
|
||||
|
||||
case CardRequestType.UploadOnlineMatchingResult:
|
||||
{
|
||||
$"Get Online Matching result, data is {xmlData}".Info();
|
||||
var resultString = await UploadOnlineMatchingResult(cardId, xmlData);
|
||||
return ConstructResponse(resultString);
|
||||
}
|
||||
#endregion
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(requestType), requestType, "Request type not captured, should never happen!");
|
||||
}
|
||||
}
|
||||
|
||||
#region ReadImplementation
|
||||
|
||||
private string Card(long cardId, out ReturnCode returnCode)
|
||||
{
|
||||
var result = cardSqLiteConnection.Table<Card>().Where(card => card.CardId == cardId);
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
returnCode = ReturnCode.CardNotRegistered;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var card = result.First();
|
||||
|
||||
returnCode = ReturnCode.Ok;
|
||||
return GenerateSingleXml(card, Configs.CARD_XPATH);
|
||||
}
|
||||
|
||||
private string CardDetail(long cardId, string xmlData)
|
||||
{
|
||||
var reader = new ChoXmlReader<CardDetailReadData>(new StringReader(xmlData));
|
||||
var data = reader.Read();
|
||||
|
||||
var result = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == cardId &&
|
||||
detail.Pcol1 == data.Pcol1 && detail.Pcol2 == data.Pcol2 &&
|
||||
detail.Pcol3 == data.Pcol3);
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
return GenerateEmptyXml(Configs.CARD_DETAIL);
|
||||
}
|
||||
|
||||
var cardDetail = result.First();
|
||||
return GenerateSingleXml(cardDetail, Configs.CARD_DETAIL_SINGLE_XPATH);
|
||||
}
|
||||
|
||||
private string CardDetails(long cardId)
|
||||
{
|
||||
var result = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == cardId);
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
return GenerateEmptyXml(Configs.CARD_DETAIL);
|
||||
}
|
||||
|
||||
var cardDetails = result.ToList();
|
||||
|
||||
return GenerateRecordsXml(cardDetails, Configs.CARD_DETAIL_RECORD_XPATH);
|
||||
}
|
||||
|
||||
private string CardBData(long cardId)
|
||||
{
|
||||
var result = cardSqLiteConnection.Table<CardBData>()
|
||||
.Where(detail => detail.CardId == cardId);
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
return GenerateEmptyXml(Configs.CARD_BDATA);
|
||||
}
|
||||
var cardBData = result.First();
|
||||
|
||||
return GenerateSingleXml(cardBData, Configs.CARD_BDATA_XPATH);
|
||||
}
|
||||
|
||||
private static string GetStaticCount<T>(long cardId, int count, string xpath)
|
||||
where T : Record, IIdModel, ICardIdModel, new()
|
||||
{
|
||||
var models = new List<T>();
|
||||
|
||||
for (var id = 1; id <= count; id++)
|
||||
{
|
||||
var model = new T();
|
||||
model.SetId(id);
|
||||
model.SetCardId(cardId);
|
||||
models.Add(model);
|
||||
}
|
||||
|
||||
return GenerateRecordsXml(models, xpath);
|
||||
}
|
||||
|
||||
private static string GetSession(long cardId, string mac)
|
||||
{
|
||||
var session = new Session
|
||||
{
|
||||
CardId = cardId,
|
||||
Mac = mac,
|
||||
SessionId = "12345678901234567890123456789012",
|
||||
Expires = 9999,
|
||||
PlayerId = 1
|
||||
};
|
||||
|
||||
return GenerateSingleXml(session, Configs.SESSION_XPATH);
|
||||
}
|
||||
|
||||
private static string TotalTrophy(long cardId)
|
||||
{
|
||||
var trophy = new TotalTrophy
|
||||
{
|
||||
CardId = cardId,
|
||||
TrophyNum = 9
|
||||
};
|
||||
|
||||
return GenerateSingleXml(trophy, Configs.TOTAL_TROPHY_XPATH);
|
||||
}
|
||||
|
||||
private static string Coin(long cardId)
|
||||
{
|
||||
var coin = new Coin
|
||||
{
|
||||
CardId = cardId,
|
||||
CurrentCoins = 999999,
|
||||
TotalCoins = 999999,
|
||||
MonthlyCoins = 999999
|
||||
};
|
||||
|
||||
return GenerateSingleXml(coin, Configs.COIN_XPATH);
|
||||
}
|
||||
|
||||
private static string UnlockReward(long cardId)
|
||||
{
|
||||
var unlockRewards = new List<UnlockReward>
|
||||
{
|
||||
new()
|
||||
{
|
||||
CardId = cardId,
|
||||
RewardType = 1,
|
||||
RewardId = 1,
|
||||
TargetId = 1,
|
||||
TargetNum = 1,
|
||||
KeyNum = 3
|
||||
}
|
||||
};
|
||||
|
||||
return GenerateRecordsXml(unlockRewards, Configs.UNLOCK_REWARD_XPATH);
|
||||
}
|
||||
|
||||
private static string UnlockKeynum(long cardId)
|
||||
{
|
||||
var unlockKeynums = new List<UnlockKeynum>
|
||||
{
|
||||
new()
|
||||
{
|
||||
CardId = cardId,
|
||||
RewardId = 1,
|
||||
KeyNum = 0,
|
||||
RewardCount = 1
|
||||
}
|
||||
};
|
||||
|
||||
return GenerateRecordsXml(unlockKeynums, Configs.UNLOCK_KEYNUM_XPATH);
|
||||
}
|
||||
|
||||
private string MusicUnlock()
|
||||
{
|
||||
var result = musicSqLiteConnection.Table<Music>().ToList();
|
||||
|
||||
return GenerateRecordsXml(result, Configs.MUSIC_XPATH);
|
||||
}
|
||||
|
||||
private string MusicAouUnlock()
|
||||
{
|
||||
var result = musicSqLiteConnection.Table<MusicAou>().ToList();
|
||||
|
||||
return !result.Any() ? GenerateEmptyXml(Configs.MUSIC_AOU) : GenerateRecordsXml(result, Configs.MUSIC_AOU_XPATH);
|
||||
}
|
||||
|
||||
private string MusicExtra()
|
||||
{
|
||||
var result = musicSqLiteConnection.Table<MusicExtra>().ToList();
|
||||
|
||||
return GenerateRecordsXml(result, Configs.MUSIC_EXTRA_XPATH);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HelperMethods
|
||||
|
||||
private static string ConstructResponse(string xml, ReturnCode returnCode = ReturnCode.Ok)
|
||||
{
|
||||
var returnCodeInt = (int)returnCode;
|
||||
if (returnCodeInt == 1)
|
||||
{
|
||||
return $"{returnCodeInt}\n" +
|
||||
"1,1\n" +
|
||||
xml;
|
||||
}
|
||||
return $"{returnCodeInt}";
|
||||
}
|
||||
|
||||
private static string GenerateEmptyXml(string fieldName)
|
||||
{
|
||||
var xml = new XDocument(new XElement("root",
|
||||
new XElement(fieldName)));
|
||||
xml.Declaration = new XDeclaration("1.0", "UTF-8", null);
|
||||
|
||||
return xml.ToString();
|
||||
}
|
||||
|
||||
private static string GenerateSingleXml<T>(T obj, string xpath) where T : class
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
using (var writer = new ChoXmlWriter<T>(sb))
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.UseXmlSerialization = true;
|
||||
writer.WithXPath(xpath);
|
||||
|
||||
writer.Write(obj);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string GenerateRecordsXml<T>(IReadOnlyList<T> list, string xpath) where T : Record
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
var obj = list[i];
|
||||
obj.RecordId = i + 1;
|
||||
}
|
||||
|
||||
using (var writer = new ChoXmlWriter<T>(stringBuilder))
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.UseXmlSerialization = true;
|
||||
writer.WithXPath(xpath);
|
||||
writer.Write(list);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WriteImplementation
|
||||
|
||||
private void Write<T>(long cardId, string xmlData) where T : class, ICardIdModel
|
||||
{
|
||||
var reader = new ChoXmlReader<T>(new StringReader(xmlData)).WithXPath(Configs.DATA_XPATH);
|
||||
var writeObject = reader.Read();
|
||||
|
||||
if (writeObject == null)
|
||||
{
|
||||
throw new HttpRequestException();
|
||||
}
|
||||
|
||||
writeObject.SetCardId(cardId);
|
||||
var rowsAffected = cardSqLiteConnection.InsertOrReplace(writeObject, typeof(T));
|
||||
|
||||
if (rowsAffected == 0)
|
||||
{
|
||||
throw new ApplicationException("Update database failed!");
|
||||
}
|
||||
|
||||
$"Updated {typeof(T)}".Info();
|
||||
}
|
||||
|
||||
private void WriteCardPlayCount(long cardId)
|
||||
{
|
||||
var record = cardSqLiteConnection.Table<CardPlayCount>().Where(count => count.CardId == cardId);
|
||||
|
||||
if (!record.Any())
|
||||
{
|
||||
$"Created new play count data for card {cardId}".Info();
|
||||
var playCount = new CardPlayCount
|
||||
{
|
||||
CardId = cardId,
|
||||
PlayCount = 1,
|
||||
LastPlayed = DateTime.Now
|
||||
};
|
||||
cardSqLiteConnection.InsertOrReplace(playCount);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = record.First();
|
||||
var now = DateTime.Now;
|
||||
var lastPlayedTime = data.LastPlayed;
|
||||
|
||||
if (now <= lastPlayedTime)
|
||||
{
|
||||
$"Current time {now} is less than or equal to last played time! Clock skew detected!".Warn();
|
||||
data.PlayCount = 0;
|
||||
data.LastPlayed = DateTime.Now;
|
||||
cardSqLiteConnection.InsertOrReplace(data);
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
|
||||
if (now.Hour >= 8)
|
||||
{
|
||||
start = DateTime.Today.AddHours(8);
|
||||
end = start.AddHours(24);
|
||||
}
|
||||
else
|
||||
{
|
||||
end = DateTime.Today.AddHours(8);
|
||||
start = end.AddHours(-24);
|
||||
}
|
||||
|
||||
data.PlayCount = lastPlayedTime.IsBetween(start, end) ? data.PlayCount + 1 : 0;
|
||||
cardSqLiteConnection.InsertOrReplace(data);
|
||||
$"Updated card play count, current count is {data.PlayCount}".Info();
|
||||
}
|
||||
|
||||
private void WriteCardDetail(long cardId, string xmlData)
|
||||
{
|
||||
var result = cardSqLiteConnection.Table<CardDetail>()
|
||||
.Where(detail => detail.CardId == cardId);
|
||||
|
||||
// Unlock all unlockable songs in card details table when write card detail for the first time
|
||||
if (!result.Any())
|
||||
{
|
||||
UnlockSongs(cardId);
|
||||
}
|
||||
|
||||
var reader = new ChoXmlReader<CardDetail>(new StringReader(xmlData)).WithXPath(Configs.DATA_XPATH);
|
||||
var cardDetail = reader.Read();
|
||||
|
||||
if (cardDetail is null)
|
||||
{
|
||||
throw new HttpRequestException("Write object is null");
|
||||
}
|
||||
|
||||
cardDetail.SetCardId(cardId);
|
||||
cardDetail.LastPlayTime = DateTime.Now;
|
||||
var rowsAffected = cardSqLiteConnection.InsertOrReplace(cardDetail);
|
||||
if (rowsAffected == 0)
|
||||
{
|
||||
throw new ApplicationException("Update database failed!");
|
||||
}
|
||||
|
||||
"Updated card detail".Info();
|
||||
}
|
||||
private void UnlockSongs(long cardId)
|
||||
{
|
||||
var unlockableSongIds = Configs.SETTINGS.UnlockableSongIds;
|
||||
|
||||
if (unlockableSongIds is null)
|
||||
{
|
||||
unlockableSongIds = Configs.DEFAULT_UNLOCKABLE_SONGS;
|
||||
}
|
||||
var detailList = unlockableSongIds.Select(id => new CardDetail
|
||||
{
|
||||
CardId = cardId,
|
||||
Pcol1 = 10,
|
||||
Pcol2 = id,
|
||||
Pcol3 = 0,
|
||||
ScoreUi2 = 1,
|
||||
ScoreUi6 = 1,
|
||||
LastPlayTime = DateTime.Now
|
||||
})
|
||||
.ToList();
|
||||
|
||||
cardSqLiteConnection.InsertOrIgnoreAll(detailList);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OnlineMatchingImplementation
|
||||
|
||||
private static async Task<string> StartOnlineMatching(long cardId, string xmlData)
|
||||
{
|
||||
var reader = new ChoXmlReader<OnlineMatchingEntry>(new StringReader(xmlData)).WithXPath(Configs.DATA_XPATH);
|
||||
var entry = reader.Read();
|
||||
|
||||
var request = Converters.ConvertFromEntry(entry) ;
|
||||
request.CardId = cardId;
|
||||
request.EntryStart = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
request.MatchingTimeout = 20;
|
||||
request.MatchingRemainingTime = 3;
|
||||
request.MatchingWaitTime = 10;
|
||||
request.Status = 1;
|
||||
|
||||
var client = new HttpClient();
|
||||
var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.START_MATCHING_URL}";
|
||||
try
|
||||
{
|
||||
var response = await client.PostAsJsonAsync(url, request);
|
||||
var dataList = await response.Content.ReadFromJsonAsync<List<OnlineMatchingData>>();
|
||||
if (dataList is null)
|
||||
{
|
||||
throw new HttpRequestException("Start matching request fail");
|
||||
}
|
||||
var result = dataList.ConvertAll(input => Converters.ConvertFromData(input));
|
||||
return GenerateRecordsXml(result, Configs.ONLINE_MATCHING_XPATH);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error("", "Http request failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> UpdateOnlineMatching(long cardId, string xmlData)
|
||||
{
|
||||
var reader = new ChoXmlReader<OnlineMatchingUpdateData>(new StringReader(xmlData));
|
||||
var data = reader.Read();
|
||||
var request = new OnlineMatchingUpdateRequest
|
||||
{
|
||||
Action = data.Action,
|
||||
CardId = cardId,
|
||||
EventId = data.EventId,
|
||||
MatchingId = data.MatchingId,
|
||||
MessageId = data.MessageId
|
||||
};
|
||||
var client = new HttpClient();
|
||||
var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.UPDATE_MATCHING_URL}";
|
||||
try
|
||||
{
|
||||
var response = await client.PostAsJsonAsync(url, request);
|
||||
var dataList = await response.Content.ReadFromJsonAsync<List<OnlineMatchingEntry>>();
|
||||
if (dataList is null)
|
||||
{
|
||||
throw new HttpRequestException("Update matching request fail");
|
||||
}
|
||||
return GenerateRecordsXml(dataList, Configs.ONLINE_MATCHING_XPATH);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error("", "Http request failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<string> UploadOnlineMatchingResult(long cardId, string xmlData)
|
||||
{
|
||||
var reader = new ChoXmlReader<OnlineMatchingResultData>(new StringReader(xmlData));
|
||||
var data = reader.Read();
|
||||
var request = new OnlineMatchingFinishRequest
|
||||
{
|
||||
CardId = cardId,
|
||||
MatchingId = data.MatchingId
|
||||
};
|
||||
var client = new HttpClient();
|
||||
var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.UPDATE_MATCHING_URL}";
|
||||
try
|
||||
{
|
||||
var response = await client.PostAsJsonAsync(url, request);
|
||||
var success = await response.Content.ReadFromJsonAsync<bool>();
|
||||
|
||||
var result = new OnlineMatchingResult
|
||||
{
|
||||
Status = success ? 1:0
|
||||
};
|
||||
return GenerateSingleXml(result, Configs.ONLINE_BATTLE_RESULT_XPATH);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.Error("", "Http request failed");
|
||||
throw;
|
||||
}
|
||||
/*var entries = OnlineMatchingEntries[0xDEADBEEF];
|
||||
var entry = entries.Find(matchingEntry => matchingEntry.CardId == cardId);
|
||||
if (entry is null)
|
||||
{
|
||||
throw new HttpException(400,"Entry for this card id does not exist!");
|
||||
}
|
||||
|
||||
if (entry.MatchingId != data.MatchingId)
|
||||
{
|
||||
throw new HttpException(400,"Matching Id mismatch!");
|
||||
}
|
||||
|
||||
OnlineMatchingEntries[0xDEADBEEF].Remove(entry);
|
||||
var result = new OnlineMatchingResult
|
||||
{
|
||||
Status = 1
|
||||
};
|
||||
return GenerateSingleXml(result, Configs.ONLINE_BATTLE_RESULT_XPATH);*/
|
||||
}
|
||||
#endregion
|
||||
|
||||
private enum CardRequestType
|
||||
{
|
||||
// Read data
|
||||
ReadCard = 259,
|
||||
ReadCardDetail = 260,
|
||||
ReadCardDetails = 261,
|
||||
ReadCardBData = 264,
|
||||
ReadAvatar = 418,
|
||||
ReadItem = 420,
|
||||
ReadSkin = 422,
|
||||
ReadTitle = 424,
|
||||
ReadMusic = 428,
|
||||
ReadEventReward = 441,
|
||||
ReadNavigator = 443,
|
||||
ReadMusicExtra = 465,
|
||||
ReadMusicAou = 467,
|
||||
ReadCoin = 468,
|
||||
ReadUnlockReward = 507,
|
||||
ReadUnlockKeynum = 509,
|
||||
ReadSoundEffect = 8458,
|
||||
ReadGetMessage = 8461,
|
||||
ReadCond = 8465,
|
||||
ReadTotalTrophy = 8468,
|
||||
|
||||
// Sessions
|
||||
GetSession = 401,
|
||||
StartSession = 402,
|
||||
|
||||
// Write data
|
||||
WriteCard = 771,
|
||||
WriteCardDetail = 772,
|
||||
WriteCardBData = 776,
|
||||
WriteAvatar = 929,
|
||||
WriteItem = 931,
|
||||
WriteTitle = 935,
|
||||
WriteMusicDetail = 941,
|
||||
WriteNavigator = 954,
|
||||
WriteCoin = 980,
|
||||
WriteSkin = 933,
|
||||
WriteUnlockKeynum = 1020,
|
||||
WriteSoundEffect = 8969,
|
||||
|
||||
// Online matching
|
||||
StartOnlineMatching = 8705,
|
||||
UpdateOnlineMatching = 8961,
|
||||
UploadOnlineMatchingResult = 8709
|
||||
}
|
||||
|
||||
private enum Command
|
||||
{
|
||||
CardReadRequest = 256,
|
||||
CardWriteRequest = 768,
|
||||
RegisterRequest = 512,
|
||||
ReissueRequest = 1536
|
||||
}
|
||||
|
||||
private enum ReturnCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 処理は正常に完了しました in debug string
|
||||
/// </summary>
|
||||
Ok = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 未登録のカードです in debug string
|
||||
/// </summary>
|
||||
CardNotRegistered = 23,
|
||||
|
||||
/// <summary>
|
||||
/// 再発行予約がありません in debug string
|
||||
/// </summary>
|
||||
NotReissue = 27
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class IncomServiceController : WebApiController
|
||||
{
|
||||
[Route(HttpVerbs.Post, "/incom.php")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public string IncomService()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1+1";
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Post, "/incomALL.php")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public string IncomAllService()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1+1";
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.models;
|
||||
using SQLite.Net2;
|
||||
using Swan;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class OptionServiceController : WebApiController
|
||||
{
|
||||
|
||||
private readonly SQLiteConnection cardSqLiteConnection;
|
||||
|
||||
public OptionServiceController()
|
||||
{
|
||||
cardSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.CardDbName);
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/PlayInfo.php")]
|
||||
public string OptionService([QueryField("card_id")] long cardId)
|
||||
{
|
||||
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1\n" +
|
||||
$"{GetPlayCount(cardId)}";
|
||||
}
|
||||
|
||||
private int GetPlayCount(long cardId)
|
||||
{
|
||||
var record = cardSqLiteConnection.Table<CardPlayCount>().Where(count => count.CardId == cardId);
|
||||
|
||||
if (!record.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
var data = record.First();
|
||||
var lastPlayedTime = data.LastPlayed;
|
||||
|
||||
if (now <= lastPlayedTime)
|
||||
{
|
||||
$"Current time {now} is less than or equal to last played time! Clock skew detected!".Warn();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
if (now.Hour >= 8)
|
||||
{
|
||||
start = DateTime.Today.AddHours(8);
|
||||
end = start.AddHours(24);
|
||||
}
|
||||
else
|
||||
{
|
||||
end = DateTime.Today.AddHours(8);
|
||||
start = end.AddHours(-24);
|
||||
}
|
||||
|
||||
return lastPlayedTime.IsBetween(start, end) ? data.PlayCount : 0;
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using ChoETL;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.models;
|
||||
using SQLite.Net2;
|
||||
using Swan;
|
||||
using Swan.Logging;
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class RankController : WebApiController
|
||||
{
|
||||
private readonly SQLiteConnection cardSqLiteConnection;
|
||||
private readonly SQLiteConnection musicSqLiteConnection;
|
||||
|
||||
public RankController()
|
||||
{
|
||||
cardSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.CardDbName);
|
||||
musicSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.MusicDbName);
|
||||
}
|
||||
|
||||
|
||||
[Route(HttpVerbs.Get, "/ranking.php")]
|
||||
public string Rank([QueryField("cmd_type")] int type)
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Application.Octet;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
if (!Enum.IsDefined(typeof(RankType), type))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, "Rank type out of range");
|
||||
}
|
||||
|
||||
var requestType = (RankType)type;
|
||||
|
||||
switch (requestType)
|
||||
{
|
||||
case RankType.GlobalRank:
|
||||
case RankType.UnknownRank1:
|
||||
case RankType.UnknownRank2:
|
||||
case RankType.UnknownRank3:
|
||||
$"Getting rank request, type is {requestType}".Info();
|
||||
|
||||
return ConstructResponse(RankTemp("score_rank"));
|
||||
case RankType.PlayNumRank:
|
||||
$"Getting rank request, type is {requestType}".Info();
|
||||
|
||||
return ConstructResponse(PlayNumRank());
|
||||
case RankType.EventRank:
|
||||
$"Getting rank request, type is {requestType}".Info();
|
||||
|
||||
return ConstructResponse(RankTemp("event_rank"));
|
||||
default:
|
||||
#pragma warning disable CA2208
|
||||
throw new ArgumentOutOfRangeException(nameof(requestType));
|
||||
#pragma warning restore CA2208
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConstructResponse(string xml)
|
||||
{
|
||||
return "1\n" +
|
||||
xml;
|
||||
}
|
||||
|
||||
// TODO: Add proper rank support
|
||||
private static string RankTemp(string rankType)
|
||||
{
|
||||
var rankStatus = new RankStatus
|
||||
{
|
||||
Rows = 0,
|
||||
Status = 0
|
||||
};
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
using (var writer = new ChoXmlWriter<RankStatus>(sb))
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.UseXmlSerialization = true;
|
||||
writer.WithXPath(Configs.RANK_STATUS_XPATH);
|
||||
|
||||
writer.Write(rankStatus);
|
||||
}
|
||||
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(sb.ToString());
|
||||
var root = document.DocumentElement;
|
||||
|
||||
if (root == null)
|
||||
{
|
||||
throw SelfCheck.Failure("Internal XML error!");
|
||||
}
|
||||
|
||||
root.AppendChild(document.CreateElement(rankType));
|
||||
|
||||
var stringWriter = new StringWriter();
|
||||
var xmlTextWriter = new XmlTextWriter(stringWriter);
|
||||
document.WriteTo(xmlTextWriter);
|
||||
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
|
||||
private string PlayNumRank()
|
||||
{
|
||||
var rankStatus = new RankStatus
|
||||
{
|
||||
Rows = 30,
|
||||
TableName = "play_num_rank",
|
||||
Status = 1,
|
||||
EndDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
|
||||
var playNumRankContainer = new PlayNumRankContainer
|
||||
{
|
||||
PlayNumRankRecords = GetPlayNumRankRecords(),
|
||||
RankStatus = rankStatus
|
||||
};
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
using (var writer = new ChoXmlWriter<PlayNumRankContainer>(sb))
|
||||
{
|
||||
writer.Configuration.UseXmlSerialization = true;
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.IgnoreRootName = true;
|
||||
writer.Write(playNumRankContainer);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private List<PlayNumRankRecord> GetPlayNumRankRecords()
|
||||
{
|
||||
var records = new List<PlayNumRankRecord>();
|
||||
var musics = musicSqLiteConnection.Table<Music>().ToList().OrderBy(arg => Guid.NewGuid()).Take(30).ToList();
|
||||
|
||||
for (var i = 0; i < musics.Count; i++)
|
||||
{
|
||||
var music = musics[i];
|
||||
var index = i + 1;
|
||||
var record = new PlayNumRankRecord
|
||||
{
|
||||
Id = index,
|
||||
Rank = index,
|
||||
Rank2 = index + 1,
|
||||
PrevRank = musics.Count - i,
|
||||
PrevRank2 = index + 1,
|
||||
Artist = music.Artist,
|
||||
Pcol1 = music.MusicId,
|
||||
ScoreBi1 = index,
|
||||
Title = music.Title
|
||||
};
|
||||
records.Add(record);
|
||||
}
|
||||
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
private enum RankType
|
||||
{
|
||||
GlobalRank = 4119,
|
||||
PlayNumRank = 6657,
|
||||
EventRank = 6661,
|
||||
UnknownRank1 = 6666,
|
||||
UnknownRank2 = 6667,
|
||||
UnknownRank3 = 4098
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class ResponeServiceController : WebApiController
|
||||
{
|
||||
[Route(HttpVerbs.Post, "/respone.php")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public string ResponeService()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1";
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Net.Mime;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using Swan.Logging;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class ServerController : WebApiController
|
||||
{
|
||||
private static readonly string DataUrl = $"https://cert.nesys.jp/{Configs.STATIC_FOLDER}/{Configs.SETTINGS.EventFolder}";
|
||||
|
||||
[Route(HttpVerbs.Get, "/certify.php")]
|
||||
public string Certify([QueryData] NameValueCollection parameters)
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
var gid = parameters["gid"];
|
||||
var mac = parameters["mac"];
|
||||
var random = parameters["r"];
|
||||
var hash = parameters["md"];
|
||||
|
||||
if (gid == null)
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorNoGid);
|
||||
}
|
||||
|
||||
if (mac == null)
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorNoMac);
|
||||
}
|
||||
|
||||
if (random == null)
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorNoRandom);
|
||||
}
|
||||
|
||||
if (hash == null)
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorNoHash);
|
||||
}
|
||||
|
||||
if (!MacValid(mac))
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorInvalidMac);
|
||||
}
|
||||
|
||||
if (!Md5Valid(hash))
|
||||
{
|
||||
return QuitWithError(ErrorCode.ErrorInvalidHash);
|
||||
}
|
||||
|
||||
using var md5 = MD5.Create();
|
||||
|
||||
var ticket = string.Join(string.Empty,
|
||||
md5.ComputeHash(Encoding.UTF8.GetBytes(gid)).Select(b => b.ToString("x2")));
|
||||
|
||||
|
||||
var response = $"host=card_id=7020392000147361,relay_addr={Configs.SETTINGS.RelayServer},relay_port={Configs.SETTINGS.RelayPort}\n" +
|
||||
"no=1337\n" +
|
||||
"name=123\n" +
|
||||
"pref=nesys\n" +
|
||||
"addr=nesys@home\n" +
|
||||
"x-next-time=15\n" +
|
||||
$"x-img=http://{Configs.SETTINGS.ServerIp}{Configs.STATIC_BASE_ROUTE}/news.png\n" +
|
||||
$"x-ranking=http://{Configs.SETTINGS.ServerIp}{Configs.RANK_BASE_ROUTE}/ranking.php\n" +
|
||||
$"ticket={ticket}";
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/cursel.php")]
|
||||
public string Cursel()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1\n";
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/data.php")]
|
||||
public string Data()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
var responseList = Configs.SETTINGS.ResponseData.ToList();
|
||||
var count = responseList.Count;
|
||||
var dataString = new StringBuilder();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var data = responseList[i];
|
||||
var fileUrl = data.FileName.StartsWith("/") ? $"{DataUrl}{data.FileName}" : $"{DataUrl}/{data.FileName}";
|
||||
dataString.Append($"{i},{fileUrl},{data.NotBeforeUnixTime},{data.NotAfterUnixTime},{data.Md5},{data.Index}");
|
||||
dataString.Append('\n');
|
||||
}
|
||||
|
||||
return $"count={count}\n" +
|
||||
"nexttime=1\n" +
|
||||
(Configs.SETTINGS.DownloadEvents ? dataString.ToString().TrimEnd('\n') : "");
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, "/gameinfo.php")]
|
||||
public string GameInfo()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "0\n" +
|
||||
"3\n" +
|
||||
"301000,test1\n" +
|
||||
"302000,test2\n" +
|
||||
"303000,test3";
|
||||
}
|
||||
|
||||
private static bool MacValid(string mac)
|
||||
{
|
||||
return Regex.IsMatch(mac, "^[a-fA-F0-9]{12}$");
|
||||
}
|
||||
|
||||
private static bool Md5Valid(string md5)
|
||||
{
|
||||
return Regex.IsMatch(md5, "^[a-fA-F0-9]{32}$");
|
||||
}
|
||||
|
||||
private static string QuitWithError(ErrorCode errorCode)
|
||||
{
|
||||
return $"error={(int)errorCode}";
|
||||
}
|
||||
|
||||
private enum ErrorCode
|
||||
{
|
||||
ErrorNoGid,
|
||||
ErrorNoMac,
|
||||
ErrorNoRandom,
|
||||
ErrorNoHash,
|
||||
ErrorInvalidMac,
|
||||
ErrorInvalidHash
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers
|
||||
{
|
||||
// TODO: Add proper update check response
|
||||
public class UpdateController : WebApiController
|
||||
{
|
||||
[Route(HttpVerbs.Get, "/check.php")]
|
||||
public string CheckUpdate()
|
||||
{
|
||||
var parameters = HttpContext.GetRequestQueryData();
|
||||
foreach (var key in parameters.AllKeys)
|
||||
{
|
||||
$"Key {key}: {parameters[key]}".Info();
|
||||
}
|
||||
|
||||
HttpContext.Response.StatusCode = 404;
|
||||
return "Not found";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
|
||||
namespace GCLocalServerRewrite.controllers;
|
||||
|
||||
public class UploadServiceController : WebApiController
|
||||
{
|
||||
[Route(HttpVerbs.Post, "/upload.php")]
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public string UploadService()
|
||||
{
|
||||
HttpContext.Response.ContentType = MediaTypeNames.Text.Plain;
|
||||
HttpContext.Response.ContentEncoding = new UTF8Encoding(false);
|
||||
HttpContext.Response.KeepAlive = true;
|
||||
|
||||
return "1\n" +
|
||||
"OK";
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Avatar : Record , IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "avatar_id")]
|
||||
public int AvatarId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; } = 1;
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
AvatarId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using ChoETL;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("card_main")]
|
||||
public class Card : ICardIdModel
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("card_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "card_id")]
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[Column("player_name")]
|
||||
[ChoXmlElementRecordField(FieldName = "player_name")]
|
||||
[XmlElement(ElementName = "player_name")]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[Column("score_i1")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_i1")]
|
||||
[XmlElement("score_i1")]
|
||||
public int Score { get; set; }
|
||||
|
||||
[Column("fcol1")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol1")]
|
||||
[XmlElement("fcol1")]
|
||||
public int Fcol1 { get; set; }
|
||||
|
||||
[Column("fcol2")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol2")]
|
||||
[XmlElement("fcol2")]
|
||||
public int Fcol2 { get; set; }
|
||||
|
||||
[Column("fcol3")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol3")]
|
||||
[XmlElement("fcol3")]
|
||||
public int Fcol3 { get; set; }
|
||||
|
||||
[Column("achieve_status")]
|
||||
[ChoXmlElementRecordField(FieldName = "achieve_status")]
|
||||
[XmlElement("achieve_status")]
|
||||
public string AchieveStatus { get; set; } = string.Empty;
|
||||
|
||||
[Column("created")]
|
||||
[ChoXmlElementRecordField(FieldName = "created")]
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "2017-01-01 08:00:00";
|
||||
|
||||
[Column("modified")]
|
||||
[ChoXmlElementRecordField(FieldName = "modified")]
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "2017-01-01 08:00:00";
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using ChoETL;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("card_bdata")]
|
||||
public class CardBData : ICardIdModel
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("card_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "card_id")]
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[Column("bdata")]
|
||||
[ChoXmlElementRecordField(FieldName = "bdata")]
|
||||
[XmlElement(ElementName = "bdata")]
|
||||
public string BData { get; set; } = string.Empty;
|
||||
|
||||
[Column("bdata_size")]
|
||||
[ChoXmlElementRecordField(FieldName = "bdata_size")]
|
||||
[XmlElement(ElementName = "bdata_size")]
|
||||
public int BDataSize { get; set; }
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using ChoETL;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("card_detail")]
|
||||
public class CardDetail : Record, ICardIdModel
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("card_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "card_id")]
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[PrimaryKey]
|
||||
[Column("pcol1")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol1")]
|
||||
[XmlElement(ElementName = "pcol1")]
|
||||
public int Pcol1 { get; set; }
|
||||
|
||||
[PrimaryKey]
|
||||
[Column("pcol2")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol2")]
|
||||
[XmlElement(ElementName = "pcol2")]
|
||||
public int Pcol2 { get; set; }
|
||||
|
||||
[PrimaryKey]
|
||||
[Column("pcol3")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol3")]
|
||||
[XmlElement(ElementName = "pcol3")]
|
||||
public int Pcol3 { get; set; }
|
||||
|
||||
[Column("score_i1")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_i1")]
|
||||
[XmlElement(ElementName = "score_i1")]
|
||||
public long ScoreI1 { get; set; }
|
||||
|
||||
[Column("score_ui1")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui1")]
|
||||
[XmlElement(ElementName = "score_ui1")]
|
||||
public long ScoreUi1 { get; set; }
|
||||
|
||||
[Column("score_ui2")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui2")]
|
||||
[XmlElement(ElementName = "score_ui2")]
|
||||
public long ScoreUi2 { get; set; }
|
||||
|
||||
[Column("score_ui3")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui3")]
|
||||
[XmlElement(ElementName = "score_ui3")]
|
||||
public long ScoreUi3 { get; set; }
|
||||
|
||||
[Column("score_ui4")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui4")]
|
||||
[XmlElement(ElementName = "score_ui4")]
|
||||
public long ScoreUi4 { get; set; }
|
||||
|
||||
[Column("score_ui5")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui5")]
|
||||
[XmlElement(ElementName = "score_ui5")]
|
||||
public long ScoreUi5 { get; set; }
|
||||
|
||||
[Column("score_ui6")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_ui6")]
|
||||
[XmlElement(ElementName = "score_ui6")]
|
||||
public long ScoreUi6 { get; set; }
|
||||
|
||||
[Column("score_bi1")]
|
||||
[ChoXmlElementRecordField(FieldName = "score_bi1")]
|
||||
[XmlElement(ElementName = "score_bi1")]
|
||||
public long ScoreBi1 { get; set; }
|
||||
|
||||
[Column("last_play_tenpo_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "last_play_tenpo_id")]
|
||||
[XmlElement(ElementName = "last_play_tenpo_id")]
|
||||
public string LastPlayShopId { get; set; } = "1337";
|
||||
|
||||
[Column("fcol1")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol1")]
|
||||
[XmlElement("fcol1")]
|
||||
public int Fcol1 { get; set; }
|
||||
|
||||
[Column("fcol2")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol2")]
|
||||
[XmlElement("fcol2")]
|
||||
public int Fcol2 { get; set; }
|
||||
|
||||
[Column("fcol3")]
|
||||
[ChoXmlElementRecordField(FieldName = "fcol3")]
|
||||
[XmlElement("fcol3")]
|
||||
public int Fcol3 { get; set; }
|
||||
|
||||
[Column("last_play_time")]
|
||||
[XmlIgnore]
|
||||
public DateTime LastPlayTime { get; set; } = DateTime.MinValue;
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using ChoETL;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[ChoXmlRecordObject(XPath = "/root/data")]
|
||||
public class CardDetailReadData
|
||||
{
|
||||
[XmlElement(ElementName = "pcol1")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol1")]
|
||||
public int Pcol1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pcol2")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol2")]
|
||||
public int Pcol2 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pcol3")]
|
||||
[ChoXmlElementRecordField(FieldName = "pcol3")]
|
||||
public int Pcol3 { get; set; }
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class CardPlayCount
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[Column("play_count")]
|
||||
public int PlayCount { get; set; }
|
||||
|
||||
[Column("last_played_time")]
|
||||
public DateTime LastPlayed { get; set; }
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Coin
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "current")]
|
||||
public int CurrentCoins { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "total")]
|
||||
public int TotalCoins { get; set; }
|
||||
|
||||
[XmlElement("monthly")]
|
||||
public int MonthlyCoins { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public interface ICardIdModel
|
||||
{
|
||||
public void SetCardId(long cardId);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public interface IIdModel
|
||||
{
|
||||
public void SetId(int id);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Item : Record, IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "item_id")]
|
||||
public int ItemId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "item_num")]
|
||||
public int ItemNum { get; set; } = 90;
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
ItemId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("music_unlock")]
|
||||
public class Music : Record
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("music_id")]
|
||||
[XmlElement("music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[Column("title")]
|
||||
[XmlElement(ElementName = "title")]
|
||||
public string? Title { get; set; } = string.Empty;
|
||||
|
||||
[Column("artist")]
|
||||
[XmlElement(ElementName = "artist")]
|
||||
public string? Artist
|
||||
{
|
||||
get => _artist;
|
||||
set => _artist = value ?? string.Empty;
|
||||
}
|
||||
|
||||
private string? _artist = string.Empty;
|
||||
|
||||
[Column("release_date")]
|
||||
[XmlElement(ElementName = "release_date")]
|
||||
public string ReleaseDate { get; set; } = "2013-01-01 08:00:00";
|
||||
|
||||
[Column("end_date")]
|
||||
[XmlElement(ElementName = "end_date")]
|
||||
public string EndDate { get; set; } = "2030-01-01 08:00:00";
|
||||
|
||||
[Column("new_flag")]
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[Column("use_flag")]
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
|
||||
[Ignore]
|
||||
[XmlElement("calc_flag")]
|
||||
public uint CalcFlag { get; set; } = 2;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("music_aou")]
|
||||
public class MusicAou : Record
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("music_id")]
|
||||
[XmlElement("music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[Column("use_flag")]
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[Table("music_extra")]
|
||||
public class MusicExtra : Record
|
||||
{
|
||||
[PrimaryKey]
|
||||
[Column("music_id")]
|
||||
[XmlElement("music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[Column("use_flag")]
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Navigator : Record, IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "navigator_id")]
|
||||
public int NavigatorId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
NavigatorId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using ChoETL;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class OnlineMatchingEntry: Record
|
||||
{
|
||||
[XmlElement(ElementName = "machine_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "machine_id")]
|
||||
public long MachineId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "event_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "event_id")]
|
||||
public long EventId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "matching_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "matching_id")]
|
||||
public long MatchingId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "entry_no")]
|
||||
[ChoXmlElementRecordField(FieldName = "entry_no")]
|
||||
public long EntryNo { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "entry_start")]
|
||||
[ChoXmlElementRecordField(FieldName = "entry_start")]
|
||||
public string EntryStart { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
[XmlElement(ElementName = "status")]
|
||||
[ChoXmlElementRecordField(FieldName = "status")]
|
||||
public long Status { get; set; } = 1;
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "player_name")]
|
||||
[ChoXmlElementRecordField(FieldName = "player_name")]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "avatar_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "avatar_id")]
|
||||
public long AvatarId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "title_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "title_id")]
|
||||
public long TitleId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "class_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "class_id")]
|
||||
public long ClassId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "group_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "group_id")]
|
||||
public long GroupId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "tenpo_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "tenpo_id")]
|
||||
public long TenpoId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "tenpo_name")]
|
||||
[ChoXmlElementRecordField(FieldName = "tenpo_name")]
|
||||
public string TenpoName { get; set; } = "1337";
|
||||
|
||||
[XmlElement(ElementName = "pref_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "pref_id")]
|
||||
public long PrefId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pref")]
|
||||
[ChoXmlElementRecordField(FieldName = "pref")]
|
||||
public string Pref { get; set; } = "nesys";
|
||||
|
||||
[XmlElement(ElementName = "message_id")]
|
||||
[ChoXmlElementRecordField(FieldName = "message_id")]
|
||||
public long MessageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Communication timeout?
|
||||
/// </summary>
|
||||
[XmlElement(ElementName = "matching_timeout")]
|
||||
[ChoXmlElementRecordField(FieldName = "matching_timeout")]
|
||||
public long MatchingTimeout { get; set; } = 99;
|
||||
|
||||
/// <summary>
|
||||
/// Wait time
|
||||
/// </summary>
|
||||
[XmlElement(ElementName = "matching_wait_time")]
|
||||
[ChoXmlElementRecordField(FieldName = "matching_wait_time")]
|
||||
public long MatchingWaitTime { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Seems not used
|
||||
/// </summary>
|
||||
[XmlElement(ElementName = "matching_remaining_time")]
|
||||
[ChoXmlElementRecordField(FieldName = "matching_remaining_time")]
|
||||
public long MatchingRemainingTime { get; set; } = 89;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class OnlineMatchingResult
|
||||
{
|
||||
[XmlElement(ElementName = "status")]
|
||||
public int Status { get; set; }
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
using ChoETL;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[ChoXmlRecordObject(XPath = "/root/data")]
|
||||
public class OnlineMatchingResultData
|
||||
{
|
||||
[ChoXmlElementRecordField(FieldName = "event_id")]
|
||||
public long EventId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "matching_id")]
|
||||
public long MatchingId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "class_id")]
|
||||
public long ClassId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "group_id")]
|
||||
public long GroupId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "result_score")]
|
||||
public long ResultScore { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "result_star")]
|
||||
public long ResultStar { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "result_rank")]
|
||||
public long ResultRank { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "music_id_1st")]
|
||||
public long MusicIdFirst { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "music_id_2nd")]
|
||||
public long MusicIdSecond { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "music_id_3rd")]
|
||||
public long MusicIdThird { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "difficulty_lv_1st")]
|
||||
public long DifficultyFirst { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "difficulty_lv_2nd")]
|
||||
public long DifficultySecond { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "difficulty_lv_3rd")]
|
||||
public long DifficultyThird { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "item_id_1st")]
|
||||
public long ItemIdFirst { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "item_id_2nd")]
|
||||
public long ItemIdSecond { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "item_id_3rd")]
|
||||
public long ItemIdThird { get; set; }
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using ChoETL;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[ChoXmlRecordObject(XPath = "/root/data")]
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
public class OnlineMatchingUpdateData
|
||||
{
|
||||
[ChoXmlElementRecordField(FieldName = "action")]
|
||||
public long Action { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "event_id")]
|
||||
public long EventId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "matching_id")]
|
||||
public long MatchingId { get; set; }
|
||||
|
||||
[ChoXmlElementRecordField(FieldName = "message_id")]
|
||||
public long MessageId { get; set; }
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class PlayNumRankContainer
|
||||
{
|
||||
[XmlArray("play_num_rank")]
|
||||
public List<PlayNumRankRecord> PlayNumRankRecords { get; set; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus? RankStatus { get; set; }
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[XmlType("record")]
|
||||
public class PlayNumRankRecord
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement("rank")]
|
||||
public int Rank { get; set; }
|
||||
|
||||
[XmlElement("rank2")]
|
||||
public int Rank2 { get; set; }
|
||||
|
||||
[XmlElement("prev_rank")]
|
||||
public int PrevRank { get; set; }
|
||||
|
||||
[XmlElement("prev_rank2")]
|
||||
public int PrevRank2 { get; set; }
|
||||
|
||||
[XmlElement("pcol1")]
|
||||
public int Pcol1 { get; set; }
|
||||
|
||||
[XmlElement("score_bi1")]
|
||||
public int ScoreBi1 { get; set; }
|
||||
|
||||
[XmlElement("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
[XmlElement("artist")]
|
||||
public string? Artist { get; set; }
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[XmlType("ranking_status")]
|
||||
public class RankStatus
|
||||
{
|
||||
[XmlElement("table_name")]
|
||||
public string TableName { get; set; } = "rank_table";
|
||||
|
||||
[XmlElement("start_date")]
|
||||
public string StartDate { get; set; } = "2021-05-30";
|
||||
|
||||
[XmlElement("end_date")]
|
||||
public string EndDate { get; set; } = "2022-06-08";
|
||||
|
||||
[XmlElement("status")]
|
||||
public int Status { get; set; }
|
||||
|
||||
[XmlElement("rows")]
|
||||
public int Rows { get; set; }
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
using SQLite.Net2;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Record
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
[Ignore]
|
||||
public int RecordId { get; set; }
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Session
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "mac_addr")]
|
||||
public string Mac { get; set; } = "000000000000";
|
||||
|
||||
[XmlElement(ElementName = "session_id")]
|
||||
public string SessionId { get; set; } = "12345678901234567890123456789012";
|
||||
|
||||
[XmlElement(ElementName = "expires")]
|
||||
public int Expires { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "player_id")]
|
||||
public int PlayerId { get; set; }
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Skin : Record, IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "skin_id")]
|
||||
public int SkinId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
SkinId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class SoundEffect : Record, IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "sound_effect_id")]
|
||||
public int SeId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
SeId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Title : Record, IIdModel, ICardIdModel
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "title_id")]
|
||||
public int TitleId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
TitleId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class TotalTrophy
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "total_trophy_num")]
|
||||
public int TrophyNum { get; set; }
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class UnlockKeynum : Record
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_id")]
|
||||
public int RewardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "key_num")]
|
||||
public int KeyNum { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_count")]
|
||||
public int RewardCount { get; set; }
|
||||
|
||||
[XmlElement("expired_flag")]
|
||||
public int ExpiredFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
[XmlElement("cash_flag")]
|
||||
public int CashFlag { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class UnlockReward : Record
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_id")]
|
||||
public int RewardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_type")]
|
||||
public int RewardType { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "open_date")]
|
||||
public string OpenDate { get; set; } = "2021-05-30";
|
||||
|
||||
[XmlElement(ElementName = "close_date")]
|
||||
public string CloseDate { get; set; } = "2030-05-30";
|
||||
|
||||
[XmlElement(ElementName = "open_time")]
|
||||
public string OpenTime { get; set; } = "00:00:01";
|
||||
|
||||
[XmlElement(ElementName = "close_time")]
|
||||
public string CloseTime { get; set; } = "23:59:59";
|
||||
|
||||
[XmlElement(ElementName = "target_id")]
|
||||
public int TargetId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "target_num")]
|
||||
public int TargetNum { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "key_num")]
|
||||
public int KeyNum { get; set; }
|
||||
|
||||
[XmlElement("display_flag")]
|
||||
public int DisplayFlag { get; set; } = 1;
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
[XmlElement("limited_flag")]
|
||||
public int LimitedFlag { get; set; }
|
||||
|
||||
[XmlElement("open_unixtime")]
|
||||
public long OpenUnixTime { get; set; } = 1622304001;
|
||||
|
||||
[XmlElement("close_unixtime")]
|
||||
public long CloseUnixTime { get; set; } = 1906387199;
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Actions;
|
||||
using EmbedIO.Files;
|
||||
using EmbedIO.WebApi;
|
||||
using GCLocalServerRewrite.common;
|
||||
using GCLocalServerRewrite.controllers;
|
||||
using GCLocalServerRewrite.models;
|
||||
using Swan.Logging;
|
||||
using System.Text;
|
||||
using Swan;
|
||||
|
||||
namespace GCLocalServerRewrite.server;
|
||||
|
||||
public class Server
|
||||
{
|
||||
public static WebServer CreateWebServer(IEnumerable<string> urlPrefixes)
|
||||
{
|
||||
InitializeDatabase();
|
||||
X509Certificate2 cert;
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
{
|
||||
cert = CertificateHelper.InitializeCertificate();
|
||||
}
|
||||
else
|
||||
{
|
||||
var certPath = Path.Combine(PathHelper.CertRootPath, "cert.pfx");
|
||||
var certPassword = string.Empty;
|
||||
var collection = new X509Certificate2Collection();
|
||||
collection.Import(certPath, null, X509KeyStorageFlags.PersistKeySet |
|
||||
X509KeyStorageFlags.MachineKeySet |
|
||||
X509KeyStorageFlags.Exportable);
|
||||
if (!collection.Any())
|
||||
{
|
||||
SelfCheck.Failure("Failed to import certificate!!!");
|
||||
}
|
||||
cert = collection.First();
|
||||
}
|
||||
|
||||
var server = new WebServer(webServerOptions => webServerOptions
|
||||
.WithUrlPrefixes(urlPrefixes)
|
||||
.WithCertificate(cert)
|
||||
.WithMode(HttpListenerMode.EmbedIO))
|
||||
.WithLocalSessionManager()
|
||||
.WithCors()
|
||||
.WithWebApi(Configs.API_BASE_ROUTE, module => module.WithController<ApiController>())
|
||||
.WithWebApi(Configs.CARD_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<CardServiceController>())
|
||||
.WithWebApi(Configs.OPTION_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<OptionServiceController>())
|
||||
.WithWebApi(Configs.UPLOAD_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<UploadServiceController>())
|
||||
.WithWebApi(Configs.RESPONE_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<ResponeServiceController>())
|
||||
.WithWebApi(Configs.INCOM_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<IncomServiceController>())
|
||||
.WithWebApi(Configs.ALIVE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<AliveController>())
|
||||
.WithWebApi(Configs.SERVER_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<ServerController>())
|
||||
.WithWebApi(Configs.RANK_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<RankController>())
|
||||
.WithWebApi(Configs.UPDATE_SERVICE_BASE_ROUTE, ResponseSerializer.None(true),
|
||||
module => module.WithController<UpdateController>())
|
||||
.WithStaticFolder(Configs.STATIC_BASE_ROUTE, PathHelper.HtmlRootPath, true, m => m
|
||||
.WithContentCaching(Configs.USE_FILE_CACHE))
|
||||
// Add static files after other modules to avoid conflicts
|
||||
.WithStaticFolder("/", PathHelper.HtmlRootPath, true, m =>
|
||||
{
|
||||
m.WithContentCaching(Configs.USE_FILE_CACHE);
|
||||
m.OnMappingFailed = async (context, info) =>
|
||||
{
|
||||
var htmlContents = await File.ReadAllTextAsync(Path.Combine(PathHelper.HtmlRootPath, "index.html"));
|
||||
context.Response.StatusCode = 200;
|
||||
await context.SendStringAsync(htmlContents, "text/html", Encoding.UTF8);
|
||||
};
|
||||
})
|
||||
.WithModule(new ActionModule("/", HttpVerbs.Any,
|
||||
ctx => ctx.SendDataAsync(new { Message = "Error" })));
|
||||
server.AddCustomMimeType(".dll", "application/octet-stream");
|
||||
server.AddCustomMimeType(".blat", "application/octet-stream");
|
||||
server.AddCustomMimeType(".dat", "application/octet-stream");
|
||||
server.AddCustomMimeType(".json", "application/json");
|
||||
server.AddCustomMimeType(".wasm", "application/wasm");
|
||||
server.AddCustomMimeType(".woff", "application/font-woff");
|
||||
server.AddCustomMimeType(".woff2", "application/font-woff2");
|
||||
|
||||
// Listen for state changes.
|
||||
server.StateChanged += (_, e) => $"WebServer New State - {e.NewState}".Info();
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
private static void InitializeDatabase()
|
||||
{
|
||||
DatabaseHelper.InitializeLocalDatabase(Configs.SETTINGS.CardDbName,
|
||||
typeof(Card), typeof(CardBData), typeof(CardDetail), typeof(CardPlayCount));
|
||||
DatabaseHelper.InitializeLocalDatabase(Configs.SETTINGS.MusicDbName,
|
||||
typeof(Music), typeof(MusicAou), typeof(MusicExtra));
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
Hello world!
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 818 B |
@ -1,131 +0,0 @@
|
||||
using MatchServer.Storage;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedProject.models;
|
||||
|
||||
namespace MatchServer.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class MatchingController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<MatchingController> logger;
|
||||
|
||||
|
||||
public MatchingController(ILogger<MatchingController> logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[HttpPost("Start")]
|
||||
public ActionResult<IEnumerable<OnlineMatchingData>> StartOnlineMatching(OnlineMatchingData startData)
|
||||
{
|
||||
logger.LogInformation("Start matching, card id {CardId}, player name {PlayerName}", startData.CardId, startData.PlayerName);
|
||||
var matchingDb = MatchingDb.GetInstance;
|
||||
|
||||
lock (matchingDb.DbLock)
|
||||
{
|
||||
foreach (var (matchingId, entries) in matchingDb.MatchingDictionary)
|
||||
{
|
||||
if (entries.Count >= 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entries.Any(data => data.CardId == startData.CardId))
|
||||
{
|
||||
logger.LogWarning("Card id {CardId} already exists in matching id {MatchingId}", startData.CardId, matchingId);
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.Add(startData);
|
||||
startData.MatchingId = matchingId;
|
||||
startData.EntryNo = entries.Count - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (startData.MatchingId != 0)
|
||||
{
|
||||
return Ok(matchingDb.MatchingDictionary[startData.MatchingId]);
|
||||
}
|
||||
|
||||
startData.MatchingId = matchingDb.MatchingDictionary.Count + 1;
|
||||
startData.EntryNo = 0;
|
||||
matchingDb.MatchingDictionary[startData.MatchingId] = new List<OnlineMatchingData>
|
||||
{
|
||||
startData
|
||||
};
|
||||
|
||||
return Ok(matchingDb.MatchingDictionary[startData.MatchingId]);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("Update")]
|
||||
public ActionResult<IEnumerable<OnlineMatchingUpdateRequest>> UpdateOnlineMatching(OnlineMatchingUpdateRequest updateData)
|
||||
{
|
||||
var matchingDb = MatchingDb.GetInstance;
|
||||
var matchingId = updateData.MatchingId;
|
||||
|
||||
logger.LogInformation("Update matching, card id is {CardId}, matching id is {MatchingId}", updateData.CardId, updateData.MatchingId);
|
||||
|
||||
if (!matchingDb.MatchingDictionary.ContainsKey(matchingId))
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var dataList = matchingDb.MatchingDictionary[matchingId];
|
||||
|
||||
var data = dataList.Find(data => data.CardId == updateData.CardId);
|
||||
if (data is null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
data.MessageId = updateData.MessageId;
|
||||
if (data.MatchingRemainingTime <= 0)
|
||||
{
|
||||
data.Status = 3;
|
||||
return Ok(dataList);
|
||||
}
|
||||
|
||||
data.MatchingRemainingTime--;
|
||||
return Ok(dataList);
|
||||
}
|
||||
|
||||
[HttpPost("Finish")]
|
||||
public ActionResult<bool> FinishOnlineMatching(OnlineMatchingFinishRequest request)
|
||||
{
|
||||
var matchingDb = MatchingDb.GetInstance;
|
||||
var matchingId = request.MatchingId;
|
||||
|
||||
lock (matchingDb.DbLock)
|
||||
{
|
||||
if (!matchingDb.MatchingDictionary.ContainsKey(matchingId))
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
var dataList = matchingDb.MatchingDictionary[matchingId];
|
||||
|
||||
var index = dataList.FindIndex(data => data.CardId == request.CardId);
|
||||
dataList.RemoveAt(index);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpGet("Debug")]
|
||||
public ActionResult<Dictionary<long, List<OnlineMatchingUpdateRequest>>> InspectOnlineMatching()
|
||||
{
|
||||
var matchingDb = MatchingDb.GetInstance;
|
||||
|
||||
return Ok(matchingDb.MatchingDictionary);
|
||||
}
|
||||
|
||||
[HttpGet("Clear")]
|
||||
public ActionResult<bool> Clear()
|
||||
{
|
||||
var matchingDb = MatchingDb.GetInstance;
|
||||
lock (matchingDb.DbLock)
|
||||
{
|
||||
matchingDb.MatchingDictionary.Clear();
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,21 +0,0 @@
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:45319",
|
||||
"sslPort": 44313
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"MatchServer": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7023;http://localhost:5038",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using SharedProject.models;
|
||||
|
||||
namespace MatchServer.Storage;
|
||||
|
||||
public class MatchingDb
|
||||
{
|
||||
public Dictionary<long, List<OnlineMatchingData>> MatchingDictionary;
|
||||
|
||||
public object DbLock = new();
|
||||
|
||||
static MatchingDb()
|
||||
{
|
||||
}
|
||||
|
||||
private MatchingDb()
|
||||
{
|
||||
MatchingDictionary = new Dictionary<long, List<OnlineMatchingData>>();
|
||||
}
|
||||
|
||||
public static MatchingDb GetInstance { get; } = new MatchingDb();
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
@ -1,12 +0,0 @@
|
||||
<linker>
|
||||
<assembly fullname="MudBlazor" preserve="all">
|
||||
<type fullname="MudBlazor.FilterOperator" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterOperator/String" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterOperator/Number" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterOperator/Enum" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterOperator/Boolean" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterOperator/DateTime" preserve="all" />
|
||||
<type fullname="MudBlazor.FilterDefinition`1" preserve="all" />
|
||||
<type fullname="MudBlazor.Filter" preserve="all" />
|
||||
</assembly>
|
||||
</linker>
|
@ -1,81 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<RunAOTCompilation>False</RunAOTCompilation>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<RunAOTCompilation>True</RunAOTCompilation>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
|
||||
<TrimmerSingleWarn>false</TrimmerSingleWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="ILLink.Descriptors.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ILLink.Descriptors.xml">
|
||||
<LogicalName>ILLink.Descriptors.xml</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GenFu" Version="1.6.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.10" PrivateAssets="all" />
|
||||
<PackageReference Include="MudBlazor" Version="6.0.17" />
|
||||
<PackageReference Include="protobuf-net" Version="3.1.22" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\avatar.dat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\avatar.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\navigator.dat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\navigator.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\title.dat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\title.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Update="wwwroot\news.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Utils" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31717.71
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MudAdmin", "MudAdmin.csproj", "{D6DF8A15-5B8D-4302-90D2-FC71264B18CC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D6DF8A15-5B8D-4302-90D2-FC71264B18CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6DF8A15-5B8D-4302-90D2-FC71264B18CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6DF8A15-5B8D-4302-90D2-FC71264B18CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6DF8A15-5B8D-4302-90D2-FC71264B18CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {58C61F27-917C-435B-8900-9B3CE8F8DCD4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,73 +0,0 @@
|
||||
@using SharedProject.common
|
||||
@using System.Text.RegularExpressions
|
||||
@inject HttpClient Client
|
||||
@inject ILogger<ChangePlayerNameDialog> Logger
|
||||
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">
|
||||
Change Player Name
|
||||
</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<MudForm @bind-IsValid="IsValid">
|
||||
<MudTextField Value="@Data.CardId" Label="CardId" ReadOnly="true"/>
|
||||
<MudTextField @bind-Value="Data.PlayerName"
|
||||
Immediate="true"
|
||||
Counter="SharedConstants.MAX_PLAYER_NAME_LENGTH"
|
||||
MaxLength="SharedConstants.MAX_PLAYER_NAME_LENGTH"
|
||||
Validation="ValidatePlayerName"/>
|
||||
</MudForm>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel">Cancel</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="Submit" Disabled="@(!IsValid)">Confirm</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SharedProject.models.User Data { get; set; } = null!;
|
||||
|
||||
private string originalName = string.Empty;
|
||||
|
||||
private bool IsValid { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
originalName = new string(Data.PlayerName);
|
||||
}
|
||||
|
||||
async Task Submit()
|
||||
{
|
||||
Logger.LogInformation("Data is {cardId}, {name}", Data.CardId, Data.PlayerName);
|
||||
var response = await Client.PostAsJsonAsync("api/Users/SetPlayerName", Data);
|
||||
var result = await response.Content.ReadFromJsonAsync<bool>();
|
||||
Logger.LogInformation("SetPlayerName result is {result}", result);
|
||||
MudDialog.Close(DialogResult.Ok(result));
|
||||
}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
Data.PlayerName = originalName;
|
||||
MudDialog.Cancel();
|
||||
}
|
||||
|
||||
private static string? ValidatePlayerName(string playerName)
|
||||
{
|
||||
const string pattern = @"^[a-zA-Z0-9!?,./\-+:<>_\\@*#&=() ]{1,8}$";
|
||||
|
||||
return playerName.Length switch
|
||||
{
|
||||
0 => "Player name cannot be empty!",
|
||||
> 8 => "Player name cannot be longer than 8 characters!",
|
||||
_ => !Regex.IsMatch(playerName, pattern) ? "Player name contains invalid character!" : null
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
@using SharedProject.models
|
||||
@inject HttpClient Client
|
||||
@inject ILogger<FavoriteDialog> Logger
|
||||
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
@if (!Data.IsFavorite)
|
||||
{
|
||||
<MudText Typo="Typo.h6">
|
||||
<MudIcon Icon="@Icons.Material.Filled.BookmarkAdd" Color="Color.Secondary"/>
|
||||
Add to favorite?
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.h6">
|
||||
<MudIcon Icon="@Icons.Material.Filled.BookmarkRemove" Color="Color.Secondary"/>
|
||||
Remove from favorite?
|
||||
</MudText>
|
||||
}
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<MudTextField Value="@Data.Title" Label="Song Title" ReadOnly="true"/>
|
||||
<MudTextField Value="@Data.Artist" Label="Artist Name" ReadOnly="true"/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel">Cancel</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="Submit">Confirm</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public SongPlayData Data { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public long CardId { get; set; }
|
||||
|
||||
async Task Submit()
|
||||
{
|
||||
var postData = new MusicFavoriteData
|
||||
{
|
||||
CardId = CardId,
|
||||
IsFavorite = !Data.IsFavorite,
|
||||
MusicId = Data.MusicId
|
||||
};
|
||||
Logger.LogInformation("Data is {cardId}, {musicId}", CardId, Data.MusicId);
|
||||
var response = await Client.PostAsJsonAsync("api/UserDetail/SetMusicFavorite", postData);
|
||||
var result = await response.Content.ReadFromJsonAsync<bool>();
|
||||
Logger.LogInformation("Favorite result is {result}", result);
|
||||
MudDialog.Close(DialogResult.Ok(result));
|
||||
}
|
||||
|
||||
void Cancel() => MudDialog.Cancel();
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Index</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3" GutterBottom="true">Admin page for GC local server</MudText>
|
||||
<MudText Class="mb-8">Powered by MudBlazor</MudText>
|
@ -1,305 +0,0 @@
|
||||
@page "/user/{CardId:long}"
|
||||
@using SharedProject.models
|
||||
@using SharedProject.enums
|
||||
|
||||
<PageTitle>User</PageTitle>
|
||||
<MudContainer>
|
||||
@if (pageLoading)
|
||||
{
|
||||
<MudSkeleton Width="1184px" Height="57px"/>
|
||||
<MudSkeleton Width="1184px" Height="57px"/>
|
||||
<MudSkeleton Width="1184px" Height="57px"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (userDetail is null)
|
||||
{
|
||||
<MudText Typo="Typo.h3">No Data</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudExpansionPanels>
|
||||
<MudExpansionPanel Text="Total Result">
|
||||
<MudList>
|
||||
<MudListSubheader>Player Name: @userDetail.PlayerName</MudListSubheader>
|
||||
<MudListItem>Total Score: @userDetail.TotalScore</MudListItem>
|
||||
<MudListItem>Average Score: @userDetail.AverageScore</MudListItem>
|
||||
<MudListItem>Played Song Count: @userDetail.PlayedSongCount / @userDetail.TotalSongCount</MudListItem>
|
||||
<MudListItem>Cleared Stage Count: @userDetail.ClearedStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>No Miss Stage Count: @userDetail.NoMissStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>Full Chain Stage Count: @userDetail.FullChainStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>Perfect Stage Count: @userDetail.PerfectStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>S and Above Stage Count: @userDetail.SAboveStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>S+ and Above Stage Count: @userDetail.SPlusAboveStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
<MudListItem>S++ and Above Stage Count: @userDetail.SPlusPlusAboveStageCount / @userDetail.TotalStageCount</MudListItem>
|
||||
</MudList>
|
||||
</MudExpansionPanel>
|
||||
<MudExpansionPanel Text="PlayOptions">
|
||||
<MudStack>
|
||||
<MudSelect @bind-Value="@playOption.FastSlowIndicator"
|
||||
Label="FAST/SLOW show setting">
|
||||
@foreach (var item in Enum.GetValues<PlayOptions.FastSlowIndicator>())
|
||||
{
|
||||
<MudSelectItem Value="@item">@item.GetHelpText()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@playOption.FeverTrance"
|
||||
Label="FEVER/TRANCE show setting">
|
||||
@foreach (var item in Enum.GetValues<PlayOptions.FeverTranceShow>())
|
||||
{
|
||||
<MudSelectItem Value="@item">@item.GetHelpText()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudStack Row="true">
|
||||
<MudField Label="Navigator setting">
|
||||
@NavigatorIdToString(playOption.NavigatorId)
|
||||
</MudField>
|
||||
<MudButton Variant="Variant.Text"
|
||||
|
||||
OnClick="OnChangeNavigatorButtonClick">
|
||||
Change Navigator
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true">
|
||||
<MudField Label="Avatar setting">
|
||||
@AvatarIdToString(playOption.AvatarId)
|
||||
</MudField>
|
||||
<MudButton Variant="Variant.Text"
|
||||
OnClick="OnChangeAvatarButtonClick">
|
||||
Change Avatar
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true">
|
||||
<MudField Label="Title setting">
|
||||
@TitleIdToString(playOption.TitleId)
|
||||
</MudField>
|
||||
<MudButton Variant="Variant.Text"
|
||||
OnClick="OnChangeTitleButtonClick">
|
||||
Change Title
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudOverlay @bind-Visible="IsNavigatorOverlayVisible"
|
||||
DarkBackground="true">
|
||||
<MudPaper>
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudStack>
|
||||
<MudDataGrid T="Navigator"
|
||||
MultiSelection="false" @bind-SelectedItem="SelectedNavigator"
|
||||
FixedHeader="true" FixedFooter="true" Height="70vh"
|
||||
Items="navigatorDictionary.Values" ReadOnly="true" Hover="true"
|
||||
Sortable="true" Filterable="true" Hideable="true">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Navigators</MudText>
|
||||
<MudSpacer/>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.Id)"/>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.IdString)"/>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.NameEntryString)" Title="Navigator Name"
|
||||
SortBy="NameEntrySortByFunc"/>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.ToolTipJp)" Title="Navigator Description (Japanese)"/>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.ToolTipEn)" Title="Navigator Description (English)"/>
|
||||
<Column T="Navigator" Field="@nameof(Navigator.Genre)" Title="Navigator Type"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="Navigator"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
<MudText Align="Align.Left">
|
||||
Currently selected navigator:<br>
|
||||
@SelectedNavigator
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
||||
OnClick="OnNavigatorOverlayClosed">
|
||||
Close
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</MudPaper>
|
||||
</MudOverlay>
|
||||
|
||||
<MudOverlay @bind-Visible="IsAvatarOverlayVisible"
|
||||
DarkBackground="true">
|
||||
<MudPaper>
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudStack>
|
||||
<MudDataGrid T="Avatar"
|
||||
MultiSelection="false" @bind-SelectedItem="SelectedAvatar"
|
||||
FixedHeader="true" FixedFooter="true" Height="70vh"
|
||||
Items="avatarDictionary.Values" ReadOnly="true" Hover="true"
|
||||
Sortable="true" Filterable="true" Hideable="true">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Avatars</MudText>
|
||||
<MudSpacer/>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<Column T="Avatar" Field="@nameof(Avatar.Id)"/>
|
||||
<Column T="Avatar" Field="@nameof(Avatar.IdString)"/>
|
||||
<Column T="Avatar" Field="@nameof(Avatar.FullName)" Title="Avatar Name"/>
|
||||
<Column T="Avatar" Field="@nameof(Avatar.AcquireMethodJp)" Title="Acquire Method (Japanese)"/>
|
||||
<Column T="Avatar" Field="@nameof(Avatar.AcquireMethodEn)" Title="Acquire Method (English)"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="Avatar"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
<MudText Align="Align.Left">
|
||||
Currently selected avatar:<br>
|
||||
@SelectedAvatar
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
||||
OnClick="OnAvatarOverlayClosed">
|
||||
Close
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</MudPaper>
|
||||
</MudOverlay>
|
||||
|
||||
<MudOverlay @bind-Visible="IsTitleOverlayVisible"
|
||||
DarkBackground="true">
|
||||
<MudPaper>
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudStack>
|
||||
<MudDataGrid T="Title"
|
||||
MultiSelection="false" @bind-SelectedItem="SelectedTitle"
|
||||
FixedHeader="true" FixedFooter="true" Height="70vh"
|
||||
Items="titleDictionary.Values" ReadOnly="true" Hover="true"
|
||||
Sortable="true" Filterable="true" Hideable="true">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Titles</MudText>
|
||||
<MudSpacer/>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<Column T="Title" Field="@nameof(Title.Id)"/>
|
||||
<Column T="Title" Field="@nameof(Title.IdString)"/>
|
||||
<Column T="Title" Field="@nameof(Title.NameJp)" Title="Title Name"/>
|
||||
<Column T="Title" Field="@nameof(Title.UnlockRequirementJp)" Title="Unlock Requirement (Japanese)"/>
|
||||
<Column T="Title" Field="@nameof(Title.UnlockRequirementEng)" Title="Unlock Requirement (English)"/>
|
||||
<Column T="Title" Field="@nameof(Title.Type)" Title="Title Type"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="Title"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
<MudText Align="Align.Left">
|
||||
Currently selected title:<br>
|
||||
@SelectedTitle
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
||||
OnClick="OnTitleOverlayClosed">
|
||||
Close
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</MudPaper>
|
||||
</MudOverlay>
|
||||
|
||||
<MudButton Disabled="@isSavingOptions"
|
||||
OnClick="SaveOptions"
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Info">
|
||||
@if (isSavingOptions)
|
||||
{
|
||||
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true"/>
|
||||
<MudText Class="ms-2">Saving...</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIcon Icon="@Icons.Filled.Save"></MudIcon>
|
||||
<MudText>Save</MudText>
|
||||
}
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudExpansionPanel>
|
||||
<MudExpansionPanel Text="SongPlayData">
|
||||
<MudDataGrid T="SongPlayData"
|
||||
Items="@songPlayDataList"
|
||||
Sortable="true"
|
||||
Filterable="true">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Played Songs</MudText>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<Column T="SongPlayData" Sortable="false" Filterable="false">
|
||||
<CellTemplate>
|
||||
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||
OnClick="@(() => OnShowDetailsClick(context.Item))">
|
||||
@(context.Item.ShowDetails ? "Hide" : "Show") Song Play Details
|
||||
</MudButton>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongPlayData" Field="@nameof(SongPlayData.IsFavorite)" Sortable="false" Title="Favorite">
|
||||
<CellTemplate>
|
||||
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
|
||||
ToggledChanged="@(() => OnFavoriteToggled(context.Item))"
|
||||
Icon="@Icons.Material.Filled.FavoriteBorder"
|
||||
Color="@Color.Secondary"
|
||||
Title="Add to favorite"
|
||||
ToggledIcon="@Icons.Material.Filled.Favorite"
|
||||
ToggledColor="@Color.Secondary"
|
||||
ToggledTitle="Remove from favorite"/>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongPlayData" Field="@nameof(SongPlayData.Title)" Title="Song Title"/>
|
||||
<Column T="SongPlayData" Field="@nameof(SongPlayData.Artist)" Title="Artist"/>
|
||||
<Column T="SongPlayData" Field="@nameof(SongPlayData.TotalPlayCount)" Title="Total Play Count"/>
|
||||
<Column T="SongPlayData" Field="@nameof(SongPlayData.LastPlayTime)" Title="Last Play Time"/>
|
||||
</Columns>
|
||||
<ChildRowContent>
|
||||
@if (context.Item.ShowDetails)
|
||||
{
|
||||
<MudTr>
|
||||
<td colspan="5">
|
||||
<MudCard Elevation="0">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.body1">Song Play Details</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent Class="pa-0">
|
||||
<MudTable Items="@context.Item.SongPlaySubDataList"
|
||||
Context="SongPlayDetail"
|
||||
Elevation="0"
|
||||
Filter="data => data.ClearState != ClearState.NotPlayed">
|
||||
<HeaderContent>
|
||||
<MudTh>Difficulty</MudTh>
|
||||
<MudTh>Clear State</MudTh>
|
||||
<MudTh>Play Count</MudTh>
|
||||
<MudTh>Rating</MudTh>
|
||||
<MudTh>Score</MudTh>
|
||||
<MudTh>Max Chain</MudTh>
|
||||
<MudTh>Last Play Time</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Difficulty">@SongPlayDetail.Difficulty</MudTd>
|
||||
<MudTd DataLabel="Clear State">
|
||||
@(SongPlayDetail.Score != 1000000 ? SongPlayDetail.ClearState : ClearState.Perfect)
|
||||
</MudTd>
|
||||
<MudTd DataLabel="Play Count">@SongPlayDetail.PlayCount</MudTd>
|
||||
<MudTd DataLabel="Rating">@CalculateRating(SongPlayDetail.Score)</MudTd>
|
||||
<MudTd DataLabel="Score">@SongPlayDetail.Score</MudTd>
|
||||
<MudTd DataLabel="Max Chain">@SongPlayDetail.MaxChain</MudTd>
|
||||
<MudTd DataLabel="Last Play Time">@SongPlayDetail.LastPlayTime</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</td>
|
||||
</MudTr>
|
||||
}
|
||||
</ChildRowContent>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="SongPlayData"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
</MudExpansionPanel>
|
||||
</MudExpansionPanels>
|
||||
}
|
||||
}
|
||||
</MudContainer>
|
@ -1,228 +0,0 @@
|
||||
using System.Net.Http.Json;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using ProtoBuf;
|
||||
using SharedProject.common;
|
||||
using SharedProject.models;
|
||||
|
||||
namespace MudAdmin.Pages;
|
||||
|
||||
public partial class User
|
||||
{
|
||||
[Inject]
|
||||
public HttpClient Client { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public IDialogService DialogService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
public ILogger<User> Logger { get; set; } = null!;
|
||||
|
||||
private Dictionary<long, Avatar> avatarDictionary = new();
|
||||
|
||||
private bool isSavingOptions;
|
||||
|
||||
private Dictionary<long, Navigator> navigatorDictionary = new();
|
||||
|
||||
private bool pageLoading = true;
|
||||
|
||||
private PlayOption playOption = new();
|
||||
|
||||
private List<SongPlayData> songPlayDataList = new();
|
||||
|
||||
private Dictionary<long, Title> titleDictionary = new();
|
||||
|
||||
private UserDetail? userDetail;
|
||||
|
||||
[Parameter]
|
||||
public long CardId { get; set; }
|
||||
|
||||
private bool IsTitleOverlayVisible { get; set; }
|
||||
|
||||
private bool IsNavigatorOverlayVisible { get; set; }
|
||||
|
||||
private bool IsAvatarOverlayVisible { get; set; }
|
||||
|
||||
private Title? SelectedTitle { get; set; }
|
||||
|
||||
private Avatar? SelectedAvatar { get; set; }
|
||||
|
||||
private Navigator? SelectedNavigator { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
userDetail = await Client.GetFromJsonAsync<UserDetail>($"api/UserDetail/{CardId}");
|
||||
if (userDetail is null)
|
||||
{
|
||||
pageLoading = false;
|
||||
return;
|
||||
}
|
||||
songPlayDataList = userDetail.SongPlayDataList ?? new List<SongPlayData>();
|
||||
playOption = userDetail.PlayOption;
|
||||
|
||||
var navigatorStream = await Client.GetStreamAsync(SharedConstants.NAVIGATOR_DAT_URI);
|
||||
var navigators = Serializer.Deserialize<Navigators>(navigatorStream);
|
||||
if (navigators?.NavigatorList != null)
|
||||
{
|
||||
navigatorDictionary = navigators.NavigatorList.ToDictionary(navigator => (long)navigator.Id);
|
||||
}
|
||||
|
||||
var avatarStream = await Client.GetStreamAsync(SharedConstants.AVATAR_DAT_URI);
|
||||
var avatars = Serializer.Deserialize<List<Avatar>>(avatarStream);
|
||||
if (avatars != null)
|
||||
{
|
||||
avatarDictionary = avatars.ToDictionary(avatar => (long)avatar.Id);
|
||||
}
|
||||
|
||||
var titleStream = await Client.GetStreamAsync(SharedConstants.TITLE_DAT_URI);
|
||||
var titles = Serializer.Deserialize<List<Title>>(titleStream);
|
||||
if (titles != null)
|
||||
{
|
||||
titleDictionary = titles.ToDictionary(title => (long)title.Id);
|
||||
}
|
||||
|
||||
SetSelected();
|
||||
pageLoading = false;
|
||||
}
|
||||
|
||||
private void SetSelected()
|
||||
{
|
||||
SelectedTitle = titleDictionary.GetValueOrDefault(playOption.TitleId);
|
||||
SelectedAvatar = avatarDictionary.GetValueOrDefault(playOption.AvatarId);
|
||||
SelectedNavigator = navigatorDictionary.GetValueOrDefault(playOption.NavigatorId);
|
||||
}
|
||||
|
||||
private void OnShowDetailsClick(SongPlayData data)
|
||||
{
|
||||
data.ShowDetails = !data.ShowDetails;
|
||||
}
|
||||
|
||||
private async Task SaveOptions()
|
||||
{
|
||||
isSavingOptions = true;
|
||||
var postData = new PlayOption
|
||||
{
|
||||
CardId = CardId,
|
||||
FastSlowIndicator = playOption.FastSlowIndicator,
|
||||
FeverTrance = playOption.FeverTrance,
|
||||
AvatarId = playOption.AvatarId,
|
||||
NavigatorId = playOption.NavigatorId,
|
||||
TitleId = playOption.TitleId
|
||||
};
|
||||
var result = await Client.PostAsJsonAsync("api/UserDetail/SetPlayOption", postData);
|
||||
isSavingOptions = false;
|
||||
}
|
||||
|
||||
private static string CalculateRating(int score)
|
||||
{
|
||||
var grade = SharedConstants.Grades.Where(g => g.Score <= score).Select(g => g.Grade).Last();
|
||||
return grade;
|
||||
}
|
||||
|
||||
private async Task OnFavoriteToggled(SongPlayData data)
|
||||
{
|
||||
var options = new DialogOptions
|
||||
{
|
||||
CloseOnEscapeKey = false,
|
||||
DisableBackdropClick = true,
|
||||
FullWidth = true
|
||||
};
|
||||
var parameters = new DialogParameters();
|
||||
parameters.Add("Data", data);
|
||||
parameters.Add("CardId", CardId);
|
||||
var dialog = DialogService.Show<FavoriteDialog>("Favorite", parameters, options);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result.Cancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bool)result.Data)
|
||||
{
|
||||
Logger.LogInformation("Changed!");
|
||||
data.IsFavorite = !data.IsFavorite;
|
||||
}
|
||||
}
|
||||
|
||||
private Task<IEnumerable<long>> SearchAvatar(string value)
|
||||
{
|
||||
var result = string.IsNullOrEmpty(value) ? avatarDictionary.Keys : avatarDictionary.Where(pair => pair.Value.ToString().Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(pair => pair.Key);
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private Task<IEnumerable<long>> SearchTitle(string value)
|
||||
{
|
||||
var result = string.IsNullOrEmpty(value) ? titleDictionary.Keys : titleDictionary.Where(pair => pair.Value.ToString().Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(pair => pair.Key);
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private Task<IEnumerable<long>> SearchNavigator(string value)
|
||||
{
|
||||
var result = string.IsNullOrEmpty(value) ? navigatorDictionary.Keys : navigatorDictionary.Where(pair => pair.Value.ToString().Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(pair => pair.Key);
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private string AvatarIdToString(long id)
|
||||
{
|
||||
return avatarDictionary.ContainsKey(id) ? avatarDictionary[id].ToString() : $"No Data for {id}!";
|
||||
}
|
||||
|
||||
private string NavigatorIdToString(long id)
|
||||
{
|
||||
return navigatorDictionary.ContainsKey(id) ? navigatorDictionary[id].ToString() : $"No Data for {id}!";
|
||||
}
|
||||
|
||||
private string TitleIdToString(long id)
|
||||
{
|
||||
return titleDictionary.ContainsKey(id) ? titleDictionary[id].ToString() : $"No Data for {id}!";
|
||||
}
|
||||
|
||||
private void OnChangeTitleButtonClick()
|
||||
{
|
||||
IsTitleOverlayVisible = true;
|
||||
}
|
||||
|
||||
private void OnChangeNavigatorButtonClick()
|
||||
{
|
||||
IsNavigatorOverlayVisible = true;
|
||||
}
|
||||
|
||||
private void OnChangeAvatarButtonClick()
|
||||
{
|
||||
IsAvatarOverlayVisible = true;
|
||||
}
|
||||
|
||||
private void OnTitleOverlayClosed()
|
||||
{
|
||||
IsTitleOverlayVisible = false;
|
||||
if (SelectedTitle != null)
|
||||
{
|
||||
playOption.TitleId = SelectedTitle.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavigatorOverlayClosed()
|
||||
{
|
||||
IsNavigatorOverlayVisible = false;
|
||||
if (SelectedNavigator != null)
|
||||
{
|
||||
playOption.NavigatorId = SelectedNavigator.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAvatarOverlayClosed()
|
||||
{
|
||||
IsAvatarOverlayVisible = false;
|
||||
if (SelectedAvatar != null)
|
||||
{
|
||||
playOption.AvatarId = SelectedAvatar.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private static object NameEntrySortByFunc(Navigator navigator)
|
||||
{
|
||||
return navigator.NameEntry1?.ToString().ToLowerInvariant() ?? string.Empty;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
@page "/users"
|
||||
@using models = SharedProject.models
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject HttpClient Client
|
||||
@inject IDialogService DialogService
|
||||
@inject ILogger<Users> Logger
|
||||
|
||||
<PageTitle>Users</PageTitle>
|
||||
|
||||
<MudContainer>
|
||||
@if (users is null)
|
||||
{
|
||||
<MudGrid>
|
||||
@for (var i = 0; i < 5; i++)
|
||||
{
|
||||
<MudItem>
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudSkeleton SkeletonType="SkeletonType.Rectangle" Height="32px"/>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudSkeleton Width="80px" Height="32px"/>
|
||||
<MudSkeleton Width="147px" Height="28px"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudSkeleton SkeletonType="SkeletonType.Rectangle" Width="99px" Height="25px" Class="ml-2"/>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
else if (users.Count != 0)
|
||||
{
|
||||
<MudGrid>
|
||||
@foreach (var user in users)
|
||||
{
|
||||
<MudItem>
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h5">@user.PlayerName</MudText>
|
||||
</CardHeaderContent>
|
||||
<CardHeaderActions>
|
||||
<MudIconButton Icon="@Icons.Filled.Edit" Color="Color.Default"
|
||||
OnClick="() => OnEditPlayerNameClicked(user)"/>
|
||||
</CardHeaderActions>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.h6">Card ID</MudText>
|
||||
<MudText>@user.CardId</MudText>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="() => OnCheckDetailClick(user)">Check detail</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.h3">No Data</MudText>
|
||||
}
|
||||
</MudContainer>
|
||||
|
||||
@code {
|
||||
private List<models.User>? users;
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
users = await Client.GetFromJsonAsync<List<models.User>>("api/Users") ?? new List<models.User>();
|
||||
}
|
||||
|
||||
private void OnCheckDetailClick(models.User user)
|
||||
{
|
||||
NavigationManager.NavigateTo($"user/{user.CardId}");
|
||||
}
|
||||
|
||||
private async Task OnEditPlayerNameClicked(models.User user)
|
||||
{
|
||||
var options = new DialogOptions
|
||||
{
|
||||
CloseOnEscapeKey = false,
|
||||
DisableBackdropClick = true,
|
||||
FullWidth = true
|
||||
};
|
||||
var parameters = new DialogParameters();
|
||||
parameters.Add("Data", user);
|
||||
var dialog = DialogService.Show<ChangePlayerNameDialog>("Favorite", parameters, options);
|
||||
var result = await dialog.Result;
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using MudAdmin;
|
||||
using MudBlazor.Services;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
builder.Services.AddScoped(sp => new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseUrl"))
|
||||
});
|
||||
builder.Services.AddMudServices();
|
||||
|
||||
await builder.Build().RunAsync();
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:65283",
|
||||
"sslPort": 44398
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Mudblazor.Template": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<MudThemeProvider @ref="@MudThemeProvider" @bind-IsDarkMode="@IsDarkMode"/>
|
||||
<MudDialogProvider/>
|
||||
<MudSnackbarProvider/>
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="0" Dense="true">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start"
|
||||
OnClick="@((e) => DrawerToggle())"/>
|
||||
<MudSpacer/>
|
||||
<MudTooltip Duration="1000" Text="Powered by MudBlazor">
|
||||
<MudIconButton Icon="@Icons.Custom.Brands.MudBlazor" Color="Color.Inherit"
|
||||
Link="https://mudblazor.com/" Target="_blank"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Duration="1000" Text="Github Repository">
|
||||
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit"
|
||||
Link="https://github.com/asesidaa/GC-local-server-rewrite/" Target="_blank"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Duration="1000" Text="@(IsDarkMode ? "Switch to Light Mode" : "Switch to DarkMode")">
|
||||
<MudToggleIconButton @bind-Toggled="@IsDarkMode"
|
||||
Icon="@Icons.Material.Outlined.DarkMode" Color="Color.Inherit"
|
||||
ToggledIcon="@Icons.Material.Filled.LightMode"/>
|
||||
</MudTooltip>
|
||||
</MudAppBar>
|
||||
<MudDrawer @bind-Open="drawerOpen" Elevation="1">
|
||||
<MudDrawerHeader>
|
||||
<MudText Typo="Typo.h6">GC local server Admin</MudText>
|
||||
</MudDrawerHeader>
|
||||
<NavMenu/>
|
||||
</MudDrawer>
|
||||
<MudMainContent>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="my-16 pt-16">
|
||||
@Body
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
|
||||
@code {
|
||||
bool drawerOpen = true;
|
||||
|
||||
public bool IsDarkMode { get; set; }
|
||||
|
||||
public MudThemeProvider MudThemeProvider { get; set; } = null!;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
IsDarkMode = await MudThemeProvider.GetSystemPreference();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawerToggle()
|
||||
{
|
||||
drawerOpen = !drawerOpen;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
|
||||
<MudNavLink Href="Cards" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Cards</MudNavLink>
|
||||
</MudNavMenu>
|
@ -1,11 +0,0 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||
@using Microsoft.JSInterop
|
||||
@using MudBlazor
|
||||
@using MudAdmin
|
||||
@using MudAdmin.Shared
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"BaseUrl": "https://127.0.0.1"
|
||||
}
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>MudAdmin</title>
|
||||
<base href="/" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">Loading...</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 818 B |
@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>SharedProject</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="protobuf-net" Version="3.1.22" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,9 +0,0 @@
|
||||
namespace SharedProject.common;
|
||||
|
||||
public record ScoreGradeMap(int Score, string Grade)
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{{ Score = {Score}, Grade = {Grade} }}";
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
namespace SharedProject.common;
|
||||
|
||||
public static class SharedConstants
|
||||
{
|
||||
public const int DIFFICULTY_COUNT = 4;
|
||||
|
||||
public const int E_SCORE_THRESHOLD = 0;
|
||||
|
||||
public const int D_SCORE_THRESHOLD = 300000;
|
||||
|
||||
public const int C_SCORE_THRESHOLD = 500000;
|
||||
|
||||
public const int B_SCORE_THRESHOLD = 700000;
|
||||
|
||||
public const int A_SCORE_THRESHOLD = 800000;
|
||||
|
||||
public const int S_SCORE_THRESHOLD = 900000;
|
||||
|
||||
public const int S_PLUS_SCORE_THRESHOLD = 950000;
|
||||
|
||||
public const int S_PLUS_PLUS_SCORE_THRESHOLD = 990000;
|
||||
|
||||
public const int MAX_PLAYER_NAME_LENGTH = 8;
|
||||
|
||||
public const string NAVIGATOR_DAT_URI = "data/navigator.dat";
|
||||
|
||||
public const string AVATAR_DAT_URI = "data/avatar.dat";
|
||||
|
||||
public const string TITLE_DAT_URI = "data/title.dat";
|
||||
|
||||
public static readonly ScoreGradeMap[] Grades =
|
||||
{
|
||||
new(E_SCORE_THRESHOLD, "E"),
|
||||
new(D_SCORE_THRESHOLD, "D"),
|
||||
new(C_SCORE_THRESHOLD, "C"),
|
||||
new(B_SCORE_THRESHOLD, "B"),
|
||||
new(A_SCORE_THRESHOLD, "A"),
|
||||
new(S_SCORE_THRESHOLD, "S"),
|
||||
new(S_PLUS_SCORE_THRESHOLD, "S+"),
|
||||
new(S_PLUS_PLUS_SCORE_THRESHOLD, "S++")
|
||||
};
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace SharedProject.enums;
|
||||
|
||||
public enum ClearState
|
||||
{
|
||||
NotPlayed = 0,
|
||||
Failed,
|
||||
Clear,
|
||||
NoMiss,
|
||||
FullChain,
|
||||
Perfect
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace SharedProject.enums;
|
||||
|
||||
public enum Difficulty
|
||||
{
|
||||
Simple = 0,
|
||||
Normal = 1,
|
||||
Hard = 2,
|
||||
Extra = 3
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
namespace SharedProject.enums;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string GetHelpText(this PlayOptions.FastSlowIndicator indicator)
|
||||
{
|
||||
return indicator switch
|
||||
{
|
||||
PlayOptions.FastSlowIndicator.NotUsed => "Do not show FAST/SLOW indicator",
|
||||
PlayOptions.FastSlowIndicator.NearAvatar => "Show FAST/SLOW indicator near avatar",
|
||||
PlayOptions.FastSlowIndicator.NearJudgement => "Show FAST/SLOW indicator near judgement text",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(indicator), indicator, null)
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetHelpText(this PlayOptions.FeverTranceShow show)
|
||||
{
|
||||
return show switch
|
||||
{
|
||||
PlayOptions.FeverTranceShow.NotUsed => "Do not show FEVER/TRANCE",
|
||||
PlayOptions.FeverTranceShow.Show => "Show FEVER/TRANCE",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(show), show, null)
|
||||
};
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using ProtoBuf;
|
||||
|
||||
namespace SharedProject.enums;
|
||||
|
||||
[ProtoContract]
|
||||
public enum NavigatorDefaultAvailability
|
||||
{
|
||||
NotAvailable = 0,
|
||||
Available = 1,
|
||||
AvailableWithVoice = 2,
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using ProtoBuf;
|
||||
|
||||
namespace SharedProject.enums;
|
||||
|
||||
[ProtoContract]
|
||||
public enum NavigatorGenre
|
||||
{
|
||||
Default = 1,
|
||||
Original = 2,
|
||||
Game = 3,
|
||||
Touhou = 4,
|
||||
Vocaloid = 5,
|
||||
Collab = 6,
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
namespace SharedProject.enums;
|
||||
|
||||
public static class PlayOptions
|
||||
{
|
||||
public enum FastSlowIndicator
|
||||
{
|
||||
NotUsed = 3,
|
||||
NearAvatar = 1,
|
||||
NearJudgement = 2
|
||||
}
|
||||
|
||||
public enum FeverTranceShow
|
||||
{
|
||||
NotUsed = 2,
|
||||
Show = 1
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using ProtoBuf;
|
||||
|
||||
namespace SharedProject.enums;
|
||||
|
||||
[ProtoContract]
|
||||
public enum TitleUnlockType
|
||||
{
|
||||
Invalid = 0,
|
||||
Default = 1,
|
||||
Clear = 2,
|
||||
NoMiss = 3,
|
||||
FullChain = 4,
|
||||
SRankSimpleStages = 5,
|
||||
SRankNormalStages = 6,
|
||||
SRankHardStages = 7,
|
||||
SRankExtraStages = 8,
|
||||
SRankAllDifficulties = 9,
|
||||
SPlusRankAllDifficulties = 10,
|
||||
SPlusPlusRankAllDifficulties = 11,
|
||||
Event = 12,
|
||||
Prefecture = 13,
|
||||
ChainMilestone = 14,
|
||||
Adlibs = 15,
|
||||
ConsecutiveNoMiss = 16,
|
||||
ClearsUsingItems = 17,
|
||||
Avatars = 18,
|
||||
MultiplayerStarsTotal = 19,
|
||||
SongSet20 = 20,
|
||||
SongSet21 = 21,
|
||||
SongSet22 = 22,
|
||||
SongSet23 = 23,
|
||||
SongSet24 = 24,
|
||||
SongSet25 = 25,
|
||||
SongSet26 = 26,
|
||||
ProfileLevel = 27,
|
||||
Perfect = 28,
|
||||
OnlineMatching = 29,
|
||||
Trophies = 30,
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using ProtoBuf;
|
||||
|
||||
namespace SharedProject.models;
|
||||
|
||||
[ProtoContract]
|
||||
public class Avatar
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[ProtoMember(2)]
|
||||
public string? IdString { get; set; }
|
||||
|
||||
[ProtoMember(3)]
|
||||
public string? FullName { get; set; }
|
||||
|
||||
[ProtoMember(4)]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[ProtoMember(5)]
|
||||
public string? Variant { get; set; }
|
||||
|
||||
[ProtoMember(6)]
|
||||
public string? AcquireMethodJp { get; set; }
|
||||
|
||||
[ProtoMember(7)]
|
||||
public string? AcquireMethodEn { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return $"{Id}: {FullName}, {AcquireMethodEn}";
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharedProject.models;
|
||||
|
||||
public class MusicFavoriteData
|
||||
{
|
||||
[JsonPropertyName(nameof(CardId))]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[JsonPropertyName(nameof(MusicId))]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[JsonPropertyName(nameof(IsFavorite))]
|
||||
public bool IsFavorite { get; set; }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user