Compare commits

..

No commits in common. "master" and "1.0.0-rc.1" have entirely different histories.

18 changed files with 104 additions and 154 deletions

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\bin</BaseOutputPath> <BaseOutputPath>..\bin</BaseOutputPath>

View File

@ -154,8 +154,11 @@ namespace Milimoe.FunGame.Server.Controller
} }
} }
if (ValidateClientParameters != null) if (ValidateClientParameters is null)
{ {
return "";
}
foreach (Func<SocketObject, string> handler in ValidateClientParameters.GetInvocationList().Cast<Func<SocketObject, string>>()) foreach (Func<SocketObject, string> handler in ValidateClientParameters.GetInvocationList().Cast<Func<SocketObject, string>>())
{ {
string msg = handler(obj); string msg = handler(obj);
@ -165,8 +168,6 @@ namespace Milimoe.FunGame.Server.Controller
ServerHelper.WriteLine(msg, InvokeMessageType.Error); ServerHelper.WriteLine(msg, InvokeMessageType.Error);
} }
} }
}
return builder.ToString().Trim(); return builder.ToString().Trim();
} }
} }

View File

@ -315,7 +315,7 @@ namespace Milimoe.FunGame.Server.Controller
if (SQLHelper.Result == SQLResult.Success) if (SQLHelper.Result == SQLResult.Success)
{ {
ServerHelper.WriteLine("[CreateRoom] Master: " + user.Username + " RoomID: " + roomid); ServerHelper.WriteLine("[CreateRoom] Master: " + user.Username + " RoomID: " + roomid);
DataRow? dr = SQLHelper.ExecuteDataRow(RoomQuery.Select_RoomByRoomId(SQLHelper, roomid)); DataRow? dr = SQLHelper.ExecuteDataRow(RoomQuery.Select_IsExistRoom(SQLHelper, roomid));
if (dr != null) if (dr != null)
{ {
room = Factory.GetRoom(dr, user); room = Factory.GetRoom(dr, user);
@ -355,7 +355,7 @@ namespace Milimoe.FunGame.Server.Controller
string roomid = DataRequest.GetDictionaryJsonObject<string>(requestData, "roomid") ?? "-1"; string roomid = DataRequest.GetDictionaryJsonObject<string>(requestData, "roomid") ?? "-1";
bool isMaster = DataRequest.GetDictionaryJsonObject<bool>(requestData, "isMaster"); bool isMaster = DataRequest.GetDictionaryJsonObject<bool>(requestData, "isMaster");
if (roomid != "-1" && FunGameSystem.RoomList.Exists(roomid)) if (roomid != "-1" && FunGameSystem.RoomList.IsExist(roomid))
{ {
Room room = FunGameSystem.RoomList[roomid]; Room room = FunGameSystem.RoomList[roomid];
RoomEventArgs eventArgs = new(room); RoomEventArgs eventArgs = new(room);
@ -403,7 +403,7 @@ namespace Milimoe.FunGame.Server.Controller
} }
else if (SQLHelper != null) else if (SQLHelper != null)
{ {
SQLHelper.ExecuteDataSet(RoomQuery.Select_RoomByRoomId(SQLHelper, roomid)); SQLHelper.ExecuteDataSet(RoomQuery.Select_IsExistRoom(SQLHelper, roomid));
if (SQLHelper.Success) if (SQLHelper.Success)
{ {
FunGameSystem.RoomList.IntoRoom(roomid, Server.User); FunGameSystem.RoomList.IntoRoom(roomid, Server.User);
@ -897,7 +897,7 @@ namespace Milimoe.FunGame.Server.Controller
string newModule = DataRequest.GetDictionaryJsonObject<string>(requestData, "module") ?? ""; string newModule = DataRequest.GetDictionaryJsonObject<string>(requestData, "module") ?? "";
string newMap = DataRequest.GetDictionaryJsonObject<string>(requestData, "map") ?? ""; string newMap = DataRequest.GetDictionaryJsonObject<string>(requestData, "map") ?? "";
User user = Server.User; User user = Server.User;
if (roomid != "-1" && FunGameSystem.RoomList.Exists(roomid)) if (roomid != "-1" && FunGameSystem.RoomList.IsExist(roomid))
{ {
Room room = FunGameSystem.RoomList[roomid]; Room room = FunGameSystem.RoomList[roomid];
RoomEventArgs eventArgs = new(room); RoomEventArgs eventArgs = new(room);
@ -973,7 +973,7 @@ namespace Milimoe.FunGame.Server.Controller
string roomid = DataRequest.GetDictionaryJsonObject<string>(requestData, "roomid") ?? "-1"; string roomid = DataRequest.GetDictionaryJsonObject<string>(requestData, "roomid") ?? "-1";
User newMaster = DataRequest.GetDictionaryJsonObject<User>(requestData, "newMaster") ?? Factory.GetUser(); User newMaster = DataRequest.GetDictionaryJsonObject<User>(requestData, "newMaster") ?? Factory.GetUser();
if (roomid != "-1" && FunGameSystem.RoomList.Exists(roomid) && newMaster.Id != 0) if (roomid != "-1" && FunGameSystem.RoomList.IsExist(roomid) && newMaster.Id != 0)
{ {
Room room = FunGameSystem.RoomList[roomid]; Room room = FunGameSystem.RoomList[roomid];
RoomEventArgs eventArgs = new(room); RoomEventArgs eventArgs = new(room);
@ -1393,7 +1393,7 @@ namespace Milimoe.FunGame.Server.Controller
{ {
Goods goods = store.Goods[goodsId]; Goods goods = store.Goods[goodsId];
int count = counts[goodsId]; int count = counts[goodsId];
if (goods.Stock != -1 && count > goods.Stock) if (count > goods.Stock)
{ {
result = false; result = false;
buyResult.Add($"购买失败,原因:库存不足,当前库存为:{goods.Stock},购买数量:{count}。"); buyResult.Add($"购买失败,原因:库存不足,当前库存为:{goods.Stock},购买数量:{count}。");
@ -1421,11 +1421,11 @@ namespace Milimoe.FunGame.Server.Controller
else else
{ {
subResult = false; subResult = false;
buyResult.Add($"购买失败,原因:需要花费 {totalPrice} {General.GameplayEquilibriumConstant.InGameMaterial},但是您只有 {user.Inventory.Materials} {General.GameplayEquilibriumConstant.InGameMaterial}。"); buyResult.Add($"购买失败,原因:需要花费 {totalPrice} {General.GameplayEquilibriumConstant.InGameMaterial},但是您只有 {user.Inventory.Credits} {General.GameplayEquilibriumConstant.InGameMaterial}。");
} }
if (subResult) if (subResult)
{ {
if (goods.Stock != -1) goods.Stock -= count; goods.Stock -= count;
totalCost += totalPrice; totalCost += totalPrice;
ProcessStoreBuy(goods, useCredits, price, count, user); ProcessStoreBuy(goods, useCredits, price, count, user);
buyResult.Add($"成功消费:{totalPrice} {currency},购买了 {count} 个 {goods.Name}。"); buyResult.Add($"成功消费:{totalPrice} {currency},购买了 {count} 个 {goods.Name}。");
@ -1524,7 +1524,7 @@ namespace Milimoe.FunGame.Server.Controller
try try
{ {
User? buyer = SQLHelper.GetUserById(userid, true); User? buyer = SQLHelper.GetUserById(userid, true);
User? itemUser = SQLHelper.GetUserById(marketItem.User, true); User? itemUser = SQLHelper.GetUserById(marketItem.User.Id, true);
if (itemUser != null && buyer != null && itemUser.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item) if (itemUser != null && buyer != null && itemUser.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item)
{ {
if (buyer.Inventory.Credits >= price) if (buyer.Inventory.Credits >= price)
@ -1631,7 +1631,7 @@ namespace Milimoe.FunGame.Server.Controller
Guid itemGuid = DataRequest.GetDictionaryJsonObject<Guid>(requestData, "itemGuid"); Guid itemGuid = DataRequest.GetDictionaryJsonObject<Guid>(requestData, "itemGuid");
long userid = DataRequest.GetDictionaryJsonObject<long>(requestData, "userid"); long userid = DataRequest.GetDictionaryJsonObject<long>(requestData, "userid");
Character[] targets = DataRequest.GetDictionaryJsonObject<Character[]>(requestData, "targets") ?? []; Character[] targets = DataRequest.GetDictionaryJsonObject<Character[]>(requestData, "targets") ?? [];
int useCount = DataRequest.GetDictionaryJsonObject<int>(requestData, "useCount"); long useCount = DataRequest.GetDictionaryJsonObject<long>(requestData, "useCount");
GeneralEventArgs eventArgs = new(itemGuid, userid, targets, useCount); GeneralEventArgs eventArgs = new(itemGuid, userid, targets, useCount);
FunGameSystem.ServerPluginLoader?.OnBeforeUseItemEvent(this, eventArgs); FunGameSystem.ServerPluginLoader?.OnBeforeUseItemEvent(this, eventArgs);
@ -1646,16 +1646,16 @@ namespace Milimoe.FunGame.Server.Controller
User? user = SQLHelper.GetUserById(userid, true); User? user = SQLHelper.GetUserById(userid, true);
if (user != null && user.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item) if (user != null && user.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item)
{ {
// 暂定标准实现是传这个参数,作用目标 // 暂定标准实现是传这个参数,作用目标和使用数量
Dictionary<string, object> args = new() Dictionary<string, object> args = new()
{ {
{ "targets", targets } { "targets", targets },
{ "useCount", useCount }
}; };
bool used = item.UseItem(user, useCount, args); bool used = item.UseItem(args);
if (used) if (used)
{ {
SQLHelper.UpdateInventory(user.Inventory); SQLHelper.UpdateInventory(user.Inventory);
result = true;
} }
} }
if (result) if (result)
@ -1698,7 +1698,6 @@ namespace Milimoe.FunGame.Server.Controller
user.Inventory.Credits += reward; user.Inventory.Credits += reward;
item.EntityState = EntityState.Deleted; item.EntityState = EntityState.Deleted;
SQLHelper.UpdateInventory(user.Inventory); SQLHelper.UpdateInventory(user.Inventory);
result = true;
} }
} }
if (result) if (result)
@ -1722,7 +1721,6 @@ namespace Milimoe.FunGame.Server.Controller
Guid itemGuid = DataRequest.GetDictionaryJsonObject<Guid>(requestData, "itemGuid"); Guid itemGuid = DataRequest.GetDictionaryJsonObject<Guid>(requestData, "itemGuid");
long userid = DataRequest.GetDictionaryJsonObject<long>(requestData, "userid"); long userid = DataRequest.GetDictionaryJsonObject<long>(requestData, "userid");
double price = DataRequest.GetDictionaryJsonObject<double>(requestData, "price"); double price = DataRequest.GetDictionaryJsonObject<double>(requestData, "price");
int stock = DataRequest.GetDictionaryJsonObject<int>(requestData, "stock");
User? user = SQLHelper?.GetUserById(userid, true); User? user = SQLHelper?.GetUserById(userid, true);
if (user != null && user.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item) if (user != null && user.Inventory.Items.FirstOrDefault(i => i.Guid == itemGuid) is Item item)
{ {
@ -1732,7 +1730,7 @@ namespace Milimoe.FunGame.Server.Controller
} }
else else
{ {
SQLHelper?.AddMarketItem(itemGuid, userid, price, stock); SQLHelper?.AddMarketItem(itemGuid, userid, price);
if (SQLHelper?.Success ?? false) if (SQLHelper?.Success ?? false)
{ {
msg = ""; msg = "";
@ -2019,13 +2017,14 @@ namespace Milimoe.FunGame.Server.Controller
} }
} }
if (msg == "") if (msg != "")
{ {
offer = SQLHelper.GetOffer(offerId); offer = SQLHelper.GetOffer(offerId);
if (offer != null) if (offer != null)
{ {
SQLHelper.Commit(); SQLHelper.Commit();
resultData.Add("offer", offer); resultData.Add("offer", offer);
msg = "";
} }
} }
} }

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\bin</BaseOutputPath> <BaseOutputPath>..\bin</BaseOutputPath>
@ -39,8 +39,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.0" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.4" />
<PackageReference Include="MySql.Data" Version="9.5.0" /> <PackageReference Include="MySql.Data" Version="9.3.0" />
<PackageReference Include="System.Text.Json" Version="9.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -16,7 +16,7 @@ HTTPListener? WebSocketListener = null;
ServerHelper.WriteLine("正在读取配置文件并初始化服务 . . ."); ServerHelper.WriteLine("正在读取配置文件并初始化服务 . . .");
// 检查是否存在配置文件 // 检查是否存在配置文件
if (!INIHelper.INIFileExists()) if (!INIHelper.ExistINIFile())
{ {
ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . ."); ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . .");
INIHelper.Init(Config.FunGameType); INIHelper.Init(Config.FunGameType);

View File

@ -20,7 +20,7 @@ namespace Milimoe.FunGame.Server.Models
{ {
if (Name == "" && DataSource == "" && Port == "" && DataBase == "" && User == "" && Password == "") if (Name == "" && DataSource == "" && Port == "" && DataBase == "" && User == "" && Password == "")
{ {
if (INIHelper.INIFileExists()) if (INIHelper.ExistINIFile())
{ {
DataSource = INIHelper.ReadINI("MySQL", "DBServer"); DataSource = INIHelper.ReadINI("MySQL", "DBServer");
Port = INIHelper.ReadINI("MySQL", "DBPort"); Port = INIHelper.ReadINI("MySQL", "DBPort");
@ -41,7 +41,7 @@ namespace Milimoe.FunGame.Server.Models
{ {
if (DataSource == "") if (DataSource == "")
{ {
if (INIHelper.INIFileExists()) if (INIHelper.ExistINIFile())
{ {
DataSource = INIHelper.ReadINI("SQLite", "DataSource"); DataSource = INIHelper.ReadINI("SQLite", "DataSource");
} }

View File

@ -73,7 +73,7 @@ namespace Milimoe.FunGame.Server.Services
internal static (string Msg, RegInvokeType Type, bool Success) HandleNoVerifyCode(SQLHelper sqlHelper, MailSender? mailSender, string username, string email, string clientName) internal static (string Msg, RegInvokeType Type, bool Success) HandleNoVerifyCode(SQLHelper sqlHelper, MailSender? mailSender, string username, string email, string clientName)
{ {
// 先检查账号是否重复 // 先检查账号是否重复
sqlHelper.ExecuteDataSet(UserQuery.Select_UserByUsername(sqlHelper, username)); sqlHelper.ExecuteDataSet(UserQuery.Select_IsExistUsername(sqlHelper, username));
if (sqlHelper.Result == SQLResult.Success) if (sqlHelper.Result == SQLResult.Success)
{ {
ServerHelper.WriteLine(clientName + " 账号已被注册"); ServerHelper.WriteLine(clientName + " 账号已被注册");
@ -81,7 +81,7 @@ namespace Milimoe.FunGame.Server.Services
} }
// 检查邮箱是否重复 // 检查邮箱是否重复
sqlHelper.ExecuteDataSet(UserQuery.Select_UserByEmail(sqlHelper, email)); sqlHelper.ExecuteDataSet(UserQuery.Select_IsExistEmail(sqlHelper, email));
if (sqlHelper.Result == SQLResult.Success) if (sqlHelper.Result == SQLResult.Success)
{ {
ServerHelper.WriteLine(clientName + " 邮箱已被注册"); ServerHelper.WriteLine(clientName + " 邮箱已被注册");

View File

@ -142,7 +142,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using MySqlCommand command = new(script, _connection); using MySqlCommand command = new(script, _connection);
command.CommandType = CommandType; command.CommandType = CommandType;
foreach (KeyValuePair<string, object> param in Parameters) foreach (KeyValuePair<string, object> param in Parameters)
@ -206,7 +206,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using MySqlCommand command = new(script, _connection); using MySqlCommand command = new(script, _connection);
command.CommandType = CommandType; command.CommandType = CommandType;
foreach (KeyValuePair<string, object> param in Parameters) foreach (KeyValuePair<string, object> param in Parameters)
@ -270,7 +270,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using MySqlCommand command = new(script, _connection) using MySqlCommand command = new(script, _connection)
{ {
@ -287,6 +287,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
{ {
SelectCommand = command SelectCommand = command
}; };
_dataSet = new();
_affectedRows = adapter.Fill(_dataSet); _affectedRows = adapter.Fill(_dataSet);
if (localTransaction) Commit(); if (localTransaction) Commit();
@ -334,7 +335,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using MySqlCommand command = new(script, _connection) using MySqlCommand command = new(script, _connection)
{ {
@ -351,6 +352,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
{ {
SelectCommand = command SelectCommand = command
}; };
_dataSet = new();
_affectedRows = await adapter.FillAsync(_dataSet); _affectedRows = await adapter.FillAsync(_dataSet);
if (localTransaction) Commit(); if (localTransaction) Commit();
@ -480,7 +482,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
_result = SQLResult.NotFound; _result = SQLResult.NotFound;
_affectedRows = 0; _affectedRows = 0;
_lastInsertId = 0; _lastInsertId = 0;
_dataSet = new(); DataSet.Clear();
} }
} }
} }

View File

@ -140,7 +140,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using SqliteCommand command = new(script, _connection); using SqliteCommand command = new(script, _connection);
command.CommandType = CommandType; command.CommandType = CommandType;
foreach (KeyValuePair<string, object> param in Parameters) foreach (KeyValuePair<string, object> param in Parameters)
@ -206,7 +206,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using SqliteCommand command = new(script, _connection); using SqliteCommand command = new(script, _connection);
command.CommandType = CommandType; command.CommandType = CommandType;
foreach (KeyValuePair<string, object> param in Parameters) foreach (KeyValuePair<string, object> param in Parameters)
@ -272,7 +272,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using SqliteCommand command = new(script, _connection) using SqliteCommand command = new(script, _connection)
{ {
CommandType = CommandType CommandType = CommandType
@ -285,6 +285,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
ReSet(); ReSet();
using SqliteDataReader reader = command.ExecuteReader(); using SqliteDataReader reader = command.ExecuteReader();
_dataSet = new();
do do
{ {
DataTable table = new(); DataTable table = new();
@ -337,7 +338,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
OpenConnection(); OpenConnection();
Script = script; Script = script;
ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api, LogLevel.Debug); ServerHelper.WriteLine("SQLQuery -> " + script, InvokeMessageType.Api);
using SqliteCommand command = new(script, _connection) using SqliteCommand command = new(script, _connection)
{ {
CommandType = CommandType CommandType = CommandType
@ -350,6 +351,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
ReSet(); ReSet();
using SqliteDataReader reader = await command.ExecuteReaderAsync(); using SqliteDataReader reader = await command.ExecuteReaderAsync();
_dataSet = new();
do do
{ {
DataTable table = new(); DataTable table = new();
@ -484,7 +486,7 @@ namespace Milimoe.FunGame.Server.Services.DataUtility
_result = SQLResult.NotFound; _result = SQLResult.NotFound;
_affectedRows = 0; _affectedRows = 0;
_lastInsertId = 0; _lastInsertId = 0;
_dataSet = new(); DataSet.Clear();
} }
} }
} }

View File

@ -85,7 +85,7 @@ namespace Milimoe.FunGame.Server.Services
SQLMode.SQLite => new SQLiteHelper(), SQLMode.SQLite => new SQLiteHelper(),
_ => null, _ => null,
}); });
if (INIHelper.INIFileExists()) if (INIHelper.ExistINIFile())
{ {
string useMySQL = INIHelper.ReadINI("MySQL", "UseMySQL").Trim(); string useMySQL = INIHelper.ReadINI("MySQL", "UseMySQL").Trim();
string useSQLite = INIHelper.ReadINI("SQLite", "UseSQLite").Trim(); string useSQLite = INIHelper.ReadINI("SQLite", "UseSQLite").Trim();
@ -239,21 +239,6 @@ namespace Milimoe.FunGame.Server.Services
} }
} }
/// <summary>
/// Web API 启动完成回调
/// </summary>
public static void OnWebAPIStarted(params object[] objs)
{
try
{
WebAPIPluginLoader?.OnWebAPIStarted(objs);
}
catch (Exception e)
{
ServerHelper.Error(e);
}
}
/// <summary> /// <summary>
/// 服务器启动登记 /// 服务器启动登记
/// </summary> /// </summary>

View File

@ -72,12 +72,10 @@ namespace Milimoe.FunGame.Server.Services
{ {
Console.WriteLine("\r" + GetPrefix(InvokeMessageType.Error, LogLevel.Error) + e.Message + "\n" + e.StackTrace); Console.WriteLine("\r" + GetPrefix(InvokeMessageType.Error, LogLevel.Error) + e.Message + "\n" + e.StackTrace);
Type(); Type();
TXTHelper.AppendErrorLog(e);
} }
public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) public static void Write(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true)
{ {
if (msg.Trim() == "") return;
if (type == InvokeMessageType.Warning) if (type == InvokeMessageType.Warning)
{ {
level = LogLevel.Warning; level = LogLevel.Warning;
@ -88,14 +86,14 @@ namespace Milimoe.FunGame.Server.Services
} }
if (!useLevel || (useLevel && (int)level >= (int)Config.LogLevelValue)) if (!useLevel || (useLevel && (int)level >= (int)Config.LogLevelValue))
{ {
Console.Write("\r" + GetPrefix(type, level) + msg + "> "); if (msg.Trim() != "") Console.Write("\r" + GetPrefix(type, level) + msg + "> ");
Console.ResetColor(); Console.ResetColor();
} }
else Type();
} }
public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) public static void WriteLine(string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true)
{ {
if (msg.Trim() == "") return;
if (type == InvokeMessageType.Warning) if (type == InvokeMessageType.Warning)
{ {
level = LogLevel.Warning; level = LogLevel.Warning;
@ -106,14 +104,13 @@ namespace Milimoe.FunGame.Server.Services
} }
if (!useLevel || ((int)level >= (int)Config.LogLevelValue)) if (!useLevel || ((int)level >= (int)Config.LogLevelValue))
{ {
Console.WriteLine("\r" + GetPrefix(type, level) + msg); if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type, level) + msg);
Type();
} }
Type();
} }
public static void WriteLine_Addons(string addon, string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true) public static void WriteLine_Addons(string addon, string msg, InvokeMessageType type = InvokeMessageType.System, LogLevel level = LogLevel.Info, bool useLevel = true)
{ {
if (msg.Trim() == "") return;
if (type == InvokeMessageType.Warning) if (type == InvokeMessageType.Warning)
{ {
level = LogLevel.Warning; level = LogLevel.Warning;
@ -124,9 +121,9 @@ namespace Milimoe.FunGame.Server.Services
} }
if (!useLevel || ((int)level >= (int)Config.LogLevelValue)) if (!useLevel || ((int)level >= (int)Config.LogLevelValue))
{ {
Console.WriteLine("\r" + GetPrefix(type, level, addon) + msg); if (msg.Trim() != "") Console.WriteLine("\r" + GetPrefix(type, level, addon) + msg);
Type();
} }
Type();
} }
public static void Type() public static void Type()
@ -148,7 +145,7 @@ namespace Milimoe.FunGame.Server.Services
private static Hashtable GetServerSettingHashtable() private static Hashtable GetServerSettingHashtable()
{ {
Hashtable settings = []; Hashtable settings = [];
if (INIHelper.INIFileExists()) if (INIHelper.ExistINIFile())
{ {
settings.Add("LogLevel", INIHelper.ReadINI("Console", "LogLevel")); settings.Add("LogLevel", INIHelper.ReadINI("Console", "LogLevel"));
settings.Add("Name", INIHelper.ReadINI("Server", "Name")); settings.Add("Name", INIHelper.ReadINI("Server", "Name"));
@ -260,7 +257,7 @@ namespace Milimoe.FunGame.Server.Services
{ {
if (SenderMailAddress == "" && SenderName == "" && SenderPassword == "" && SmtpHost == "") if (SenderMailAddress == "" && SenderName == "" && SenderPassword == "" && SmtpHost == "")
{ {
if (INIHelper.INIFileExists()) if (INIHelper.ExistINIFile())
{ {
if (bool.TryParse(INIHelper.ReadINI("Mailer", "UseMailSender").ToLower(), out bool use)) if (bool.TryParse(INIHelper.ReadINI("Mailer", "UseMailSender").ToLower(), out bool use))
{ {

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Authorization; using Milimoe.FunGame.WebAPI.Services;
using Milimoe.FunGame.WebAPI.Services;
namespace Milimoe.FunGame.WebAPI.Architecture namespace Milimoe.FunGame.WebAPI.Architecture
{ {
@ -12,33 +11,12 @@ namespace Milimoe.FunGame.WebAPI.Architecture
// 获取 JWT Token // 获取 JWT Token
string token = context.Request.Headers.Authorization.ToString().Replace("Bearer ", ""); string token = context.Request.Headers.Authorization.ToString().Replace("Bearer ", "");
if (token == "")
{
await next(context);
return;
}
// 如果存在 Authorize 属性且指定了 CustomBearer 认证方案,跳过 JWT 吊销检查
Endpoint? endpoint = context.GetEndpoint();
IReadOnlyList<AuthorizeAttribute>? authorizeAttributes = endpoint?.Metadata.GetOrderedMetadata<AuthorizeAttribute>();
if (authorizeAttributes != null)
{
foreach (AuthorizeAttribute authorizeAttribute in authorizeAttributes)
{
if (authorizeAttribute.AuthenticationSchemes == "APIBearer" || authorizeAttribute.AuthenticationSchemes == "CustomBearer")
{
await next(context);
return;
}
}
}
// 检查 JWT 是否被吊销 // 检查 JWT 是否被吊销
if (jwtService.IsTokenRevoked(token)) if (jwtService.IsTokenRevoked(token))
{ {
context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Response.StatusCode = StatusCodes.Status401Unauthorized;
context.Response.ContentType = "application/json"; context.Response.ContentType = "application/json";
await context.Response.WriteAsync("{\"message\":\"此 Token 无效或已吊销,请重新登录以获取 Token。\"}"); await context.Response.WriteAsync("{\"message\":\"此 Token 已吊销,请重新登录以获取 Token。\"}");
return; return;
} }

View File

@ -1,44 +1,38 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.OpenApi; using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi; using Microsoft.OpenApi.Models;
namespace Milimoe.FunGame.WebAPI.Architecture namespace Milimoe.FunGame.WebAPI.Architecture
{ {
public class SecurityDocumentTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer public class SecurityDocumentTransformer : IOpenApiDocumentTransformer
{ {
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken) public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{ {
IEnumerable<AuthenticationScheme> authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync(); document.Components ??= new OpenApiComponents();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer")) document.Components.SecuritySchemes = new Dictionary<string, OpenApiSecurityScheme>
{ {
Dictionary<string, IOpenApiSecurityScheme> securitySchemes = new()
{ {
["Bearer"] = new OpenApiSecurityScheme "Bearer", new OpenApiSecurityScheme
{ {
Type = SecuritySchemeType.Http, Type = SecuritySchemeType.Http,
Scheme = "bearer", Scheme = "bearer",
BearerFormat = "JWT", BearerFormat = "JWT",
In = ParameterLocation.Header Description = "BearerToken"
}
} }
}; };
document.Components ??= new OpenApiComponents(); document.SecurityRequirements = [
document.Components.SecuritySchemes = securitySchemes; new()
foreach (KeyValuePair<HttpMethod, OpenApiOperation> operation in document.Paths.Values.SelectMany(path => path.Operations!))
{ {
operation.Value.Security ??= [];
operation.Value.Security.Add(new OpenApiSecurityRequirement
{ {
[new OpenApiSecuritySchemeReference("Bearer", document)] = [] new OpenApiSecurityScheme
}); {
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
Array.Empty<string>()
} }
} }
document.Info = new() ];
{ await Task.CompletedTask;
Title = "FunGame Web API",
Version = "v1",
Description = "Welcome to FunGame Web API document."
};
} }
} }
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Milimoe.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace> <RootNamespace>Milimoe.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
@ -24,9 +24,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
<PackageReference Include="Scalar.AspNetCore" Version="2.10.3" /> <PackageReference Include="Scalar.AspNetCore" Version="2.2.1" />
<PackageReference Include="System.Text.Json" Version="9.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,6 +1,6 @@
@FunGame.WebAPI_HostAddress = http://localhost:5117 @FunGame.WebAPI_HostAddress = http://localhost:5117
GET {{FunGame.WebAPI_HostAddress}}/Room/GetRoomList/ GET {{FunGame.WebAPI_HostAddress}}/weatherforecast/
Accept: application/json Accept: application/json
### ###

View File

@ -37,7 +37,7 @@ try
ServerHelper.WriteLine("正在读取配置文件并初始化服务 . . ."); ServerHelper.WriteLine("正在读取配置文件并初始化服务 . . .");
// 检查是否存在配置文件 // 检查是否存在配置文件
if (!INIHelper.INIFileExists()) if (!INIHelper.ExistINIFile())
{ {
ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . ."); ServerHelper.WriteLine("未检测到配置文件,将自动创建配置文件 . . .");
INIHelper.Init(Config.FunGameType); INIHelper.Init(Config.FunGameType);
@ -94,17 +94,6 @@ try
ServerHelper.WriteLine("正在启动 Web API 监听 . . ."); ServerHelper.WriteLine("正在启动 Web API 监听 . . .");
Console.WriteLine("\r "); Console.WriteLine("\r ");
// 添加 JSON 转换器
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
foreach (JsonConverter converter in JsonTool.JsonSerializerOptions.Converters)
{
options.JsonSerializerOptions.Converters.Add(converter);
}
});
// 读取扩展控制器 // 读取扩展控制器
if (FunGameSystem.WebAPIPluginLoader != null) if (FunGameSystem.WebAPIPluginLoader != null)
{ {
@ -119,11 +108,23 @@ try
} }
} }
} }
// 添加 OpenAPI 文档
// 添加 JSON 转换器
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
foreach (JsonConverter converter in JsonTool.JsonSerializerOptions.Converters)
{
options.JsonSerializerOptions.Converters.Add(converter);
}
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi(options => builder.Services.AddOpenApi(options =>
{ {
options.AddDocumentTransformer<SecurityDocumentTransformer>(); options.AddDocumentTransformer(new SecurityDocumentTransformer());
}); });
// 添加 CORS 服务 // 添加 CORS 服务
builder.Services.AddCors(options => builder.Services.AddCors(options =>
@ -258,9 +259,6 @@ try
Task order = Task.Factory.StartNew(GetConsoleOrder); Task order = Task.Factory.StartNew(GetConsoleOrder);
otherobjs = [app, listener];
FunGameSystem.OnWebAPIStarted(otherobjs);
app.Run(); app.Run();
} }
catch (Exception e) catch (Exception e)

View File

@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Logging.Console;
using Milimoe.FunGame.Core.Api.Utility;
namespace Milimoe.FunGame.WebAPI.Services namespace Milimoe.FunGame.WebAPI.Services
{ {
@ -21,11 +20,6 @@ namespace Milimoe.FunGame.WebAPI.Services
textWriter.WriteLine($"{colorLevel}{timestamp} {level}/[{category}] {message}"); textWriter.WriteLine($"{colorLevel}{timestamp} {level}/[{category}] {message}");
} }
textWriter.Write("\x1b[0m\r> "); textWriter.Write("\x1b[0m\r> ");
if (logEntry.Exception != null)
{
TXTHelper.AppendErrorLog(logEntry.Exception);
}
} }
private static string GetColorCode(LogLevel logLevel) private static string GetColorCode(LogLevel logLevel)

View File

@ -38,5 +38,3 @@ FunGameWebAPI 提供 WebSocket 和 RESTful API 共存的服务,共享数据处
# 文档 # 文档
需要更多帮助请查看 [FunGame 开发文档](https://project-redbud.github.io/),此文档不保证及时更新。 需要更多帮助请查看 [FunGame 开发文档](https://project-redbud.github.io/),此文档不保证及时更新。
查阅 [DeepWiki](https://deepwiki.com/project-redbud/FunGame-Server) 文档有助于从代码层面解读项目架构和源代码。