commit
799eb85031
3
.gitignore
vendored
3
.gitignore
vendored
@ -395,4 +395,5 @@ FodyWeavers.xsd
|
|||||||
*.msp
|
*.msp
|
||||||
|
|
||||||
# JetBrains Rider
|
# JetBrains Rider
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
|
TaikoLocalServer/wwwroot/data/music_attribute.bin
|
||||||
|
95
OldSetup.md
Normal file
95
OldSetup.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Old setup
|
||||||
|
|
||||||
|
1. Download the latest release of [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader) and install it. Make sure to setup TAL using the config.toml and set the `server` parameter to your local IP address.
|
||||||
|
2. Download the latest release of [TaikoReverseProxy](https://github.com/shiibe/TaikoReverseProxy).
|
||||||
|
3. In the `Data\x64\datatable` folder of the game, find the following files:
|
||||||
|
|
||||||
|
```
|
||||||
|
music_attribute.bin
|
||||||
|
musicinfo.bin
|
||||||
|
music_order.bin
|
||||||
|
wordlist.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Extract them (you can use [7zip](https://www.7-zip.org)) and rename the extracted file like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
music_attribute -> music_attribute.json
|
||||||
|
musicinfo -> musicinfo.json
|
||||||
|
music_order -> music_order.json
|
||||||
|
wordlist -> wordlist.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Then put these in TaikoLocalServer's `wwwroot/data` folder.
|
||||||
|
|
||||||
|
4. Modify hosts, add the following entries (this step can be done automatically with TaikoReverseProxy, check the config for it):
|
||||||
|
|
||||||
|
```
|
||||||
|
server.ip tenporouter.loc
|
||||||
|
server.ip naominet.jp
|
||||||
|
server.ip v402-front.mucha-prd.nbgi-amnet.jp
|
||||||
|
server.ip vsapi.taiko-p.jp
|
||||||
|
```
|
||||||
|
|
||||||
|
where `server.ip` is your computer's ip (or the server's ip)
|
||||||
|
|
||||||
|
5. Open command prompt as admin, navigate to game root folder (where init.ps1 is). Run `regsvr32 .\AMCUS\iauthdll.dll`. It should prompt about success
|
||||||
|
|
||||||
|
6. Run TaikoReverseProxy and TaikoLocalServer, then run the game. You can access the WebUI by going to `https://naominet.jp:10122/` in your browser.
|
||||||
|
|
||||||
|
|
||||||
|
### Server setup (for TAL<2.00 or other loaders)
|
||||||
|
|
||||||
|
1. Download the server from release page, extract anywhere
|
||||||
|
|
||||||
|
2. From game's `Data\x64\datatable` folder, find `music_attribute.bin`, `musicinfo.bin`, `music_order.bin` and `wordlist.bin`, decompress them, add `.json` prefix to them.
|
||||||
|
The result is `music_attribute.json`, `musicinfo.json`, `music_order.json` and `wordlist.json`. Put the json files under` wwwroot/data` folder in server.
|
||||||
|
|
||||||
|
3. Modify hosts, add the following entries:
|
||||||
|
|
||||||
|
```
|
||||||
|
server.ip tenporouter.loc
|
||||||
|
server.ip naominet.jp
|
||||||
|
server.ip v402-front.mucha-prd.nbgi-amnet.jp
|
||||||
|
server.ip vsapi.taiko-p.jp
|
||||||
|
```
|
||||||
|
|
||||||
|
where `server.ip` is your computers ip (or the server's ip)
|
||||||
|
|
||||||
|
4. Setup [TaikoReverseProxy](https://github.com/shiibe/TaikoReverseProxy) or [Apache](#apache-setup-optional) as reverse proxy.
|
||||||
|
|
||||||
|
5. Now run the server, if everything is setup correctly, visit http://localhost:5000, you should be able to see the web ui up and running without errors. (If you encounter errors in web ui for the first time, try visit https://naominet.jp:10122/)
|
||||||
|
|
||||||
|
6. Go to game folder, copy the config files (AMConfig.ini and WritableConfig.ini) in the AMCUS folder from server release to AMCUS folder and replace the original ones.
|
||||||
|
|
||||||
|
7. Open command prompt as admin, navigate to game root folder (where init.ps1 is). Run `regsvr32 .\AMCUS\iauthdll.dll`. It should prompt about success.
|
||||||
|
|
||||||
|
8. Run AMCUS/AMAuthd.exe, then run AMCUS/AMUpdater.exe. If the updater run and exits without issue, you are ready to run the game and connect to server.
|
||||||
|
|
||||||
|
9. Run the game, it should now connect to the server.
|
||||||
|
|
||||||
|
### Run the server on another computer
|
||||||
|
|
||||||
|
If you want to run the server on another computer, the procedure is almost identical.
|
||||||
|
|
||||||
|
Before you open browser, in `wwwroot/appsettings.json`, change `BaseUrl` to `https://naominet.jp:10122` then instead of visit localhost, visit the server using domain name to test.
|
||||||
|
|
||||||
|
Also note that now the cetificate also need to be imported on client computer, or web ui may not work. If you don't need https, change `BaseUrl` to `http://server.ip:80`, and visit on client. The game does not care about certificate.
|
||||||
|
|
||||||
|
### Apache Setup (Optional)
|
||||||
|
Notice the following assumes a windows install, the server also works on Linux, but the guide only covers windows.
|
||||||
|
|
||||||
|
1. Download [Apache](https://www.apachelounge.com/download/), extract anywhere
|
||||||
|
|
||||||
|
2. Copy the content in release rar's Apache folder to installed Apache root folder (and replace, which includes httpd.conf and httpd-vhosts.conf, if no prompt to replace files, you are extracting to wrong folder)
|
||||||
|
|
||||||
|
3. Open `conf/httpd.conf` (under installed Apache folder), find this line (line 37 by default), modify it to your Apache install (extracted) full path
|
||||||
|
|
||||||
|
```htaccess
|
||||||
|
# For example, if your Apache is extracted to C:\users\username\Apache24, then this should be "c:/users/username/Apache24"
|
||||||
|
Define SRVROOT "d:/Projects/Apache24"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Open the certs folder Apache root folder, then click on the localhost.crt file and import it to trusted root store.
|
||||||
|
|
||||||
|
If everything is correct, run bin/httpd.exe, a command prompt will open (and stay open, if it shut down, probably something is not setup correctly)
|
106
README.md
106
README.md
@ -8,106 +8,38 @@ This is a server for Taiko no Tatsujin Nijiiro ver 08.18
|
|||||||
|
|
||||||
- A working game, with dongle and card reader emulation. You can use [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader) for these if you haven't.
|
- A working game, with dongle and card reader emulation. You can use [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader) for these if you haven't.
|
||||||
|
|
||||||
### Tools
|
|
||||||
|
|
||||||
- [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader): A loader for the game with hardware emulation and other fixes.
|
|
||||||
- [TaikoReverseProxy](https://github.com/shiibe/TaikoReverseProxy): A no-setup bundled proxy server, use as a user-friendly alternative to Apache.
|
|
||||||
|
|
||||||
### Quick Setup
|
### Quick Setup
|
||||||
|
|
||||||
With the newest release (>=2.00) of TaikoArcadeLoader, you no longer need to run AMAuthd or AMUpdater.
|
With the newest release (from [this](https://github.com/BroGamer4256/TaikoArcadeLoader/tree/95d633850d89cb7099e98ffe74cd23632fe26e56) commit) of TaikoArcadeLoader, you no longer need to run AMAuthd, AMUpdater or reverse proxy.
|
||||||
|
|
||||||
1. Download the latest release of [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader) and install it. Make sure to setup TAL using the config.toml and set the `server` parameter to your local IP address.
|
1. Extract the server release anywhere
|
||||||
2. Download the latest release of [TaikoReverseProxy](https://github.com/shiibe/TaikoReverseProxy).
|
|
||||||
3. In the `Data\x64\datatable` folder of the game, find the following files:
|
|
||||||
|
|
||||||
```
|
2. From the game files, copy `music_attribute.bin`, `music_order.bin`, `musicinfo.bin` and `wordlist.bin` to `wwwroot/data` folder.
|
||||||
music_attribute.bin
|
|
||||||
musicinfo.bin
|
|
||||||
music_order.bin
|
|
||||||
wordlist.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
Extract them (you can use [7zip](https://www.7-zip.org)) and rename the extracted file like so:
|
3. (Optional) Instead of direct copy, extract the specified game files (using 7zip), rename them by adding the file extension `.json` and copy the jsons over.
|
||||||
|
|
||||||
```
|
4. (Optional) In `Certificates` folder, import `root.pfx` to trusted root store, `cert.pfx` to personal store. All the other import options can be kept default.
|
||||||
music_attribute -> music_attribute.json
|
|
||||||
musicinfo -> musicinfo.json
|
|
||||||
music_order -> music_order.json
|
|
||||||
wordlist -> wordlist.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Then put these in TaikoLocalServer's `wwwroot/data` folder.
|
5. Visit http://localhost:5000 and (Optional, only if you have done step 4) https://localhost:10122, if the web ui starts without errors, the config is fine.
|
||||||
|
|
||||||
|
|
||||||
4. Modify hosts, add the following entries (this step can be done automatically with TaikoReverseProxy, check the config for it):
|
6. Modify comfig.toml from TAL, edit the following line:
|
||||||
|
|
||||||
```
|
```toml
|
||||||
server.ip tenporouter.loc
|
server = "https://divamodarchive.com" # Change https://divamodarchive.com to your/server's ip, like 192.168.1.100
|
||||||
server.ip naominet.jp
|
|
||||||
server.ip v402-front.mucha-prd.nbgi-amnet.jp
|
|
||||||
server.ip vsapi.taiko-p.jp
|
|
||||||
```
|
```
|
||||||
|
|
||||||
where `server.ip` is your computer's ip (or the server's ip)
|
7. Now the game should be able to connect.
|
||||||
|
|
||||||
5. Open command prompt as admin, navigate to game root folder (where init.ps1 is). Run `regsvr32 .\AMCUS\iauthdll.dll`. It should prompt about success
|
### About certificates
|
||||||
|
|
||||||
6. Run TaikoReverseProxy and TaikoLocalServer, then run the game. You can access the WebUI by going to `https://naominet.jp:10122/` in your browser.
|
If you want to change the certificate used by server, just replace `cert.pfx` in `Certificates` folder. The bundled certificate includes the following DNS names:
|
||||||
|
|
||||||
|
```
|
||||||
### Server setup (for TAL<2.00 or other loaders)
|
DNS Name=nbgi-amnet.jp
|
||||||
|
DNS Name=v402-front.mucha-prd.nbgi-amnet.jp
|
||||||
1. Download the server from release page, extract anywhere
|
DNS Name=*.mucha-prd.nbgi-amnet.jp
|
||||||
|
DNS Name=localhost
|
||||||
2. From game's `Data\x64\datatable` folder, find `music_attribute.bin`, `musicinfo.bin`, `music_order.bin` and `wordlist.bin`, decompress them, add `.json` prefix to them.
|
DNS Name=vsapi.taiko-p.jp
|
||||||
The result is `music_attribute.json`, `musicinfo.json`, `music_order.json` and `wordlist.json`. Put the json files under` wwwroot/data` folder in server.
|
|
||||||
|
|
||||||
3. Modify hosts, add the following entries:
|
|
||||||
|
|
||||||
```
|
|
||||||
server.ip tenporouter.loc
|
|
||||||
server.ip naominet.jp
|
|
||||||
server.ip v402-front.mucha-prd.nbgi-amnet.jp
|
|
||||||
server.ip vsapi.taiko-p.jp
|
|
||||||
```
|
|
||||||
|
|
||||||
where `server.ip` is your computers ip (or the server's ip)
|
|
||||||
|
|
||||||
4. Setup [TaikoReverseProxy](https://github.com/shiibe/TaikoReverseProxy) or [Apache](#apache-setup-optional) as reverse proxy.
|
|
||||||
|
|
||||||
5. Now run the server, if everything is setup correctly, visit http://localhost:5000, you should be able to see the web ui up and running without errors. (If you encounter errors in web ui for the first time, try visit https://naominet.jp:10122/)
|
|
||||||
|
|
||||||
6. Go to game folder, copy the config files (AMConfig.ini and WritableConfig.ini) in the AMCUS folder from server release to AMCUS folder and replace the original ones.
|
|
||||||
|
|
||||||
7. Open command prompt as admin, navigate to game root folder (where init.ps1 is). Run `regsvr32 .\AMCUS\iauthdll.dll`. It should prompt about success.
|
|
||||||
|
|
||||||
8. Run AMCUS/AMAuthd.exe, then run AMCUS/AMUpdater.exe. If the updater run and exits without issue, you are ready to run the game and connect to server.
|
|
||||||
|
|
||||||
9. Run the game, it should now connect to the server.
|
|
||||||
|
|
||||||
### Run the server on another computer
|
|
||||||
|
|
||||||
If you want to run the server on another computer, the procedure is almost identical.
|
|
||||||
|
|
||||||
Before you open browser, in `wwwroot/appsettings.json`, change `BaseUrl` to `https://naominet.jp:10122` then instead of visit localhost, visit the server using domain name to test.
|
|
||||||
|
|
||||||
Also note that now the cetificate also need to be imported on client computer, or web ui may not work. If you don't need https, change `BaseUrl` to `http://server.ip:80`, and visit on client. The game does not care about certificate.
|
|
||||||
|
|
||||||
### Apache Setup (Optional)
|
|
||||||
Notice the following assumes a windows install, the server also works on Linux, but the guide only covers windows.
|
|
||||||
|
|
||||||
1. Download [Apache](https://www.apachelounge.com/download/), extract anywhere
|
|
||||||
|
|
||||||
2. Copy the content in release rar's Apache folder to installed Apache root folder (and replace, which includes httpd.conf and httpd-vhosts.conf, if no prompt to replace files, you are extracting to wrong folder)
|
|
||||||
|
|
||||||
3. Open `conf/httpd.conf` (under installed Apache folder), find this line (line 37 by default), modify it to your Apache install (extracted) full path
|
|
||||||
|
|
||||||
```htaccess
|
|
||||||
# For example, if your Apache is extracted to C:\users\username\Apache24, then this should be "c:/users/username/Apache24"
|
|
||||||
Define SRVROOT "d:/Projects/Apache24"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Open the certs folder Apache root folder, then click on the localhost.crt file and import it to trusted root store.
|
You will need to modify hosts file to use them.
|
||||||
|
|
||||||
If everything is correct, run bin/httpd.exe, a command prompt will open (and stay open, if it shut down, probably something is not setup correctly)
|
|
||||||
|
@ -5,5 +5,5 @@ public enum PlayMode
|
|||||||
Normal = 0,
|
Normal = 0,
|
||||||
DanMode = 1,
|
DanMode = 1,
|
||||||
// Not sure about this
|
// Not sure about this
|
||||||
AiBattle = 2
|
AiBattle = 6
|
||||||
}
|
}
|
22
SharedProject/Models/AiSectionBestData.cs
Normal file
22
SharedProject/Models/AiSectionBestData.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using SharedProject.Enums;
|
||||||
|
|
||||||
|
namespace SharedProject.Models;
|
||||||
|
|
||||||
|
public class AiSectionBestData
|
||||||
|
{
|
||||||
|
public int SectionIndex { get; set; }
|
||||||
|
|
||||||
|
public CrownType Crown { get; set; }
|
||||||
|
|
||||||
|
public bool IsWin { get; set; }
|
||||||
|
|
||||||
|
public uint Score { get; set; }
|
||||||
|
|
||||||
|
public uint GoodCount { get; set; }
|
||||||
|
|
||||||
|
public uint OkCount { get; set; }
|
||||||
|
|
||||||
|
public uint MissCount { get; set; }
|
||||||
|
|
||||||
|
public uint DrumrollCount { get; set; }
|
||||||
|
}
|
@ -14,6 +14,11 @@ public class SongBestData
|
|||||||
|
|
||||||
public Difficulty Difficulty { get; set; }
|
public Difficulty Difficulty { get; set; }
|
||||||
|
|
||||||
|
public int PlayCount { get; set; }
|
||||||
|
public int ClearCount { get; set; }
|
||||||
|
public int FullComboCount { get; set; }
|
||||||
|
public int PerfectCount { get; set; }
|
||||||
|
|
||||||
public uint BestScore { get; set; }
|
public uint BestScore { get; set; }
|
||||||
|
|
||||||
public uint BestRate { get; set; }
|
public uint BestRate { get; set; }
|
||||||
@ -37,4 +42,8 @@ public class SongBestData
|
|||||||
public uint HitCount { get; set; }
|
public uint HitCount { get; set; }
|
||||||
|
|
||||||
public uint DrumrollCount { get; set; }
|
public uint DrumrollCount { get; set; }
|
||||||
|
|
||||||
|
public List<AiSectionBestData> AiSectionBestData { get; set; } = new();
|
||||||
|
|
||||||
|
public bool ShowAiData { get; set; }
|
||||||
}
|
}
|
14
SharedProject/Utils/ValueHelpers.cs
Normal file
14
SharedProject/Utils/ValueHelpers.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace SharedProject.Utils;
|
||||||
|
|
||||||
|
public static class ValueHelpers
|
||||||
|
{
|
||||||
|
public static T Min<T>(T a, T b) where T : IComparable
|
||||||
|
{
|
||||||
|
return Comparer<T>.Default.Compare(a, b) <= 0 ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Max<T>(T a, T b) where T : IComparable
|
||||||
|
{
|
||||||
|
return Comparer<T>.Default.Compare(a, b) >= 0 ? a : b;
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
BIN
TaikoLocalServer/Certificates/root.pfx
Normal file
BIN
TaikoLocalServer/Certificates/root.pfx
Normal file
Binary file not shown.
@ -4,21 +4,14 @@ public static class Constants
|
|||||||
{
|
{
|
||||||
public const string DATE_TIME_FORMAT = "yyyyMMddHHmmss";
|
public const string DATE_TIME_FORMAT = "yyyyMMddHHmmss";
|
||||||
|
|
||||||
public const int MUSIC_ID_MAX = 9000;
|
public const int MUSIC_ID_MAX = 1599;
|
||||||
|
|
||||||
public const int CROWN_FLAG_ARRAY_SIZE = MUSIC_ID_MAX + 1;
|
public const int MUSIC_ID_MAX_EXPANDED = 9000;
|
||||||
|
|
||||||
public const int DONDAFUL_CROWN_FLAG_ARRAY_SIZE = MUSIC_ID_MAX + 1;
|
|
||||||
|
|
||||||
public const int KIWAMI_SCORE_RANK_ARRAY_SIZE = MUSIC_ID_MAX + 1;
|
|
||||||
|
|
||||||
public const int IKI_CORE_RANK_ARRAY_SIZE = MUSIC_ID_MAX + 1;
|
|
||||||
|
|
||||||
public const int MIYABI_CORE_RANK_ARRAY_SIZE = MUSIC_ID_MAX + 1;
|
|
||||||
|
|
||||||
public const string DEFAULT_DB_NAME = "taiko.db3";
|
public const string DEFAULT_DB_NAME = "taiko.db3";
|
||||||
|
|
||||||
public const string MUSIC_ATTRIBUTE_FILE_NAME = "music_attribute.json";
|
public const string MUSIC_ATTRIBUTE_FILE_NAME = "music_attribute.json";
|
||||||
|
public const string MUSIC_ATTRIBUTE_COMPRESSED_FILE_NAME = "music_attribute.bin";
|
||||||
|
|
||||||
public const string DAN_DATA_FILE_NAME = "dan_data.json";
|
public const string DAN_DATA_FILE_NAME = "dan_data.json";
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ public static class FlagCalculator
|
|||||||
{
|
{
|
||||||
if (id >= bitArraySize)
|
if (id >= bitArraySize)
|
||||||
{
|
{
|
||||||
logger.LogWarning("Id out of range!");
|
logger.LogWarning("Id {Id} out of range!", id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bitSet.Set((int)id, true);
|
bitSet.Set((int)id, true);
|
||||||
|
@ -4,6 +4,8 @@ public partial class TaikoDbContext
|
|||||||
{
|
{
|
||||||
public virtual DbSet<DanScoreDatum> DanScoreData { get; set; } = null!;
|
public virtual DbSet<DanScoreDatum> DanScoreData { get; set; } = null!;
|
||||||
public virtual DbSet<DanStageScoreDatum> DanStageScoreData { get; set; } = null!;
|
public virtual DbSet<DanStageScoreDatum> DanStageScoreData { get; set; } = null!;
|
||||||
|
public virtual DbSet<AiScoreDatum> AiScoreData { get; set; } = null!;
|
||||||
|
public virtual DbSet<AiSectionScoreDatum> AiSectionScoreData { get; set; } = null!;
|
||||||
|
|
||||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
|
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@ -30,5 +32,28 @@ public partial class TaikoDbContext
|
|||||||
.HasForeignKey(d => new {d.Baid, d.DanId})
|
.HasForeignKey(d => new {d.Baid, d.DanId})
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<AiScoreDatum>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => new { e.Baid, e.SongId, e.Difficulty });
|
||||||
|
|
||||||
|
entity.HasOne(d => d.Ba)
|
||||||
|
.WithMany()
|
||||||
|
.HasPrincipalKey(p => p.Baid)
|
||||||
|
.HasForeignKey(d => d.Baid)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
modelBuilder.Entity<AiSectionScoreDatum>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => new { e.Baid, e.SongId, e.Difficulty, e.SectionIndex });
|
||||||
|
|
||||||
|
entity.HasOne(d => d.Parent)
|
||||||
|
.WithMany(p => p.AiSectionScoreData)
|
||||||
|
.HasPrincipalKey(p => new {p.Baid, p.SongId, p.Difficulty })
|
||||||
|
.HasForeignKey(d => new {d.Baid, d.SongId, d.Difficulty })
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,9 +7,9 @@ namespace TaikoLocalServer.Controllers.AmAuth;
|
|||||||
[Route("/sys/servlet/PowerOn")]
|
[Route("/sys/servlet/PowerOn")]
|
||||||
public class PowerOnController : BaseController<PowerOnController>
|
public class PowerOnController : BaseController<PowerOnController>
|
||||||
{
|
{
|
||||||
private readonly UrlSettings settings;
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
public PowerOnController(IOptions<UrlSettings> settings)
|
public PowerOnController(IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.settings = settings.Value;
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ namespace TaikoLocalServer.Controllers.AmUpdater;
|
|||||||
|
|
||||||
public class MuchaController : BaseController<MuchaController>
|
public class MuchaController : BaseController<MuchaController>
|
||||||
{
|
{
|
||||||
private readonly UrlSettings settings;
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
public MuchaController(IOptions<UrlSettings> settings)
|
public MuchaController(IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.settings = settings.Value;
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using SharedProject.Models;
|
using SharedProject.Models;
|
||||||
using SharedProject.Models.Responses;
|
using SharedProject.Models.Responses;
|
||||||
using Swan.Mapping;
|
using Swan.Mapping;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using SharedProject.Models;
|
using SharedProject.Models.Responses;
|
||||||
using SharedProject.Models.Responses;
|
|
||||||
using Swan.Mapping;
|
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using SharedProject.Models.Requests;
|
using SharedProject.Models.Requests;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using SharedProject.Models.Responses;
|
using System.Collections.Immutable;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
using SharedProject.Models.Responses;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
@ -11,10 +11,14 @@ public class PlayDataController : BaseController<PlayDataController>
|
|||||||
|
|
||||||
private readonly ISongBestDatumService songBestDatumService;
|
private readonly ISongBestDatumService songBestDatumService;
|
||||||
|
|
||||||
public PlayDataController(IUserDatumService userDatumService, ISongBestDatumService songBestDatumService)
|
private readonly ISongPlayDatumService songPlayDatumService;
|
||||||
|
|
||||||
|
public PlayDataController(IUserDatumService userDatumService, ISongBestDatumService songBestDatumService,
|
||||||
|
ISongPlayDatumService songPlayDatumService)
|
||||||
{
|
{
|
||||||
this.userDatumService = userDatumService;
|
this.userDatumService = userDatumService;
|
||||||
this.songBestDatumService = songBestDatumService;
|
this.songBestDatumService = songBestDatumService;
|
||||||
|
this.songPlayDatumService = songPlayDatumService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{baid}")]
|
[HttpGet("{baid}")]
|
||||||
@ -27,6 +31,16 @@ public class PlayDataController : BaseController<PlayDataController>
|
|||||||
}
|
}
|
||||||
|
|
||||||
var songBestRecords = await songBestDatumService.GetAllSongBestAsModel(baid);
|
var songBestRecords = await songBestDatumService.GetAllSongBestAsModel(baid);
|
||||||
|
var playLogs = await songPlayDatumService.GetSongPlayDatumByBaid(baid);
|
||||||
|
foreach (var songBestData in songBestRecords)
|
||||||
|
{
|
||||||
|
var songPlayLogs = playLogs.Where(datum => datum.SongId == songBestData.SongId &&
|
||||||
|
datum.Difficulty == songBestData.Difficulty).ToList();
|
||||||
|
songBestData.PlayCount = songPlayLogs.Count;
|
||||||
|
songBestData.ClearCount = songPlayLogs.Count(datum => datum.Crown >= CrownType.Clear);
|
||||||
|
songBestData.FullComboCount = songPlayLogs.Count(datum => datum.Crown >= CrownType.Gold);
|
||||||
|
songBestData.PerfectCount = songPlayLogs.Count(datum => datum.Crown >= CrownType.Dondaful);
|
||||||
|
}
|
||||||
var favoriteSongs = await userDatumService.GetFavoriteSongIds(baid);
|
var favoriteSongs = await userDatumService.GetFavoriteSongIds(baid);
|
||||||
var favoriteSet = favoriteSongs.ToHashSet();
|
var favoriteSet = favoriteSongs.ToHashSet();
|
||||||
foreach (var songBestRecord in songBestRecords.Where(songBestRecord => favoriteSet.Contains(songBestRecord.SongId)))
|
foreach (var songBestRecord in songBestRecords.Where(songBestRecord => favoriteSet.Contains(songBestRecord.SongId)))
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Text.Json;
|
||||||
using System.Text.Json;
|
|
||||||
using SharedProject.Models;
|
using SharedProject.Models;
|
||||||
using SharedProject.Models.Responses;
|
|
||||||
using SharedProject.Utils;
|
using SharedProject.Utils;
|
||||||
using TaikoLocalServer.Services;
|
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Api;
|
namespace TaikoLocalServer.Controllers.Api;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
@ -16,13 +15,16 @@ public class BaidController : BaseController<BaidController>
|
|||||||
|
|
||||||
private readonly IDanScoreDatumService danScoreDatumService;
|
private readonly IDanScoreDatumService danScoreDatumService;
|
||||||
|
|
||||||
|
private readonly IAiDatumService aiDatumService;
|
||||||
|
|
||||||
public BaidController(IUserDatumService userDatumService, ICardService cardService,
|
public BaidController(IUserDatumService userDatumService, ICardService cardService,
|
||||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService)
|
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService)
|
||||||
{
|
{
|
||||||
this.userDatumService = userDatumService;
|
this.userDatumService = userDatumService;
|
||||||
this.cardService = cardService;
|
this.cardService = cardService;
|
||||||
this.songBestDatumService = songBestDatumService;
|
this.songBestDatumService = songBestDatumService;
|
||||||
this.danScoreDatumService = danScoreDatumService;
|
this.danScoreDatumService = danScoreDatumService;
|
||||||
|
this.aiDatumService = aiDatumService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +114,11 @@ public class BaidController : BaseController<BaidController>
|
|||||||
var genericInfoFlgLength = genericInfoFlg.Any()? genericInfoFlg.Max() + 1 : 0;
|
var genericInfoFlgLength = genericInfoFlg.Any()? genericInfoFlg.Max() + 1 : 0;
|
||||||
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger);
|
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger);
|
||||||
|
|
||||||
|
var aiRank = (uint)(userData.AiWinCount / 10);
|
||||||
|
if (aiRank > 11)
|
||||||
|
{
|
||||||
|
aiRank = 11;
|
||||||
|
}
|
||||||
response = new BAIDResponse
|
response = new BAIDResponse
|
||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
@ -158,8 +165,8 @@ public class BaidController : BaseController<BaidController>
|
|||||||
IsDispAchievementTypeSet = true,
|
IsDispAchievementTypeSet = true,
|
||||||
LastPlayMode = userData.LastPlayMode,
|
LastPlayMode = userData.LastPlayMode,
|
||||||
IsDispSouuchiOn = true,
|
IsDispSouuchiOn = true,
|
||||||
AiRank = 0,
|
AiRank = aiRank,
|
||||||
AiTotalWin = 0,
|
AiTotalWin = (uint)userData.AiWinCount,
|
||||||
Accesstoken = "123456",
|
Accesstoken = "123456",
|
||||||
ContentInfo = GZipBytesUtil.GetGZipBytes(new byte[10])
|
ContentInfo = GZipBytesUtil.GetGZipBytes(new byte[10])
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using TaikoLocalServer.Settings;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
@ -8,9 +10,12 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
|||||||
{
|
{
|
||||||
private readonly ISongBestDatumService songBestDatumService;
|
private readonly ISongBestDatumService songBestDatumService;
|
||||||
|
|
||||||
public CrownsDataController(ISongBestDatumService songBestDatumService)
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
|
public CrownsDataController(ISongBestDatumService songBestDatumService, IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.songBestDatumService = songBestDatumService;
|
this.songBestDatumService = songBestDatumService;
|
||||||
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -21,10 +26,11 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
|||||||
|
|
||||||
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
||||||
|
|
||||||
var crown = new ushort[Constants.CROWN_FLAG_ARRAY_SIZE];
|
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||||
var dondafulCrown = new byte[Constants.DONDAFUL_CROWN_FLAG_ARRAY_SIZE];
|
var crown = new ushort[songIdMax + 1];
|
||||||
|
var dondafulCrown = new byte[songIdMax + 1];
|
||||||
|
|
||||||
for (var songId = 0; songId < Constants.MUSIC_ID_MAX; songId++)
|
for (var songId = 0; songId < songIdMax; songId++)
|
||||||
{
|
{
|
||||||
var id = songId;
|
var id = songId;
|
||||||
dondafulCrown[songId] = songBestData
|
dondafulCrown[songId] = songBestData
|
||||||
@ -41,7 +47,7 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
|||||||
// Calculate flag according to difficulty
|
// Calculate flag according to difficulty
|
||||||
.Aggregate((ushort)0, (flag, datum) => FlagCalculator.ComputeCrownFlag(flag, datum.BestCrown, datum.Difficulty));
|
.Aggregate((ushort)0, (flag, datum) => FlagCalculator.ComputeCrownFlag(flag, datum.BestCrown, datum.Difficulty));
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = new CrownsDataResponse
|
var response = new CrownsDataResponse
|
||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
|
@ -1,21 +1,32 @@
|
|||||||
namespace TaikoLocalServer.Controllers.Game;
|
using Throw;
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
[Route("/v12r03/chassis/getaidata.php")]
|
[Route("/v12r03/chassis/getaidata.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class GetAiDataController : BaseController<GetAiDataController>
|
public class GetAiDataController : BaseController<GetAiDataController>
|
||||||
{
|
{
|
||||||
|
private readonly IUserDatumService userDatumService;
|
||||||
|
|
||||||
|
public GetAiDataController(IUserDatumService userDatumService)
|
||||||
|
{
|
||||||
|
this.userDatumService = userDatumService;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Produces("application/protobuf")]
|
[Produces("application/protobuf")]
|
||||||
public IActionResult GetAiData([FromBody] GetAiDataRequest request)
|
public async Task<IActionResult> GetAiData([FromBody] GetAiDataRequest request)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("GetAiData request : {Request}", request.Stringify());
|
Logger.LogInformation("GetAiData request : {Request}", request.Stringify());
|
||||||
|
|
||||||
|
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
|
||||||
|
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||||
var response = new GetAiDataResponse
|
var response = new GetAiDataResponse
|
||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
TotalWinnings = 1,
|
TotalWinnings = (uint)user.AiWinCount,
|
||||||
InputMedian = "1",
|
InputMedian = "1000",
|
||||||
InputVariance = "0.576389"
|
InputVariance = "2000"
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
namespace TaikoLocalServer.Controllers.Game;
|
using Throw;
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
[Route("/v12r03/chassis/getaiscore.php")]
|
[Route("/v12r03/chassis/getaiscore.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class GetAiScoreController : BaseController<GetAiScoreController>
|
public class GetAiScoreController : BaseController<GetAiScoreController>
|
||||||
{
|
{
|
||||||
|
private readonly IAiDatumService aiDatumService;
|
||||||
|
|
||||||
|
public GetAiScoreController(IAiDatumService aiDatumService)
|
||||||
|
{
|
||||||
|
this.aiDatumService = aiDatumService;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Produces("application/protobuf")]
|
[Produces("application/protobuf")]
|
||||||
public IActionResult GetAiScore([FromBody] GetAiScoreRequest request)
|
public async Task<IActionResult> GetAiScore([FromBody] GetAiScoreRequest request)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("GetAiScore request : {Request}", request.Stringify());
|
Logger.LogInformation("GetAiScore request : {Request}", request.Stringify());
|
||||||
|
|
||||||
@ -15,9 +24,33 @@ public class GetAiScoreController : BaseController<GetAiScoreController>
|
|||||||
Result = 1
|
Result = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var difficulty = (Difficulty)request.Level;
|
||||||
|
difficulty.Throw().IfOutOfRange();
|
||||||
|
|
||||||
|
var aiData = await aiDatumService.GetSongAiScore(request.Baid, request.SongNo, difficulty);
|
||||||
|
if (aiData is null)
|
||||||
|
{
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var index = 0; index < aiData.AiSectionScoreData.Count; index++)
|
||||||
|
{
|
||||||
|
var sectionScoreDatum = aiData.AiSectionScoreData[index];
|
||||||
|
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData
|
||||||
|
{
|
||||||
|
Crown = (uint)sectionScoreDatum.Crown,
|
||||||
|
GoodCnt = sectionScoreDatum.GoodCount,
|
||||||
|
OkCnt = sectionScoreDatum.OkCount,
|
||||||
|
NgCnt = sectionScoreDatum.MissCount,
|
||||||
|
PoundCnt = sectionScoreDatum.DrumrollCount,
|
||||||
|
Score = sectionScoreDatum.Score,
|
||||||
|
SectionNo = (uint)index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// There's either 3 or 5 total sections
|
// There's either 3 or 5 total sections
|
||||||
// SectionNo doesn't seem to actually affect which section is being assigned to, only the List order matters
|
// SectionNo doesn't seem to actually affect which section is being assigned to, only the List order matters
|
||||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
/*response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||||
{
|
{
|
||||||
SectionNo = 1,
|
SectionNo = 1,
|
||||||
Crown = (uint)CrownType.Clear,
|
Crown = (uint)CrownType.Clear,
|
||||||
@ -66,7 +99,7 @@ public class GetAiScoreController : BaseController<GetAiScoreController>
|
|||||||
OkCnt = 50,
|
OkCnt = 50,
|
||||||
NgCnt = 25,
|
NgCnt = 25,
|
||||||
PoundCnt = 12
|
PoundCnt = 12
|
||||||
});
|
});*/
|
||||||
|
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
|
||||||
|
|
||||||
[Route("/v12r03/chassis/getdanodai.php")]
|
[Route("/v12r03/chassis/getdanodai.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
|
||||||
|
|
||||||
[Route("/v12r03/chassis/getdanscore.php")]
|
[Route("/v12r03/chassis/getdanscore.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
using Microsoft.Extensions.Options;
|
||||||
|
using TaikoLocalServer.Settings;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
@ -7,10 +8,13 @@ namespace TaikoLocalServer.Controllers.Game;
|
|||||||
public class GetScoreRankController : BaseController<GetScoreRankController>
|
public class GetScoreRankController : BaseController<GetScoreRankController>
|
||||||
{
|
{
|
||||||
private readonly ISongBestDatumService songBestDatumService;
|
private readonly ISongBestDatumService songBestDatumService;
|
||||||
|
|
||||||
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
public GetScoreRankController(ISongBestDatumService songBestDatumService)
|
public GetScoreRankController(ISongBestDatumService songBestDatumService, IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.songBestDatumService = songBestDatumService;
|
this.songBestDatumService = songBestDatumService;
|
||||||
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -18,12 +22,13 @@ public class GetScoreRankController : BaseController<GetScoreRankController>
|
|||||||
public async Task<IActionResult> GetScoreRank([FromBody] GetScoreRankRequest request)
|
public async Task<IActionResult> GetScoreRank([FromBody] GetScoreRankRequest request)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("GetScoreRank request : {Request}", request.Stringify());
|
Logger.LogInformation("GetScoreRank request : {Request}", request.Stringify());
|
||||||
var kiwamiScores = new byte[Constants.KIWAMI_SCORE_RANK_ARRAY_SIZE];
|
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||||
var miyabiScores = new ushort[Constants.MIYABI_CORE_RANK_ARRAY_SIZE];
|
var kiwamiScores = new byte[songIdMax + 1];
|
||||||
var ikiScores = new ushort[Constants.IKI_CORE_RANK_ARRAY_SIZE];
|
var miyabiScores = new ushort[songIdMax + 1];
|
||||||
|
var ikiScores = new ushort[songIdMax + 1];
|
||||||
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
||||||
|
|
||||||
for (var songId = 0; songId < Constants.MUSIC_ID_MAX; songId++)
|
for (var songId = 0; songId < songIdMax; songId++)
|
||||||
{
|
{
|
||||||
var id = songId;
|
var id = songId;
|
||||||
kiwamiScores[songId] = songBestData
|
kiwamiScores[songId] = songBestData
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
|
||||||
|
|
||||||
[Route("/v12r03/chassis/getsongintroduction.php")]
|
[Route("/v12r03/chassis/getsongintroduction.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
using Microsoft.Extensions.Options;
|
||||||
|
using TaikoLocalServer.Settings;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
@ -8,9 +9,12 @@ public class InitialDataCheckController : BaseController<InitialDataCheckControl
|
|||||||
{
|
{
|
||||||
private readonly IGameDataService gameDataService;
|
private readonly IGameDataService gameDataService;
|
||||||
|
|
||||||
public InitialDataCheckController(IGameDataService gameDataService)
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
|
public InitialDataCheckController(IGameDataService gameDataService, IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.gameDataService = gameDataService;
|
this.gameDataService = gameDataService;
|
||||||
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -19,8 +23,9 @@ public class InitialDataCheckController : BaseController<InitialDataCheckControl
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
|
Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
|
||||||
|
|
||||||
|
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||||
var enabledArray =
|
var enabledArray =
|
||||||
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), Constants.MUSIC_ID_MAX, Logger);
|
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), songIdMax, Logger);
|
||||||
|
|
||||||
var danData = new List<InitialdatacheckResponse.InformationData>();
|
var danData = new List<InitialdatacheckResponse.InformationData>();
|
||||||
for (var danId = Constants.MIN_DAN_ID; danId <= Constants.MAX_DAN_ID; danId++)
|
for (var danId = Constants.MIN_DAN_ID; danId <= Constants.MAX_DAN_ID; danId++)
|
||||||
@ -46,7 +51,7 @@ public class InitialDataCheckController : BaseController<InitialDataCheckControl
|
|||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
IsDanplay = true,
|
IsDanplay = true,
|
||||||
IsAibattle = false,
|
IsAibattle = true,
|
||||||
IsClose = false,
|
IsClose = false,
|
||||||
DefaultSongFlg = enabledArray,
|
DefaultSongFlg = enabledArray,
|
||||||
AchievementSongBit = enabledArray,
|
AchievementSongBit = enabledArray,
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
|
||||||
|
|
||||||
[Route("/v12r03/chassis/mydonentry.php")]
|
[Route("/v12r03/chassis/mydonentry.php")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
@ -20,13 +19,16 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
|
|
||||||
private readonly IDanScoreDatumService danScoreDatumService;
|
private readonly IDanScoreDatumService danScoreDatumService;
|
||||||
|
|
||||||
|
private readonly IAiDatumService aiDatumService;
|
||||||
|
|
||||||
public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
|
public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
|
||||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService)
|
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService)
|
||||||
{
|
{
|
||||||
this.userDatumService = userDatumService;
|
this.userDatumService = userDatumService;
|
||||||
this.songPlayDatumService = songPlayDatumService;
|
this.songPlayDatumService = songPlayDatumService;
|
||||||
this.songBestDatumService = songBestDatumService;
|
this.songBestDatumService = songBestDatumService;
|
||||||
this.danScoreDatumService = danScoreDatumService;
|
this.danScoreDatumService = danScoreDatumService;
|
||||||
|
this.aiDatumService = aiDatumService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -77,9 +79,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
|
|
||||||
if (playMode == PlayMode.AiBattle)
|
if (playMode == PlayMode.AiBattle)
|
||||||
{
|
{
|
||||||
// await UpdateAiBattleData(request, stageData);
|
await UpdateAiBattleData(request, stageData);
|
||||||
// Update AI win count here somewhere, or in UpdatePlayData?
|
|
||||||
// I have no clue how to update input median or variance
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await UpdateBestData(request, stageData, bestData);
|
await UpdateBestData(request, stageData, bestData);
|
||||||
@ -163,7 +163,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
ComboCount = stageData.ComboCnt,
|
ComboCount = stageData.ComboCnt,
|
||||||
HitCount = stageData.HitCnt,
|
HitCount = stageData.HitCnt,
|
||||||
DrumrollCount = stageData.PoundCnt,
|
DrumrollCount = stageData.PoundCnt,
|
||||||
Crown = PlayResultToCrown(stageData),
|
Crown = PlayResultToCrown(stageData.PlayResult, stageData.OkCnt),
|
||||||
Score = stageData.PlayScore,
|
Score = stageData.PlayScore,
|
||||||
ScoreRate = stageData.ScoreRate,
|
ScoreRate = stageData.ScoreRate,
|
||||||
ScoreRank = (ScoreRank)stageData.ScoreRank,
|
ScoreRank = (ScoreRank)stageData.ScoreRank,
|
||||||
@ -229,6 +229,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
userdata.GenericInfoFlgArray =
|
userdata.GenericInfoFlgArray =
|
||||||
UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray));
|
UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray));
|
||||||
|
|
||||||
|
userdata.AiWinCount += playResultData.AryStageInfoes.Count(data => data.IsWin);
|
||||||
await userDatumService.UpdateUserDatum(userdata);
|
await userDatumService.UpdateUserDatum(userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +301,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Determine whether it is dondaful crown as this is not reflected by play result
|
// Determine whether it is dondaful crown as this is not reflected by play result
|
||||||
var crown = PlayResultToCrown(stageData);
|
var crown = PlayResultToCrown(stageData.PlayResult, stageData.OkCnt);
|
||||||
|
|
||||||
bestDatum.UpdateBestData(crown, stageData.ScoreRank, stageData.PlayScore, stageData.ScoreRate);
|
bestDatum.UpdateBestData(crown, stageData.ScoreRank, stageData.PlayScore, stageData.ScoreRate);
|
||||||
|
|
||||||
@ -308,23 +309,69 @@ public class PlayResultController : BaseController<PlayResultController>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: AI battle
|
// TODO: AI battle
|
||||||
/*private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData)
|
private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < stageData.ArySectionDatas.Count; i++)
|
var difficulty = (Difficulty)stageData.Level;
|
||||||
|
difficulty.Throw().IfOutOfRange();
|
||||||
|
var existing = await aiDatumService.GetSongAiScore(request.BaidConf,
|
||||||
|
stageData.SongNo, difficulty);
|
||||||
|
|
||||||
|
if (existing is null)
|
||||||
{
|
{
|
||||||
// Only update crown if it's a higher crown than the previous best crown
|
var aiScoreDatum = new AiScoreDatum
|
||||||
|
{
|
||||||
|
Baid = request.BaidConf,
|
||||||
|
SongId = stageData.SongNo,
|
||||||
|
Difficulty = difficulty,
|
||||||
|
IsWin = stageData.IsWin
|
||||||
|
};
|
||||||
|
for (var index = 0; index < stageData.ArySectionDatas.Count; index++)
|
||||||
|
{
|
||||||
|
AddNewAiSectionScore(request, stageData, index, difficulty, aiScoreDatum);
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe have a "SectionNo" variable for which section number it is on the DB
|
await aiDatumService.InsertSongAiScore(aiScoreDatum);
|
||||||
// compare DB.SectionNo == i
|
return;
|
||||||
// if any aspect of the section is higher than the previous best, update it
|
|
||||||
// Similar to Dan best play updates
|
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
private static CrownType PlayResultToCrown(StageData stageData)
|
for (var index = 0; index < stageData.ArySectionDatas.Count; index++)
|
||||||
|
{
|
||||||
|
var sectionData = stageData.ArySectionDatas[index];
|
||||||
|
if (index < existing.AiSectionScoreData.Count)
|
||||||
|
{
|
||||||
|
existing.AiSectionScoreData[index].UpdateBest(sectionData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddNewAiSectionScore(request,stageData,index,difficulty,existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await aiDatumService.UpdateSongAiScore(existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddNewAiSectionScore(PlayResultRequest request, StageData stageData, int index, Difficulty difficulty,
|
||||||
|
AiScoreDatum aiScoreDatum)
|
||||||
{
|
{
|
||||||
var crown = (CrownType)stageData.PlayResult;
|
var sectionData = stageData.ArySectionDatas[index];
|
||||||
if (crown == CrownType.Gold && stageData.OkCnt == 0)
|
var aiSectionScoreDatum = new AiSectionScoreDatum
|
||||||
|
{
|
||||||
|
Baid = request.BaidConf,
|
||||||
|
SongId = stageData.SongNo,
|
||||||
|
Difficulty = difficulty,
|
||||||
|
SectionIndex = index,
|
||||||
|
OkCount = sectionData.OkCnt,
|
||||||
|
MissCount = sectionData.NgCnt
|
||||||
|
};
|
||||||
|
aiSectionScoreDatum.UpdateBest(sectionData);
|
||||||
|
aiScoreDatum.AiSectionScoreData.Add(aiSectionScoreDatum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static CrownType PlayResultToCrown(uint playResult, uint okCount)
|
||||||
|
{
|
||||||
|
var crown = (CrownType)playResult;
|
||||||
|
if (crown == CrownType.Gold && okCount == 0)
|
||||||
{
|
{
|
||||||
crown = CrownType.Dondaful;
|
crown = CrownType.Dondaful;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
using Throw;
|
||||||
using Throw;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
using Microsoft.Extensions.Options;
|
||||||
|
using TaikoLocalServer.Settings;
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Controllers.Game;
|
namespace TaikoLocalServer.Controllers.Game;
|
||||||
@ -14,12 +15,16 @@ public class UserDataController : BaseController<UserDataController>
|
|||||||
private readonly ISongPlayDatumService songPlayDatumService;
|
private readonly ISongPlayDatumService songPlayDatumService;
|
||||||
|
|
||||||
private readonly IGameDataService gameDataService;
|
private readonly IGameDataService gameDataService;
|
||||||
|
|
||||||
|
private readonly ServerSettings settings;
|
||||||
|
|
||||||
public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService, IGameDataService gameDataService)
|
public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
|
||||||
|
IGameDataService gameDataService, IOptions<ServerSettings> settings)
|
||||||
{
|
{
|
||||||
this.userDatumService = userDatumService;
|
this.userDatumService = userDatumService;
|
||||||
this.songPlayDatumService = songPlayDatumService;
|
this.songPlayDatumService = songPlayDatumService;
|
||||||
this.gameDataService = gameDataService;
|
this.gameDataService = gameDataService;
|
||||||
|
this.settings = settings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@ -28,11 +33,12 @@ public class UserDataController : BaseController<UserDataController>
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("UserData request : {Request}", request.Stringify());
|
Logger.LogInformation("UserData request : {Request}", request.Stringify());
|
||||||
|
|
||||||
|
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||||
var releaseSongArray =
|
var releaseSongArray =
|
||||||
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), Constants.MUSIC_ID_MAX, Logger);
|
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), songIdMax, Logger);
|
||||||
|
|
||||||
var uraSongArray =
|
var uraSongArray =
|
||||||
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicWithUraList(), Constants.MUSIC_ID_MAX, Logger);
|
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicWithUraList(), songIdMax, Logger);
|
||||||
|
|
||||||
var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid);
|
var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid);
|
||||||
|
|
||||||
|
16
TaikoLocalServer/Entities/AiScoreDatum.cs
Normal file
16
TaikoLocalServer/Entities/AiScoreDatum.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace TaikoLocalServer.Entities;
|
||||||
|
|
||||||
|
public class AiScoreDatum
|
||||||
|
{
|
||||||
|
public uint Baid { get; set; }
|
||||||
|
|
||||||
|
public uint SongId { get; set; }
|
||||||
|
|
||||||
|
public Difficulty Difficulty { get; set; }
|
||||||
|
|
||||||
|
public bool IsWin { get; set; }
|
||||||
|
|
||||||
|
public List<AiSectionScoreDatum> AiSectionScoreData { get; set; } = new();
|
||||||
|
|
||||||
|
public virtual Card? Ba { get; set; }
|
||||||
|
}
|
47
TaikoLocalServer/Entities/AiSectionScoreDatum.cs
Normal file
47
TaikoLocalServer/Entities/AiSectionScoreDatum.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using SharedProject.Utils;
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Entities;
|
||||||
|
|
||||||
|
public class AiSectionScoreDatum
|
||||||
|
{
|
||||||
|
public uint Baid { get; set; }
|
||||||
|
|
||||||
|
public uint SongId { get; set; }
|
||||||
|
|
||||||
|
public Difficulty Difficulty { get; set; }
|
||||||
|
|
||||||
|
public int SectionIndex { get; set; }
|
||||||
|
|
||||||
|
public CrownType Crown { get; set; }
|
||||||
|
|
||||||
|
public bool IsWin { get; set; }
|
||||||
|
|
||||||
|
public uint Score { get; set; }
|
||||||
|
|
||||||
|
public uint GoodCount { get; set; }
|
||||||
|
|
||||||
|
public uint OkCount { get; set; }
|
||||||
|
|
||||||
|
public uint MissCount { get; set; }
|
||||||
|
|
||||||
|
public uint DrumrollCount { get; set; }
|
||||||
|
|
||||||
|
public AiScoreDatum Parent { get; set; } = null!;
|
||||||
|
|
||||||
|
public void UpdateBest(PlayResultDataRequest.StageData.AiStageSectionData sectionData)
|
||||||
|
{
|
||||||
|
var crown = (CrownType)sectionData.Crown;
|
||||||
|
if (crown == CrownType.Gold && sectionData.OkCnt == 0)
|
||||||
|
{
|
||||||
|
crown = CrownType.Dondaful;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsWin = sectionData.IsWin ? sectionData.IsWin : IsWin;
|
||||||
|
Crown = ValueHelpers.Max(crown, Crown);
|
||||||
|
Score = ValueHelpers.Max(sectionData.Score, Score);
|
||||||
|
GoodCount = ValueHelpers.Max(sectionData.GoodCnt, GoodCount);
|
||||||
|
OkCount = ValueHelpers.Min(sectionData.OkCnt, OkCount);
|
||||||
|
MissCount = ValueHelpers.Min(sectionData.NgCnt, MissCount);
|
||||||
|
DrumrollCount = ValueHelpers.Max(sectionData.PoundCnt, DrumrollCount);
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
public bool DisplayAchievement { get; set; }
|
public bool DisplayAchievement { get; set; }
|
||||||
public Difficulty AchievementDisplayDifficulty { get; set; }
|
public Difficulty AchievementDisplayDifficulty { get; set; }
|
||||||
|
|
||||||
|
public int AiWinCount { get; set; }
|
||||||
public virtual Card? Ba { get; set; }
|
public virtual Card? Ba { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,6 @@ global using TaikoLocalServer.Common;
|
|||||||
global using TaikoLocalServer.Common.Utils;
|
global using TaikoLocalServer.Common.Utils;
|
||||||
global using TaikoLocalServer.Context;
|
global using TaikoLocalServer.Context;
|
||||||
global using TaikoLocalServer.Entities;
|
global using TaikoLocalServer.Entities;
|
||||||
global using TaikoLocalServer.Models;
|
global using TaikoLocalServer.Models;
|
||||||
|
global using TaikoLocalServer.Services;
|
||||||
|
global using TaikoLocalServer.Services.Interfaces;
|
432
TaikoLocalServer/Migrations/20220917180457_AddAiBattle.Designer.cs
generated
Normal file
432
TaikoLocalServer/Migrations/20220917180457_AddAiBattle.Designer.cs
generated
Normal file
@ -0,0 +1,432 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TaikoLocalServer.Context;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TaikoDbContext))]
|
||||||
|
[Migration("20220917180457_AddAiBattle")]
|
||||||
|
partial class AddAiBattle
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.0-preview.7.22376.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty");
|
||||||
|
|
||||||
|
b.ToTable("AiScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SectionIndex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Crown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("MissCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
|
||||||
|
|
||||||
|
b.ToTable("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.Card", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("AccessCode")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("AccessCode");
|
||||||
|
|
||||||
|
b.HasIndex(new[] { "Baid" }, "IX_Card_Baid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Card", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DanId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ArrivalSongCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ClearState")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0u);
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCountTotal")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SoulGaugeTotal")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "DanId");
|
||||||
|
|
||||||
|
b.ToTable("DanScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DanId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BadCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("HighScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("PlayScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("TotalHitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "DanId", "SongNumber");
|
||||||
|
|
||||||
|
b.ToTable("DanStageScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestCrown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestRate")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestScoreRank")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty");
|
||||||
|
|
||||||
|
b.ToTable("SongBestData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Crown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("HitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("MissCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("PlayTime")
|
||||||
|
.HasColumnType("datetime");
|
||||||
|
|
||||||
|
b.Property<uint>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ScoreRank")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ScoreRate")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Skipped")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Baid");
|
||||||
|
|
||||||
|
b.ToTable("SongPlayData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("AchievementDisplayDifficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorBody")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorFace")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorLimb")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CostumeData")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CostumeFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayAchievement")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayDan")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("FavoriteSongsArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("GenericInfoFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSkipOn")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsVoiceOn")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastPlayDatetime")
|
||||||
|
.HasColumnType("datetime");
|
||||||
|
|
||||||
|
b.Property<uint>("LastPlayMode")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("MyDonName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("NotesPosition")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<short>("OptionSetting")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SelectedToneId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TitleFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("TitlePlateId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ToneFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Baid");
|
||||||
|
|
||||||
|
b.ToTable("UserData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.AiScoreDatum", "Parent")
|
||||||
|
.WithMany("AiSectionScoreData")
|
||||||
|
.HasForeignKey("Baid", "SongId", "Difficulty")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.DanScoreDatum", "Parent")
|
||||||
|
.WithMany("DanStageScoreData")
|
||||||
|
.HasForeignKey("Baid", "DanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("DanStageScoreData");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
TaikoLocalServer/Migrations/20220917180457_AddAiBattle.cs
Normal file
71
TaikoLocalServer/Migrations/20220917180457_AddAiBattle.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddAiBattle : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AiScoreData",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Baid = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
SongId = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
Difficulty = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
IsWin = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AiScoreData", x => new { x.Baid, x.SongId, x.Difficulty });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AiScoreData_Card_Baid",
|
||||||
|
column: x => x.Baid,
|
||||||
|
principalTable: "Card",
|
||||||
|
principalColumn: "Baid",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AiSectionScoreData",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Baid = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
SongId = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
Difficulty = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
SectionIndex = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Crown = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
IsWin = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Score = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
GoodCount = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
OkCount = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
MissCount = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||||
|
DrumrollCount = table.Column<uint>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AiSectionScoreData", x => new { x.Baid, x.SongId, x.Difficulty, x.SectionIndex });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AiSectionScoreData_AiScoreData_Baid_SongId_Difficulty",
|
||||||
|
columns: x => new { x.Baid, x.SongId, x.Difficulty },
|
||||||
|
principalTable: "AiScoreData",
|
||||||
|
principalColumns: new[] { "Baid", "SongId", "Difficulty" },
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AiSectionScoreData");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AiScoreData");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
435
TaikoLocalServer/Migrations/20220919022643_AddWinCountToUserdata.Designer.cs
generated
Normal file
435
TaikoLocalServer/Migrations/20220919022643_AddWinCountToUserdata.Designer.cs
generated
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TaikoLocalServer.Context;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TaikoDbContext))]
|
||||||
|
[Migration("20220919022643_AddWinCountToUserdata")]
|
||||||
|
partial class AddWinCountToUserdata
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.0-preview.7.22376.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty");
|
||||||
|
|
||||||
|
b.ToTable("AiScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SectionIndex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Crown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("MissCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
|
||||||
|
|
||||||
|
b.ToTable("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.Card", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("AccessCode")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("AccessCode");
|
||||||
|
|
||||||
|
b.HasIndex(new[] { "Baid" }, "IX_Card_Baid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Card", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DanId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ArrivalSongCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ClearState")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0u);
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCountTotal")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SoulGaugeTotal")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "DanId");
|
||||||
|
|
||||||
|
b.ToTable("DanScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DanId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BadCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("HighScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("PlayScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("TotalHitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "DanId", "SongNumber");
|
||||||
|
|
||||||
|
b.ToTable("DanStageScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestCrown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestRate")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("BestScoreRank")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty");
|
||||||
|
|
||||||
|
b.ToTable("SongBestData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ComboCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Crown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("HitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("MissCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("PlayTime")
|
||||||
|
.HasColumnType("datetime");
|
||||||
|
|
||||||
|
b.Property<uint>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ScoreRank")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ScoreRate")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Skipped")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongNumber")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Baid");
|
||||||
|
|
||||||
|
b.ToTable("SongPlayData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("AchievementDisplayDifficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AiWinCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorBody")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorFace")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("ColorLimb")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CostumeData")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CostumeFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayAchievement")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("DisplayDan")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("FavoriteSongsArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("GenericInfoFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSkipOn")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsVoiceOn")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastPlayDatetime")
|
||||||
|
.HasColumnType("datetime");
|
||||||
|
|
||||||
|
b.Property<uint>("LastPlayMode")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("MyDonName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("NotesPosition")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<short>("OptionSetting")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SelectedToneId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TitleFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<uint>("TitlePlateId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ToneFlgArray")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Baid");
|
||||||
|
|
||||||
|
b.ToTable("UserData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.AiScoreDatum", "Parent")
|
||||||
|
.WithMany("AiSectionScoreData")
|
||||||
|
.HasForeignKey("Baid", "SongId", "Difficulty")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.DanScoreDatum", "Parent")
|
||||||
|
.WithMany("DanStageScoreData")
|
||||||
|
.HasForeignKey("Baid", "DanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("DanStageScoreData");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddWinCountToUserdata : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "AiWinCount",
|
||||||
|
table: "UserData",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AiWinCount",
|
||||||
|
table: "UserData");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,65 @@ namespace TaikoLocalServer.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.0-preview.7.22376.2");
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.0-preview.7.22376.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty");
|
||||||
|
|
||||||
|
b.ToTable("AiScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Property<uint>("Baid")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("SongId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Difficulty")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SectionIndex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Crown")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("DrumrollCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("GoodCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsWin")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("MissCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("OkCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<uint>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
|
||||||
|
|
||||||
|
b.ToTable("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TaikoLocalServer.Entities.Card", b =>
|
modelBuilder.Entity("TaikoLocalServer.Entities.Card", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("AccessCode")
|
b.Property<string>("AccessCode")
|
||||||
@ -197,6 +256,9 @@ namespace TaikoLocalServer.Migrations
|
|||||||
b.Property<uint>("AchievementDisplayDifficulty")
|
b.Property<uint>("AchievementDisplayDifficulty")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AiWinCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<uint>("ColorBody")
|
b.Property<uint>("ColorBody")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
@ -273,6 +335,29 @@ namespace TaikoLocalServer.Migrations
|
|||||||
b.ToTable("UserData");
|
b.ToTable("UserData");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Baid")
|
||||||
|
.HasPrincipalKey("Baid")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Ba");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TaikoLocalServer.Entities.AiScoreDatum", "Parent")
|
||||||
|
.WithMany("AiSectionScoreData")
|
||||||
|
.HasForeignKey("Baid", "SongId", "Difficulty")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
b.HasOne("TaikoLocalServer.Entities.Card", "Ba")
|
||||||
@ -332,6 +417,11 @@ namespace TaikoLocalServer.Migrations
|
|||||||
b.Navigation("Ba");
|
b.Navigation("Ba");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AiSectionScoreData");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("DanStageScoreData");
|
b.Navigation("DanStageScoreData");
|
||||||
|
@ -1,87 +1,125 @@
|
|||||||
|
using System.Reflection;
|
||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
using Microsoft.AspNetCore.HttpLogging;
|
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using TaikoLocalServer.Middlewares;
|
using TaikoLocalServer.Middlewares;
|
||||||
using TaikoLocalServer.Services;
|
|
||||||
using TaikoLocalServer.Services.Extentions;
|
using TaikoLocalServer.Services.Extentions;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using TaikoLocalServer.Settings;
|
using TaikoLocalServer.Settings;
|
||||||
using Throw;
|
using Throw;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
Log.Logger = new LoggerConfiguration()
|
||||||
// Manually enable tls 1.0
|
.WriteTo.Console()
|
||||||
builder.WebHost.UseKestrel(kestrelOptions =>
|
.CreateBootstrapLogger();
|
||||||
|
|
||||||
|
var version = Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
|
||||||
|
.InformationalVersion;
|
||||||
|
Log.Information("TaikoLocalServer version {Version}", version);
|
||||||
|
|
||||||
|
Log.Information("Server starting up...");
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
// Manually enable tls 1.0
|
||||||
|
builder.WebHost.UseKestrel(kestrelOptions =>
|
||||||
{
|
{
|
||||||
httpsOptions.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
|
kestrelOptions.ConfigureHttpsDefaults(options =>
|
||||||
|
options.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Add services to the container.
|
builder.Host.UseSerilog((context, configuration) =>
|
||||||
builder.Services.AddOptions();
|
|
||||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
|
||||||
builder.Services.Configure<UrlSettings>(builder.Configuration.GetSection(nameof(UrlSettings)));
|
|
||||||
builder.Services.AddControllers().AddProtoBufNet();
|
|
||||||
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
|
||||||
{
|
|
||||||
var dbName = builder.Configuration["DbFileName"];
|
|
||||||
if (string.IsNullOrEmpty(dbName))
|
|
||||||
{
|
{
|
||||||
dbName = Constants.DEFAULT_DB_NAME;
|
configuration.WriteTo.Console().ReadFrom.Configuration(context.Configuration);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (builder.Configuration.GetValue<bool>("ServerSettings:EnableMoreSongs"))
|
||||||
|
{
|
||||||
|
Log.Warning("Song limit expanded! Currently the game has issue loading crown/score rank and " +
|
||||||
|
"probably more server related data for songs with id > 1599. " +
|
||||||
|
"Also, the game can have random crashes because of that! Use at your own risk!");
|
||||||
}
|
}
|
||||||
var path = Path.Combine(PathHelper.GetRootPath(), dbName);
|
|
||||||
option.UseSqlite($"Data Source={path}");
|
// Add services to the container.
|
||||||
});
|
builder.Services.AddOptions();
|
||||||
builder.Services.AddHttpLogging(options =>
|
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
||||||
{
|
builder.Services.Configure<ServerSettings>(builder.Configuration.GetSection(nameof(ServerSettings)));
|
||||||
options.LoggingFields = HttpLoggingFields.RequestProperties |
|
builder.Services.AddControllers().AddProtoBufNet();
|
||||||
HttpLoggingFields.ResponseStatusCode;
|
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
||||||
});
|
|
||||||
builder.Services.AddMemoryCache();
|
|
||||||
builder.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy("DevCorsPolicy", policy =>
|
|
||||||
{
|
{
|
||||||
policy
|
var dbName = builder.Configuration["DbFileName"];
|
||||||
.AllowAnyOrigin()
|
if (string.IsNullOrEmpty(dbName))
|
||||||
.AllowAnyMethod()
|
{
|
||||||
.AllowAnyHeader();
|
dbName = Constants.DEFAULT_DB_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = Path.Combine(PathHelper.GetRootPath(), dbName);
|
||||||
|
option.UseSqlite($"Data Source={path}");
|
||||||
});
|
});
|
||||||
});
|
builder.Services.AddMemoryCache();
|
||||||
builder.Services.AddTaikoDbServices();
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAllCorsPolicy", policy =>
|
||||||
|
{
|
||||||
|
policy
|
||||||
|
.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
builder.Services.AddTaikoDbServices();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Migrate db
|
// Migrate db
|
||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<TaikoDbContext>();
|
var db = scope.ServiceProvider.GetRequiredService<TaikoDbContext>();
|
||||||
db.Database.Migrate();
|
db.Database.Migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseSerilogRequestLogging(options =>
|
||||||
|
{
|
||||||
|
options.MessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms, " +
|
||||||
|
"request host: {RequestHost}";
|
||||||
|
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
||||||
|
{
|
||||||
|
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
var gameDataService = app.Services.GetService<IGameDataService>();
|
||||||
|
gameDataService.ThrowIfNull();
|
||||||
|
await gameDataService.InitializeAsync();
|
||||||
|
|
||||||
|
// For reverse proxy
|
||||||
|
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||||
|
{
|
||||||
|
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseCors("AllowAllCorsPolicy");
|
||||||
|
// For blazor hosting
|
||||||
|
app.UseBlazorFrameworkFiles();
|
||||||
|
app.UseStaticFiles();
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
|
||||||
|
app.UseHttpLogging();
|
||||||
|
app.MapControllers();
|
||||||
|
app.MapFallbackToFile("index.html");
|
||||||
|
|
||||||
|
app.UseWhen(
|
||||||
|
context => context.Request.Path.StartsWithSegments("/sys/servlet/PowerOn", StringComparison.InvariantCulture),
|
||||||
|
applicationBuilder => applicationBuilder.UseAllNetRequestMiddleware());
|
||||||
|
|
||||||
|
app.Run();
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
var gameDataService = app.Services.GetService<IGameDataService>();
|
|
||||||
gameDataService.ThrowIfNull();
|
|
||||||
await gameDataService.InitializeAsync();
|
|
||||||
|
|
||||||
// For reverse proxy
|
|
||||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
|
||||||
{
|
{
|
||||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
Log.Fatal(ex, "Unhandled exception");
|
||||||
});
|
}
|
||||||
|
finally
|
||||||
app.UseCors("DevCorsPolicy");
|
{
|
||||||
// For blazor hosting
|
Log.Information("Shut down complete");
|
||||||
app.UseBlazorFrameworkFiles();
|
Log.CloseAndFlush();
|
||||||
app.UseStaticFiles();
|
}
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
|
|
||||||
app.UseHttpLogging();
|
|
||||||
app.MapControllers();
|
|
||||||
app.MapFallbackToFile("index.html");
|
|
||||||
|
|
||||||
app.UseWhen(context => context.Request.Path.StartsWithSegments("/sys/servlet/PowerOn", StringComparison.InvariantCulture),
|
|
||||||
applicationBuilder => applicationBuilder.UseAllNetRequestMiddleware());
|
|
||||||
|
|
||||||
app.Run();
|
|
49
TaikoLocalServer/Services/AiDatumService.cs
Normal file
49
TaikoLocalServer/Services/AiDatumService.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Throw;
|
||||||
|
|
||||||
|
namespace TaikoLocalServer.Services;
|
||||||
|
|
||||||
|
public class AiDatumService : IAiDatumService
|
||||||
|
{
|
||||||
|
private readonly TaikoDbContext context;
|
||||||
|
|
||||||
|
public AiDatumService(TaikoDbContext context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid)
|
||||||
|
{
|
||||||
|
return await context.AiScoreData.Where(datum => datum.Baid == baid)
|
||||||
|
.Include(datum => datum.AiSectionScoreData)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty)
|
||||||
|
{
|
||||||
|
return await context.AiScoreData.Where(datum => datum.Baid == baid &&
|
||||||
|
datum.SongId == songId &&
|
||||||
|
datum.Difficulty == difficulty)
|
||||||
|
.Include(datum => datum.AiSectionScoreData)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateSongAiScore(AiScoreDatum datum)
|
||||||
|
{
|
||||||
|
var existing = await context.AiScoreData.FindAsync(datum.Baid, datum.SongId, datum.Difficulty);
|
||||||
|
existing.ThrowIfNull("Cannot update a non-existing ai score!");
|
||||||
|
|
||||||
|
context.AiScoreData.Update(datum);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InsertSongAiScore(AiScoreDatum datum)
|
||||||
|
{
|
||||||
|
var existing = await context.AiScoreData.FindAsync(datum.Baid, datum.SongId, datum.Difficulty);
|
||||||
|
if (existing is not null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Ai score already exists!", nameof(datum));
|
||||||
|
}
|
||||||
|
context.AiScoreData.Add(datum);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
using SharedProject.Models;
|
using SharedProject.Models;
|
||||||
using Swan.Mapping;
|
using Swan.Mapping;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Services;
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Services;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
|
||||||
|
|
||||||
public class DanScoreDatumService : IDanScoreDatumService
|
public class DanScoreDatumService : IDanScoreDatumService
|
||||||
{
|
{
|
||||||
@ -30,7 +28,7 @@ public class DanScoreDatumService : IDanScoreDatumService
|
|||||||
var existing = await context.DanScoreData.FindAsync(datum.Baid, datum.DanId);
|
var existing = await context.DanScoreData.FindAsync(datum.Baid, datum.DanId);
|
||||||
if (existing is null)
|
if (existing is null)
|
||||||
{
|
{
|
||||||
await context.DanScoreData.AddAsync(datum);
|
context.DanScoreData.Add(datum);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Services.Extentions;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services.Extentions;
|
|
||||||
|
|
||||||
public static class ServiceExtensions
|
public static class ServiceExtensions
|
||||||
{
|
{
|
||||||
@ -11,6 +9,7 @@ public static class ServiceExtensions
|
|||||||
services.AddScoped<ISongPlayDatumService, SongPlayDatumService>();
|
services.AddScoped<ISongPlayDatumService, SongPlayDatumService>();
|
||||||
services.AddScoped<ISongBestDatumService, SongBestDatumService>();
|
services.AddScoped<ISongBestDatumService, SongBestDatumService>();
|
||||||
services.AddScoped<IDanScoreDatumService, DanScoreDatumService>();
|
services.AddScoped<IDanScoreDatumService, DanScoreDatumService>();
|
||||||
|
services.AddScoped<IAiDatumService, AiDatumService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using SharedProject.Models;
|
using SharedProject.Models;
|
||||||
using Swan.Mapping;
|
using Swan.Mapping;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Services;
|
||||||
@ -54,6 +54,10 @@ public class GameDataService : IGameDataService
|
|||||||
var danDataPath = Path.Combine(dataPath, Constants.DAN_DATA_FILE_NAME);
|
var danDataPath = Path.Combine(dataPath, Constants.DAN_DATA_FILE_NAME);
|
||||||
var songIntroDataPath = Path.Combine(dataPath, Constants.INTRO_DATA_FILE_NAME);
|
var songIntroDataPath = Path.Combine(dataPath, Constants.INTRO_DATA_FILE_NAME);
|
||||||
|
|
||||||
|
if (!File.Exists(musicAttributePath))
|
||||||
|
{
|
||||||
|
TryDecompressMusicAttribute();
|
||||||
|
}
|
||||||
await using var musicAttributeFile = File.OpenRead(musicAttributePath);
|
await using var musicAttributeFile = File.OpenRead(musicAttributePath);
|
||||||
await using var danDataFile = File.OpenRead(danDataPath);
|
await using var danDataFile = File.OpenRead(danDataPath);
|
||||||
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
|
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
|
||||||
@ -69,6 +73,18 @@ public class GameDataService : IGameDataService
|
|||||||
InitializeIntroData(introData);
|
InitializeIntroData(introData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void TryDecompressMusicAttribute()
|
||||||
|
{
|
||||||
|
var dataPath = PathHelper.GetDataPath();
|
||||||
|
var musicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_FILE_NAME);
|
||||||
|
var compressedMusicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_COMPRESSED_FILE_NAME);
|
||||||
|
|
||||||
|
using var compressed = File.Open(compressedMusicAttributePath, FileMode.Open);
|
||||||
|
using var output = File.Create(musicAttributePath);
|
||||||
|
|
||||||
|
GZip.Decompress(compressed, output, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeIntroData(List<SongIntroductionData>? introData)
|
private void InitializeIntroData(List<SongIntroductionData>? introData)
|
||||||
{
|
{
|
||||||
introData.ThrowIfNull("Shouldn't happen!");
|
introData.ThrowIfNull("Shouldn't happen!");
|
||||||
|
12
TaikoLocalServer/Services/Interfaces/IAiDatumService.cs
Normal file
12
TaikoLocalServer/Services/Interfaces/IAiDatumService.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace TaikoLocalServer.Services.Interfaces;
|
||||||
|
|
||||||
|
public interface IAiDatumService
|
||||||
|
{
|
||||||
|
public Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid);
|
||||||
|
|
||||||
|
public Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty);
|
||||||
|
|
||||||
|
public Task UpdateSongAiScore(AiScoreDatum datum);
|
||||||
|
|
||||||
|
public Task InsertSongAiScore(AiScoreDatum datum);
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
using SharedProject.Models;
|
using SharedProject.Models;
|
||||||
using Swan.Mapping;
|
using Swan.Mapping;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Services;
|
||||||
@ -32,7 +31,7 @@ public class SongBestDatumService : ISongBestDatumService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.SongBestData.AddAsync(datum);
|
context.SongBestData.Add(datum);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +42,10 @@ public class SongBestDatumService : ISongBestDatumService
|
|||||||
|
|
||||||
var result = songbestDbData.Select(datum => datum.CopyPropertiesToNew<SongBestData>()).ToList();
|
var result = songbestDbData.Select(datum => datum.CopyPropertiesToNew<SongBestData>()).ToList();
|
||||||
|
|
||||||
|
var aiSectionBest = await context.AiScoreData.Where(datum => datum.Baid == baid)
|
||||||
|
.Include(datum => datum.AiSectionScoreData)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
var playLogs = await context.SongPlayData.Where(datum => datum.Baid == baid).ToListAsync();
|
var playLogs = await context.SongPlayData.Where(datum => datum.Baid == baid).ToListAsync();
|
||||||
foreach (var bestData in result)
|
foreach (var bestData in result)
|
||||||
{
|
{
|
||||||
@ -65,6 +68,16 @@ public class SongBestDatumService : ISongBestDatumService
|
|||||||
nameof(SongPlayDatum.DrumrollCount),
|
nameof(SongPlayDatum.DrumrollCount),
|
||||||
nameof(SongPlayDatum.ComboCount)
|
nameof(SongPlayDatum.ComboCount)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var aiSection = aiSectionBest.FirstOrDefault(datum => datum.Difficulty == bestData.Difficulty &&
|
||||||
|
datum.SongId == bestData.SongId);
|
||||||
|
if (aiSection is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bestData.AiSectionBestData = aiSection.AiSectionScoreData
|
||||||
|
.Select(datum => datum.CopyPropertiesToNew<AiSectionBestData>()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using TaikoLocalServer.Services.Interfaces;
|
namespace TaikoLocalServer.Services;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
|
||||||
|
|
||||||
class SongPlayDatumService : ISongPlayDatumService
|
class SongPlayDatumService : ISongPlayDatumService
|
||||||
{
|
{
|
||||||
@ -18,7 +16,7 @@ class SongPlayDatumService : ISongPlayDatumService
|
|||||||
|
|
||||||
public async Task AddSongPlayDatum(SongPlayDatum datum)
|
public async Task AddSongPlayDatum(SongPlayDatum datum)
|
||||||
{
|
{
|
||||||
await context.SongPlayData.AddAsync(datum);
|
context.SongPlayData.Add(datum);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using TaikoLocalServer.Services.Interfaces;
|
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Services;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
namespace TaikoLocalServer.Settings;
|
namespace TaikoLocalServer.Settings;
|
||||||
|
|
||||||
public class UrlSettings
|
public class ServerSettings
|
||||||
{
|
{
|
||||||
public string MuchaUrl { get; set; } = string.Empty;
|
public string MuchaUrl { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string GameUrl { get; set; } = string.Empty;
|
public string GameUrl { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public bool EnableMoreSongs { get; set; }
|
||||||
}
|
}
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Version>0.3.0-alpha</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -11,16 +12,18 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="6.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="6.0.9" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.7.22376.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-rc.1.22426.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.7.22376.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-rc.1.22426.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-preview.7.22376.2">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-rc.1.22426.7">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="protobuf-net" Version="3.1.17" />
|
<PackageReference Include="protobuf-net" Version="3.1.17" />
|
||||||
<PackageReference Include="protobuf-net.AspNetCore" Version="3.1.17" />
|
<PackageReference Include="protobuf-net.AspNetCore" Version="3.1.17" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0-dev-00281" />
|
||||||
|
<PackageReference Include="Serilog.Expressions" Version="3.4.1-dev-00095" />
|
||||||
|
<PackageReference Include="SharpZipLib" Version="1.4.0" />
|
||||||
<PackageReference Include="Swan.Core" Version="6.0.2-beta.90" />
|
<PackageReference Include="Swan.Core" Version="6.0.2-beta.90" />
|
||||||
<PackageReference Include="Swan.Logging" Version="6.0.2-beta.69" />
|
<PackageReference Include="Swan.Logging" Version="6.0.2-beta.69" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
@ -32,18 +35,24 @@
|
|||||||
<None Update="Certificates\cert.pfx">
|
<None Update="Certificates\cert.pfx">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Certificates\root.pfx">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Update="wwwroot\data\music_attribute.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Update="wwwroot\data\dan_data.json">
|
<Content Update="wwwroot\data\dan_data.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="wwwroot\data\intro_data.json">
|
<Content Update="wwwroot\data\intro_data.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\music_attribute.bin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\music_attribute.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Information"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,56 @@
|
|||||||
{
|
{
|
||||||
"UrlSettings": {
|
"ServerSettings": {
|
||||||
"MuchaUrl": "https://v402-front.mucha-prd.nbgi-amnet.jp:10122",
|
"MuchaUrl": "https://v402-front.mucha-prd.nbgi-amnet.jp:10122",
|
||||||
"GameUrl": "vsapi.taiko-p.jp"
|
"GameUrl": "vsapi.taiko-p.jp",
|
||||||
|
"EnableMoreSongs": false
|
||||||
},
|
},
|
||||||
|
|
||||||
"DbFileName" : "taiko.db3",
|
"DbFileName" : "taiko.db3",
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
"Serilog": {
|
||||||
|
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||||
|
"MinimumLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning",
|
"Override": {
|
||||||
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
|
"Microsoft": "Warning",
|
||||||
}
|
"Microsoft.AspNetCore": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Filter": [
|
||||||
|
{
|
||||||
|
"Name": "ByExcluding",
|
||||||
|
"Args": {
|
||||||
|
"expression": "@mt = 'An unhandled exception has occurred while executing the request.'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"WriteTo": [
|
||||||
|
{
|
||||||
|
"Name": "File",
|
||||||
|
"Args": { "path": "./Logs/log-.txt", "rollingInterval": "Day" }
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
|
|
||||||
"Kestrel": {
|
"Kestrel": {
|
||||||
"Endpoints": {
|
"Endpoints": {
|
||||||
"Server": {
|
"BaseServer": {
|
||||||
"Url": "http://0.0.0.0:5000"
|
"Url": "http://0.0.0.0:5000"
|
||||||
|
},
|
||||||
|
"AmAuthServer": {
|
||||||
|
"Url": "http://0.0.0.0:80"
|
||||||
|
},
|
||||||
|
"MuchaServer": {
|
||||||
|
"Url": "https://0.0.0.0:10122"
|
||||||
|
},
|
||||||
|
"GameServer1": {
|
||||||
|
"Url": "https://0.0.0.0:54430"
|
||||||
|
},
|
||||||
|
"GameServer2": {
|
||||||
|
"Url": "https://0.0.0.0:54431"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Certificates": {
|
"Certificates": {
|
||||||
|
@ -68,9 +68,8 @@
|
|||||||
FullWidth="true"
|
FullWidth="true"
|
||||||
AnchorOrigin="Origin.BottomCenter"
|
AnchorOrigin="Origin.BottomCenter"
|
||||||
TransformOrigin="Origin.TopCenter">
|
TransformOrigin="Origin.TopCenter">
|
||||||
<MudMenuItem Href="@($"Cards/{user.Baid}/TaikoMode")">Taiko Mode</MudMenuItem>
|
<MudMenuItem Href="@($"Cards/{user.Baid}/HighScores")">High Scores</MudMenuItem>
|
||||||
<MudMenuItem Href="@($"Cards/{user.Baid}/DaniDojo")">Dani Dojo</MudMenuItem>
|
<MudMenuItem Href="@($"Cards/{user.Baid}/DaniDojo")">Dani Dojo</MudMenuItem>
|
||||||
@*<MudMenuItem Href="@($"Cards/{user.Baid}/AIBattle")">AI Battle</MudMenuItem>*@
|
|
||||||
</MudMenu>
|
</MudMenu>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudCardActions>
|
</MudCardActions>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
@inject IGameDataService GameDataService
|
@inject IGameDataService GameDataService
|
||||||
@inject HttpClient Client
|
@inject HttpClient Client
|
||||||
|
|
||||||
@page "/Cards/{baid:int}/TaikoMode"
|
@page "/Cards/{baid:int}/HighScores"
|
||||||
|
|
||||||
<MudBreadcrumbs Items="breadcrumbs" Class="px-0"></MudBreadcrumbs>
|
<MudBreadcrumbs Items="breadcrumbs" Class="px-0"></MudBreadcrumbs>
|
||||||
|
|
||||||
<h1>Taiko Mode</h1>
|
<h1>High Scores</h1>
|
||||||
<MudText Typo="Typo.caption">Card: @Baid</MudText>
|
<MudText Typo="Typo.caption">Card: @Baid</MudText>
|
||||||
|
|
||||||
<MudGrid Class="my-8">
|
<MudGrid Class="my-8">
|
||||||
@ -29,7 +29,7 @@
|
|||||||
Icon="@GetDifficultyIcon(difficulty)">
|
Icon="@GetDifficultyIcon(difficulty)">
|
||||||
@if (songBestDataMap.ContainsKey(difficulty))
|
@if (songBestDataMap.ContainsKey(difficulty))
|
||||||
{
|
{
|
||||||
<MudDataGrid Items="@songBestDataMap[difficulty]"
|
<MudDataGrid Items="@songBestDataMap[difficulty]" RowClick="(DataGridRowClickEventArgs<SongBestData> _) => { return;}"
|
||||||
ColumnResizeMode="ResizeMode.None" RowsPerPage="25" Elevation="0">
|
ColumnResizeMode="ResizeMode.None" RowsPerPage="25" Elevation="0">
|
||||||
<Columns>
|
<Columns>
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song" StickyLeft="true">
|
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song" StickyLeft="true">
|
||||||
@ -68,7 +68,7 @@
|
|||||||
</MudChip>
|
</MudChip>
|
||||||
</CellTemplate>
|
</CellTemplate>
|
||||||
</Column>
|
</Column>
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestScore)" Title="Best Score"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.BestScore)" Title="Best Score" />
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestCrown)" Title="Best Crown">
|
<Column T="SongBestData" Field="@nameof(SongBestData.BestCrown)" Title="Best Crown">
|
||||||
<CellTemplate>
|
<CellTemplate>
|
||||||
<img src="@($"/images/crown_{context.Item.BestCrown}.png")" alt="@(GetCrownText(context.Item.BestCrown))" title="@(GetCrownText(context.Item.BestCrown))" style="@IconStyle" />
|
<img src="@($"/images/crown_{context.Item.BestCrown}.png")" alt="@(GetCrownText(context.Item.BestCrown))" title="@(GetCrownText(context.Item.BestCrown))" style="@IconStyle" />
|
||||||
@ -82,13 +82,73 @@
|
|||||||
}
|
}
|
||||||
</CellTemplate>
|
</CellTemplate>
|
||||||
</Column>
|
</Column>
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good" Sortable="false"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good" Sortable="false" />
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="OK" Sortable="false"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="OK" Sortable="false" />
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Bad" Sortable="false"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Bad" Sortable="false" />
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drumroll" Sortable="false"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drumroll" Sortable="false"/>
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="MAX Combo" Sortable="false"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="MAX Combo" Sortable="false" />
|
||||||
<Column T="SongBestData" Field="@nameof(SongBestData.LastPlayTime)" Title="Last Played"/>
|
<Column T="SongBestData" Field="@nameof(SongBestData.ShowAiData)" Title="AI Battle Data">
|
||||||
|
<CellTemplate>
|
||||||
|
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||||
|
OnClick="@(() => ToggleShowAiData(context.Item))"
|
||||||
|
Disabled="@(!IsAiDataPresent(context.Item))">
|
||||||
|
@(context.Item.ShowAiData ? "Hide" : "Show")
|
||||||
|
</MudButton>
|
||||||
|
</CellTemplate>
|
||||||
|
</Column>
|
||||||
|
<Column T="SongBestData" Field="@nameof(SongBestData.LastPlayTime)" Title="Last Played" Hideable="true" />
|
||||||
|
<Column T="SongBestData" Field="@nameof(SongBestData.PlayCount)" Title="Total Plays" Hideable="true" />
|
||||||
|
<Column T="SongBestData" Field="@nameof(SongBestData.ClearCount)" Title="Total Clears" Hideable="true" />
|
||||||
|
<Column T="SongBestData" Field="@nameof(SongBestData.FullComboCount)" Title="Total Full Combos" Hideable="true" />
|
||||||
|
<Column T="SongBestData" Field="@nameof(SongBestData.PerfectCount)" Title="Total Donderful Combos" Hideable="true" />
|
||||||
</Columns>
|
</Columns>
|
||||||
|
<ChildRowContent>
|
||||||
|
@if (context.Item.ShowAiData)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td colspan="1" class="pa-3 ai-battle-td">
|
||||||
|
<MudText Typo="Typo.body2" Style="font-weight: bold">
|
||||||
|
AI Battle Data
|
||||||
|
</MudText>
|
||||||
|
</td>
|
||||||
|
<td colspan="16">
|
||||||
|
<MudTable Elevation="0" ReadOnly="true"
|
||||||
|
Items="@context.Item.AiSectionBestData" Context="aiSectionContext">
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>Section No.</MudTh>
|
||||||
|
<MudTh>Result</MudTh>
|
||||||
|
<MudTh>Score</MudTh>
|
||||||
|
<MudTh>Crown</MudTh>
|
||||||
|
<MudTh>Good</MudTh>
|
||||||
|
<MudTh>OK</MudTh>
|
||||||
|
<MudTh>Bad</MudTh>
|
||||||
|
<MudTh>Drumroll</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd>@(aiSectionContext.SectionIndex + 1)</MudTd>
|
||||||
|
<MudTd>
|
||||||
|
@if (@aiSectionContext.IsWin) {
|
||||||
|
<img src="@($"/images/ai_Win.png")" alt="Win" title="Win" style="@IconStyle" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<img src="@($"/images/ai_Lose.png")" alt="Lose" title="Lose" style="@IconStyle" />
|
||||||
|
}
|
||||||
|
</MudTd>
|
||||||
|
<MudTd>@aiSectionContext.Score</MudTd>
|
||||||
|
<MudTd>
|
||||||
|
<img src="@($"/images/ai_crown_{aiSectionContext.Crown}.png")" alt="@(GetCrownText(aiSectionContext.Crown))" title="@(GetCrownText(aiSectionContext.Crown))" style="@IconStyle" />
|
||||||
|
</MudTd>
|
||||||
|
<MudTd>@aiSectionContext.GoodCount</MudTd>
|
||||||
|
<MudTd>@aiSectionContext.OkCount</MudTd>
|
||||||
|
<MudTd>@aiSectionContext.MissCount</MudTd>
|
||||||
|
<MudTd>@aiSectionContext.DrumrollCount</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
</MudTable>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</ChildRowContent>
|
||||||
<PagerContent>
|
<PagerContent>
|
||||||
<MudDataGridPager T="SongBestData"/>
|
<MudDataGridPager T="SongBestData"/>
|
||||||
</PagerContent>
|
</PagerContent>
|
@ -1,12 +1,15 @@
|
|||||||
namespace TaikoWebUI.Pages;
|
using static MudBlazor.Colors;
|
||||||
|
using System;
|
||||||
|
|
||||||
public partial class TaikoMode
|
namespace TaikoWebUI.Pages;
|
||||||
|
|
||||||
|
public partial class HighScores
|
||||||
{
|
{
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int Baid { get; set; }
|
public int Baid { get; set; }
|
||||||
|
|
||||||
private const string IconStyle = "width:25px; height:25px;";
|
private const string IconStyle = "width:25px; height:25px;";
|
||||||
|
|
||||||
private SongBestResponse? response;
|
private SongBestResponse? response;
|
||||||
|
|
||||||
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
||||||
@ -41,7 +44,7 @@ public partial class TaikoMode
|
|||||||
|
|
||||||
|
|
||||||
breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true));
|
breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true));
|
||||||
breadcrumbs.Add(new BreadcrumbItem("Taiko Mode", href: $"/Cards/{Baid}/TaikoMode", disabled: false));
|
breadcrumbs.Add(new BreadcrumbItem("High Scores", href: $"/Cards/{Baid}/HighScores", disabled: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnFavoriteToggled(SongBestData data)
|
private async Task OnFavoriteToggled(SongBestData data)
|
||||||
@ -133,7 +136,19 @@ public partial class TaikoMode
|
|||||||
SongGenre.Variety => "background: #1dc83b; color: #fff",
|
SongGenre.Variety => "background: #1dc83b; color: #fff",
|
||||||
SongGenre.Classical => "background: #bfa356",
|
SongGenre.Classical => "background: #bfa356",
|
||||||
_ => ""
|
_ => ""
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToggleShowAiData(SongBestData data)
|
||||||
|
{
|
||||||
|
data.ShowAiData = !data.ShowAiData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsAiDataPresent(SongBestData data)
|
||||||
|
{
|
||||||
|
var aiData = data.AiSectionBestData;
|
||||||
|
|
||||||
|
return aiData.Count > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ builder.RootComponents.Add<HeadOutlet>("head::after");
|
|||||||
|
|
||||||
builder.Services.AddSingleton(sp => new HttpClient
|
builder.Services.AddSingleton(sp => new HttpClient
|
||||||
{
|
{
|
||||||
BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseUrl"))
|
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
||||||
});
|
});
|
||||||
builder.Services.AddMudServices();
|
builder.Services.AddMudServices();
|
||||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
||||||
@ -15,10 +15,6 @@ builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
|||||||
var host = builder.Build();
|
var host = builder.Build();
|
||||||
|
|
||||||
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
|
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
|
||||||
#if DEBUG
|
await gameDataService.InitializeAsync(builder.HostEnvironment.BaseAddress);
|
||||||
await gameDataService.InitializeAsync(builder.Configuration.GetValue<string>("DataBaseUrl"));
|
|
||||||
#else
|
|
||||||
await gameDataService.InitializeAsync(builder.Configuration.GetValue<string>("BaseUrl"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
await host.RunAsync();
|
await host.RunAsync();
|
@ -1,4 +1,7 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.Json;
|
||||||
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using Swan.Mapping;
|
using Swan.Mapping;
|
||||||
using TaikoWebUI.Shared.Models;
|
using TaikoWebUI.Shared.Models;
|
||||||
|
|
||||||
@ -27,16 +30,13 @@ public class GameDataService : IGameDataService
|
|||||||
|
|
||||||
public async Task InitializeAsync(string dataBaseUrl)
|
public async Task InitializeAsync(string dataBaseUrl)
|
||||||
{
|
{
|
||||||
var musicInfo = await client.GetFromJsonAsync<MusicInfo>($"{dataBaseUrl}/data/musicinfo.json");
|
dataBaseUrl = dataBaseUrl.TrimEnd('/');
|
||||||
var wordList = await client.GetFromJsonAsync<WordList>($"{dataBaseUrl}/data/wordlist.json");
|
var musicInfo = await GetData<MusicInfo>(dataBaseUrl, Constants.MUSIC_INFO_BASE_NAME);
|
||||||
var musicOrder = await client.GetFromJsonAsync<MusicOrder>($"{dataBaseUrl}/data/music_order.json");
|
var wordList = await GetData<WordList>(dataBaseUrl, Constants.WORD_LIST_BASE_NAME);
|
||||||
|
var musicOrder = await GetData<MusicOrder>(dataBaseUrl, Constants.MUSIC_ORDER_BASE_NAME);
|
||||||
var danData = await client.GetFromJsonAsync<List<DanData>>($"{dataBaseUrl}/data/dan_data.json");
|
var danData = await client.GetFromJsonAsync<List<DanData>>($"{dataBaseUrl}/data/dan_data.json");
|
||||||
|
|
||||||
musicInfo.ThrowIfNull();
|
|
||||||
wordList.ThrowIfNull();
|
|
||||||
musicOrder.ThrowIfNull();
|
|
||||||
danData.ThrowIfNull();
|
danData.ThrowIfNull();
|
||||||
|
|
||||||
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
||||||
|
|
||||||
// To prevent duplicate entries in wordlist
|
// To prevent duplicate entries in wordlist
|
||||||
@ -52,6 +52,36 @@ public class GameDataService : IGameDataService
|
|||||||
await Task.Run(() => InitializeTitles(dict));
|
await Task.Run(() => InitializeTitles(dict));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<T> GetData<T>(string dataBaseUrl, string fileBaseName) where T : notnull
|
||||||
|
{
|
||||||
|
T? data;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data = await client.GetFromJsonAsync<T>($"{dataBaseUrl}/data/{fileBaseName}.json");
|
||||||
|
data.ThrowIfNull();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
if (e.StatusCode != HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
await using var compressed = await client.GetStreamAsync($"{dataBaseUrl}/data/{fileBaseName}.bin");
|
||||||
|
await using var gZipInputStream = new GZipInputStream(compressed);
|
||||||
|
using var decompressed = new MemoryStream();
|
||||||
|
|
||||||
|
// Decompress
|
||||||
|
await gZipInputStream.CopyToAsync(decompressed);
|
||||||
|
|
||||||
|
// Reset stream for reading
|
||||||
|
decompressed.Position = 0;
|
||||||
|
data = await JsonSerializer.DeserializeAsync<T>(decompressed);
|
||||||
|
data.ThrowIfNull();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string GetMusicNameBySongId(uint songId)
|
public string GetMusicNameBySongId(uint songId)
|
||||||
{
|
{
|
||||||
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.SongName : string.Empty;
|
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.SongName : string.Empty;
|
||||||
|
@ -9,4 +9,8 @@ public static class Constants
|
|||||||
public const int COSTUME_PUCHI_MAX = 129;
|
public const int COSTUME_PUCHI_MAX = 129;
|
||||||
public const int COSTUME_COLOR_MAX = 63;
|
public const int COSTUME_COLOR_MAX = 63;
|
||||||
public const int PLAYER_TITLE_MAX = 750;
|
public const int PLAYER_TITLE_MAX = 750;
|
||||||
|
|
||||||
|
public const string MUSIC_INFO_BASE_NAME = "musicinfo";
|
||||||
|
public const string WORD_LIST_BASE_NAME = "wordlist";
|
||||||
|
public const string MUSIC_ORDER_BASE_NAME = "music_order";
|
||||||
}
|
}
|
@ -8,9 +8,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autocomplete.Clients" Version="1.1.0" />
|
<PackageReference Include="Autocomplete.Clients" Version="1.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.7" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.9" PrivateAssets="all" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.0.15" />
|
<PackageReference Include="MudBlazor" Version="6.0.15" />
|
||||||
|
<PackageReference Include="SharpZipLib" Version="1.4.0" />
|
||||||
<PackageReference Include="Swan.Core" Version="6.0.2-beta.90" />
|
<PackageReference Include="Swan.Core" Version="6.0.2-beta.90" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@ -19,7 +20,19 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Update="wwwroot\appsettings.json">
|
<Content Update="wwwroot\data\musicinfo.bin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\music_order.bin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\wordlist.bin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\music_attribute.bin">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\data\music_order.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="wwwroot\data\musicinfo.json">
|
<Content Update="wwwroot\data\musicinfo.json">
|
||||||
@ -28,9 +41,6 @@
|
|||||||
<Content Update="wwwroot\data\wordlist.json">
|
<Content Update="wwwroot\data\wordlist.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Update="wwwroot\data\music_order.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"DataBaseUrl": "http://localhost:5000"
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"BaseUrl": "http://localhost:5000"
|
|
||||||
}
|
|
BIN
TaikoWebUI/wwwroot/images/ai_Lose.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_Lose.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
TaikoWebUI/wwwroot/images/ai_Win.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_Win.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
TaikoWebUI/wwwroot/images/ai_crown_Clear.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_crown_Clear.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
TaikoWebUI/wwwroot/images/ai_crown_Dondaful.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_crown_Dondaful.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
TaikoWebUI/wwwroot/images/ai_crown_Gold.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_crown_Gold.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
TaikoWebUI/wwwroot/images/ai_crown_None.png
Normal file
BIN
TaikoWebUI/wwwroot/images/ai_crown_None.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
@ -29,4 +29,23 @@
|
|||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.columns-panel {
|
||||||
|
column-count: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-battle-td {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 99;
|
||||||
|
background: #FAFAFA;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 600px) {
|
||||||
|
.ai-battle-td {
|
||||||
|
display: revert;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user