优化+新功能+BUG修复

This commit is contained in:
milimoe 2026-05-12 22:31:57 +08:00
parent 3a8477efae
commit 9dfd61885b
Signed by: milimoe
GPG Key ID: 9554D37E4B8991D0
10 changed files with 638 additions and 29 deletions

View File

@ -43,6 +43,11 @@ namespace Oshima.FunGame.OshimaModules.Regions
}
public virtual bool AddGoodsToStore(string storeName, List<Goods> goodsList, bool addToNextRefreshGoods = true)
{
return false;
}
public override string ToString()
{
StringBuilder builder = new();

View File

@ -187,6 +187,46 @@ namespace Oshima.FunGame.OshimaModules.Regions
storeTemplate.SaveConfig();
}
public override bool AddGoodsToStore(string storeName, List<Goods> goodsList, bool addToNextRefreshGoods = true)
{
EntityModuleConfig<Store> storeTemplate = new("stores", "dokyo");
storeTemplate.LoadConfig();
Store? store = storeTemplate.Get(storeName);
store ??= storeName switch
{
"dokyo_forge" => CreateNewForgeStore(),
"dokyo_horseracing" => CreateNewHorseRacingStore(),
"dokyo_cooperative" => CreateNewCooperativeStore(),
_ => null
};
if (store is null)
{
return false;
}
long maxKey = store.Goods.Count > 0 ? store.Goods.Keys.Max() : 0;
long newKey = maxKey + 1;
foreach (Goods goods in goodsList)
{
goods.Id = newKey;
store.Goods[newKey] = goods;
if (addToNextRefreshGoods)
{
store.NextRefreshGoods[newKey] = goods;
}
newKey++;
}
storeTemplate.Add(storeName, store);
storeTemplate.SaveConfig();
return true;
}
private static Store CreateNewForgeStore()
{
Store store = new("锻造积分商店")

View File

@ -81,5 +81,134 @@ namespace Oshima.FunGame.WebAPI.Model
[JsonPropertyName("result")]
public string? Result { get; set; }
[JsonPropertyName("stage")]
public string? Stage { get; set; }
}
public class BettingEvent
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("status")]
public int Status { get; set; } // 0=未开始 1=进行中 2=已结束
[JsonPropertyName("start_time")]
public DateTime StartTime { get; set; }
[JsonPropertyName("end_time")]
public DateTime EndTime { get; set; }
[JsonPropertyName("created_at")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("updated_at")]
public DateTime UpdatedAt { get; set; }
}
public class BettingMatch
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("event_id")]
public int EventId { get; set; }
[JsonPropertyName("stage")]
public string? Stage { get; set; }
[JsonPropertyName("team1_name")]
public string Team1Name { get; set; } = "";
[JsonPropertyName("team1_logo")]
public string? Team1Logo { get; set; }
[JsonPropertyName("team2_name")]
public string Team2Name { get; set; } = "";
[JsonPropertyName("team2_logo")]
public string? Team2Logo { get; set; }
[JsonPropertyName("status")]
public int Status { get; set; } // 0=未开始 1=进行中 2=已结束
[JsonPropertyName("start_time")]
public DateTime StartTime { get; set; }
[JsonPropertyName("bet_deadline")]
public DateTime BetDeadline { get; set; }
[JsonPropertyName("result")]
public string? Result { get; set; }
[JsonPropertyName("winner")]
public int? Winner { get; set; } // 1=team1, 2=team2, null=未定
[JsonPropertyName("available_options")]
public string AvailableOptions { get; set; } = "[]"; // JSON 数组字符串
[JsonPropertyName("team1_win_odds")]
public decimal Team1WinOdds { get; set; }
[JsonPropertyName("team2_win_odds")]
public decimal Team2WinOdds { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("created_at")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("updated_at")]
public DateTime UpdatedAt { get; set; }
}
public class BettingBetRecord
{
[JsonPropertyName("id")]
public long Id { get; set; }
[JsonPropertyName("user_id")]
public long UserId { get; set; }
[JsonPropertyName("match_id")]
public int MatchId { get; set; }
[JsonPropertyName("option_type")]
public int OptionType { get; set; } // 1=team1胜 2=team2胜 3=精确比分 4=MVP
[JsonPropertyName("option_value")]
public string OptionValue { get; set; } = "";
[JsonPropertyName("amount")]
public long Amount { get; set; }
[JsonPropertyName("odds_at_bet")]
public decimal OddsAtBet { get; set; }
[JsonPropertyName("bet_time")]
public DateTime BetTime { get; set; }
[JsonPropertyName("is_settled")]
public bool IsSettled { get; set; }
[JsonPropertyName("payout")]
public long? Payout { get; set; }
[JsonPropertyName("is_claimed")]
public bool IsClaimed { get; set; }
[JsonPropertyName("result_note")]
public string? ResultNote { get; set; }
[JsonPropertyName("created_at")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("updated_at")]
public DateTime UpdatedAt { get; set; }
}
}

View File

@ -151,7 +151,7 @@ namespace Oshima.FunGame.WebAPI.Services
sql.ExecuteDataSet($@"
SELECT m.id, m.team1_name, m.team2_name, m.status, m.start_time, m.stage,
e.name AS event_name, e.id AS event_id
e.name AS event_name, e.id AS event_id, m.result
FROM csbetting_matches m
LEFT JOIN csbetting_events e ON m.event_id = e.id
ORDER BY
@ -176,8 +176,9 @@ namespace Oshima.FunGame.WebAPI.Services
string stage = row["stage"]?.ToString() ?? "";
string eventName = row["event_name"]?.ToString() ?? "";
long eventId = Convert.ToInt64(row["event_id"]);
string result = row["result"] != DBNull.Value ? row["result"].ToString() ?? "" : "";
string statusStr = status switch { 0 => "未开始", 1 => "进行中", 2 => "已结束", _ => "未知" };
string statusStr = status switch { 0 => "未开始", 1 => "进行中", 2 => $"已结束 | {result}", _ => "未知" };
string matchLabel = $"{t1} vs {t2}".CreateCmdInput($"比赛详情 {id}");
sb.Append($"[{id}] {matchLabel}");
@ -222,6 +223,22 @@ namespace Oshima.FunGame.WebAPI.Services
eventName = rowEvent["name"].ToString() ?? "";
}
// 查询各选项统计
sql.Parameters["@mid"] = matchId;
DataSet stats = sql.ExecuteDataSet(@"SELECT option_type,
COUNT(*) AS totalRecord, SUM(amount) AS totalAmount
FROM csbetting_bet_records WHERE match_id = @mid GROUP BY option_type");
// 将统计存入字典便于查找
Dictionary<int, (int, long)> statDict = [];
if (sql.Success && stats.Tables[0].Rows.Count > 0)
{
foreach (DataRow srow in stats.Tables[0].Rows)
{
statDict[Convert.ToInt32(srow["option_type"])] = (Convert.ToInt32(srow["totalRecord"]), Convert.ToInt64(srow["totalAmount"]));
}
}
string statusStr = status switch { 0 => "未开始", 1 => "进行中", 2 => "已结束", _ => "未知" };
StringBuilder sb = new();
sb.AppendLine($"比赛 #{matchId}");
@ -241,27 +258,44 @@ namespace Oshima.FunGame.WebAPI.Services
sb.AppendLine($"> 📝 {description}\r\n");
}
if (status == 0) sb.AppendLine($"可用选项:");
DateTime now = DateTime.Now;
bool canBet = (status == 0 || status == 1) && now < deadline;
if (canBet) sb.AppendLine($"可用选项:");
else sb.AppendLine($"该比赛已截止预测。");
string GetStatString(int opt)
{
if (statDict.TryGetValue(opt, out var stat) && stat.Item1 > 0)
{
return $" 👥 {stat.Item1} 🔥 {stat.Item2}";
}
return "";
};
string statText = "";
if (available.Contains("team1_win"))
{
sb.AppendLine($" - {t1} 胜 (x {team1Odds})");
if (status == 0) kb.AppendButtons(2, Button.CreateCmdButton($"⚔️ {t1} 胜", $"预测 {matchId} team1 1000", enter: false));
statText = GetStatString(1);
sb.AppendLine($" - {t1} 胜 (x {team1Odds}){statText}");
if (canBet) kb.AppendButtons(2, Button.CreateCmdButton($"⚔️ {t1} 胜", $"预测 {matchId} team1 1000", enter: false));
}
if (available.Contains("team2_win"))
{
sb.AppendLine($" - {t2} 胜 (x {team2Odds})");
if (status == 0) kb.AppendButtons(2, Button.CreateCmdButton($"🛡️ {t2} 胜", $"预测 {matchId} team2 1000", enter: false));
statText = GetStatString(2);
sb.AppendLine($" - {t2} 胜 (x {team2Odds}){statText}");
if (canBet) kb.AppendButtons(2, Button.CreateCmdButton($"🛡️ {t2} 胜", $"预测 {matchId} team2 1000", enter: false));
}
if (available.Contains("score"))
{
sb.AppendLine($" - 精确比分 (x 4)");
if (status == 0) kb.AppendButtons(2, Button.CreateCmdButton("🎯 精确比分", $"预测 {matchId} score:", enter: false));
statText = GetStatString(3);
sb.AppendLine($" - 精确比分 (x 4){statText}");
if (canBet) kb.AppendButtons(2, Button.CreateCmdButton("🎯 精确比分", $"预测 {matchId} score:", enter: false));
}
if (available.Contains("mvp"))
{
sb.AppendLine($" - 赛事MVP (x 3.5)");
if (status == 0) kb.AppendButtons(2, Button.CreateCmdButton("🏆 MVP", $"预测 {matchId} mvp:", enter: false));
statText = GetStatString(4);
sb.AppendLine($" - 赛事MVP (x 3.5){statText}");
if (canBet) kb.AppendButtons(2, Button.CreateCmdButton("🏆 MVP", $"预测 {matchId} mvp:", enter: false));
}
if (status == 2)
{
@ -270,7 +304,7 @@ namespace Oshima.FunGame.WebAPI.Services
if (winner != 3) sb.AppendLine($"结果:{result}");
}
if (status == 0)
if (canBet)
{
sb.AppendLine($"预测指令:{"".CreateCmdInput()} <比赛ID> <选项> <{General.GameplayEquilibriumConstant.InGameCurrency}数>\r\n👇🏻 点击下方按钮快速预测");
}
@ -316,9 +350,9 @@ namespace Oshima.FunGame.WebAPI.Services
alreadyBet = Convert.ToInt64(sql.DataSet.Tables[0].Rows[0]["total"] ?? 0L);
totalBet += alreadyBet;
}
if (totalBet > 5000)
if (totalBet > 10000)
{
error = $"本场比赛你的助力总额不能超过 5000 {General.GameplayEquilibriumConstant.InGameCurrency}(已助力 {alreadyBet})。";
error = $"本场比赛你的助力总额不能超过 10000 {General.GameplayEquilibriumConstant.InGameCurrency}(已助力 {alreadyBet})。";
return false;
}
@ -919,6 +953,11 @@ namespace Oshima.FunGame.WebAPI.Services
sql.Parameters["@result"] = (object?)request.Result ?? "";
setClause.Append("result = @result, ");
}
if (request.Stage != null)
{
sql.Parameters["@stage"] = (object?)request.Stage ?? "";
setClause.Append("stage = @stage, ");
}
if (setClause.Length == 0)
{

View File

@ -28,7 +28,6 @@ CREATE TABLE IF NOT EXISTS `csbetting_events` (
`status` tinyint NOT NULL DEFAULT '0' COMMENT '赛事状态0=未开始1=进行中2=已结束',
`start_time` datetime NOT NULL COMMENT '赛事开始时间',
`end_time` datetime NOT NULL COMMENT '赛事结束时间',
`mvp_candidates` json DEFAULT NULL COMMENT 'MVP候选人UID列表如 [1001, 1002]',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),

View File

@ -0,0 +1,267 @@
using System.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Milimoe.FunGame.Core.Api.Utility;
using Oshima.FunGame.WebAPI.Model;
namespace Oshima.FunGame.WebAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class BettingController : ControllerBase
{
/// <summary>
/// 获取赛事列表(分页 + 可选状态过滤)
/// </summary>
[AllowAnonymous]
[HttpGet("events")]
public ActionResult<IEnumerable<BettingEvent>> GetEvents(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] int? status = null)
{
using var sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null) return StatusCode(500, "数据库连接失败");
sql.ClearParametersAfterExecute = false;
// 动态条件
string where = status.HasValue ? "WHERE status = @status" : "";
if (status.HasValue) sql.Parameters["@status"] = status.Value;
// 总数
sql.ExecuteDataSet($"SELECT COUNT(*) FROM csbetting_events {where}");
int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0;
int totalPages = (int)Math.Ceiling(total / (double)pageSize);
if (page > totalPages) page = totalPages;
if (page < 1) page = 1;
int offset = (page - 1) * pageSize;
sql.ExecuteDataSet($@"
SELECT * FROM csbetting_events {where}
ORDER BY start_time DESC
LIMIT {pageSize} OFFSET {offset}");
if (!sql.Success || sql.DataSet.Tables.Count == 0)
return Ok(new { data = Array.Empty<BettingEvent>(), page, totalPages, total });
var list = new List<BettingEvent>();
foreach (DataRow row in sql.DataSet.Tables[0].Rows)
{
list.Add(MapEvent(row));
}
return Ok(new { data = list, page, totalPages, total });
}
/// <summary>
/// 获取单个赛事详情
/// </summary>
[AllowAnonymous]
[HttpGet("events/{id:int}")]
public ActionResult<BettingEvent> GetEvent(int id)
{
using var sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null) return StatusCode(500, "数据库连接失败");
sql.ClearParametersAfterExecute = false;
sql.Parameters["@id"] = id;
DataRow? row = sql.ExecuteDataRow("SELECT * FROM csbetting_events WHERE id = @id");
if (row == null) return NotFound();
return Ok(MapEvent(row));
}
/// <summary>
/// 获取比赛列表(分页 + 可选过滤)
/// </summary>
[AllowAnonymous]
[HttpGet("matches")]
public ActionResult<IEnumerable<BettingMatch>> GetMatches(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] int? eventId = null,
[FromQuery] int? status = null)
{
using var sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null) return StatusCode(500, "数据库连接失败");
sql.ClearParametersAfterExecute = false;
var conditions = new List<string>();
if (eventId.HasValue)
{
conditions.Add("event_id = @eventId");
sql.Parameters["@eventId"] = eventId.Value;
}
if (status.HasValue)
{
conditions.Add("status = @status");
sql.Parameters["@status"] = status.Value;
}
string where = conditions.Count > 0 ? "WHERE " + string.Join(" AND ", conditions) : "";
sql.ExecuteDataSet($"SELECT COUNT(*) FROM csbetting_matches {where}");
int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0;
int totalPages = (int)Math.Ceiling(total / (double)pageSize);
if (page > totalPages) page = totalPages;
if (page < 1) page = 1;
int offset = (page - 1) * pageSize;
sql.ExecuteDataSet($@"
SELECT * FROM csbetting_matches {where}
ORDER BY start_time DESC
LIMIT {pageSize} OFFSET {offset}");
if (!sql.Success || sql.DataSet.Tables.Count == 0)
return Ok(new { data = Array.Empty<BettingMatch>(), page, totalPages, total });
var list = new List<BettingMatch>();
foreach (DataRow row in sql.DataSet.Tables[0].Rows)
{
list.Add(MapMatch(row));
}
return Ok(new { data = list, page, totalPages, total });
}
/// <summary>
/// 获取单个比赛详情
/// </summary>
[AllowAnonymous]
[HttpGet("matches/{id:int}")]
public ActionResult<BettingMatch> GetMatch(int id)
{
using var sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null) return StatusCode(500, "数据库连接失败");
sql.ClearParametersAfterExecute = false;
sql.Parameters["@id"] = id;
DataRow? row = sql.ExecuteDataRow("SELECT * FROM csbetting_matches WHERE id = @id");
if (row == null) return NotFound();
return Ok(MapMatch(row));
}
/// <summary>
/// 获取投注记录列表(管理员专用)
/// </summary>
[Authorize(AuthenticationSchemes = "CustomBearer")]
[HttpGet("bets")]
public ActionResult<IEnumerable<BettingBetRecord>> GetBets(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] long? userId = null,
[FromQuery] int? matchId = null,
[FromQuery] bool? isSettled = null)
{
// 简易管理员检查(可替换为实际鉴权)
if (!User.IsInRole("Admin") && !User.IsInRole("Operator"))
return Forbid();
using var sql = Factory.OpenFactory.GetSQLHelper();
if (sql == null) return StatusCode(500, "数据库连接失败");
sql.ClearParametersAfterExecute = false;
var conditions = new List<string>();
if (userId.HasValue)
{
conditions.Add("user_id = @uid");
sql.Parameters["@uid"] = userId.Value;
}
if (matchId.HasValue)
{
conditions.Add("match_id = @mid");
sql.Parameters["@mid"] = matchId.Value;
}
if (isSettled.HasValue)
{
conditions.Add("is_settled = @settled");
sql.Parameters["@settled"] = isSettled.Value ? 1 : 0;
}
string where = conditions.Count > 0 ? "WHERE " + string.Join(" AND ", conditions) : "";
sql.ExecuteDataSet($"SELECT COUNT(*) FROM csbetting_bet_records {where}");
int total = sql.Success ? Convert.ToInt32(sql.DataSet.Tables[0].Rows[0][0]) : 0;
int totalPages = (int)Math.Ceiling(total / (double)pageSize);
if (page > totalPages) page = totalPages;
if (page < 1) page = 1;
int offset = (page - 1) * pageSize;
sql.ExecuteDataSet($@"
SELECT * FROM csbetting_bet_records {where}
ORDER BY bet_time DESC
LIMIT {pageSize} OFFSET {offset}");
if (!sql.Success || sql.DataSet.Tables.Count == 0)
return Ok(new { data = Array.Empty<BettingBetRecord>(), page, totalPages, total });
var list = new List<BettingBetRecord>();
foreach (DataRow row in sql.DataSet.Tables[0].Rows)
{
list.Add(MapBetRecord(row));
}
return Ok(new { data = list, page, totalPages, total });
}
// ---------- 映射辅助方法 ----------
private static BettingEvent MapEvent(DataRow row)
{
return new BettingEvent
{
Id = Convert.ToInt32(row["id"]),
Name = row["name"].ToString() ?? "",
Status = Convert.ToInt32(row["status"]),
StartTime = Convert.ToDateTime(row["start_time"]),
EndTime = Convert.ToDateTime(row["end_time"]),
CreatedAt = Convert.ToDateTime(row["created_at"]),
UpdatedAt = Convert.ToDateTime(row["updated_at"])
};
}
private static BettingMatch MapMatch(DataRow row)
{
return new BettingMatch
{
Id = Convert.ToInt32(row["id"]),
EventId = Convert.ToInt32(row["event_id"]),
Stage = row["stage"]?.ToString(),
Team1Name = row["team1_name"].ToString() ?? "",
Team1Logo = row["team1_logo"]?.ToString(),
Team2Name = row["team2_name"].ToString() ?? "",
Team2Logo = row["team2_logo"]?.ToString(),
Status = Convert.ToInt32(row["status"]),
StartTime = Convert.ToDateTime(row["start_time"]),
BetDeadline = Convert.ToDateTime(row["bet_deadline"]),
Result = row["result"]?.ToString(),
Winner = row["winner"] != DBNull.Value ? Convert.ToInt32(row["winner"]) : null,
AvailableOptions = row["available_options"].ToString() ?? "[]",
Team1WinOdds = Convert.ToDecimal(row["team1_win_odds"]),
Team2WinOdds = Convert.ToDecimal(row["team2_win_odds"]),
Description = row["description"]?.ToString(),
CreatedAt = Convert.ToDateTime(row["created_at"]),
UpdatedAt = Convert.ToDateTime(row["updated_at"])
};
}
private static BettingBetRecord MapBetRecord(DataRow row)
{
return new BettingBetRecord
{
Id = Convert.ToInt64(row["id"]),
UserId = Convert.ToInt64(row["user_id"]),
MatchId = Convert.ToInt32(row["match_id"]),
OptionType = Convert.ToInt32(row["option_type"]),
OptionValue = row["option_value"].ToString() ?? "",
Amount = Convert.ToInt64(row["amount"]),
OddsAtBet = Convert.ToDecimal(row["odds_at_bet"]),
BetTime = Convert.ToDateTime(row["bet_time"]),
IsSettled = Convert.ToInt32(row["is_settled"]) == 1,
Payout = row["payout"] != DBNull.Value ? Convert.ToInt64(row["payout"]) : null,
IsClaimed = Convert.ToInt32(row["is_claimed"]) == 1,
ResultNote = row["result_note"]?.ToString(),
CreatedAt = Convert.ToDateTime(row["created_at"]),
UpdatedAt = Convert.ToDateTime(row["updated_at"])
};
}
}
}

View File

@ -162,7 +162,7 @@ namespace Oshima.FunGame.WebAPI.Controllers
long total = CSBettingService.ClaimRewards(uid);
if (total > 0)
{
user.Inventory.Credits += (int)total;
user.Inventory.Credits += total;
FunGameService.SetUserConfigButNotRelease(uid, pc, user);
md.Content = $"领取成功!获得 {total} {General.GameplayEquilibriumConstant.InGameCurrency}。";
}

View File

@ -8577,6 +8577,79 @@ namespace Oshima.FunGame.WebAPI.Controllers
}
}
[HttpPost("systemstoreaddgoods")]
public BotReply SystemStoreAddGoods([FromQuery] long? uid = null, [FromQuery] long region = 0, [FromQuery] string storeName = "", [FromQuery] string name = "", [FromQuery] double price = 0, [FromQuery] int stock = -1, [FromQuery] int quota = 0, [FromQuery] bool addToNextRefreshGoods = true)
{
long userid = uid ?? Convert.ToInt64("10" + Verification.CreateVerifyCode(VerifyCodeType.NumberVerifyCode, 11));
PluginConfig pc = FunGameService.GetUserConfig(userid, out _);
if (pc.Count > 0)
{
User user = FunGameService.GetUser(pc);
string msg = "";
if (user.IsAdmin)
{
if (FunGameConstant.PlayerRegions.FirstOrDefault(r => r.Id == region) is OshimaRegion or)
{
if (FunGameConstant.Items.FirstOrDefault(i => i.Name == name) is Item item)
{
Item newItem = item.Copy();
Goods g = new()
{
Name = newItem.Name,
Description = newItem.Description,
Stock = stock,
Quota = quota,
};
g.Items.Add(newItem);
if (price == 0)
{
(int min, int max) = (0, 0);
if (FunGameConstant.PriceRanges.TryGetValue(item.QualityType, out (int Min, int Max) range))
{
(min, max) = (range.Min, range.Max);
}
price = Random.Shared.Next(min, max);
}
newItem.Price = price;
g.SetPrice(General.GameplayEquilibriumConstant.InGameCurrency, price);
if (or.AddGoodsToStore(storeName, [g], addToNextRefreshGoods))
{
msg = $"添加成功,请查看商店!";
}
else
{
msg = $"添加失败,商店可能不存在。";
}
}
else
{
msg = $"目标物品不存在,请重新输入。";
}
}
else
{
msg = $"未知地区,请重新输入。{"".CreateCmdInput()}";
}
}
else
{
msg = $"你没有权限使用此指令!";
}
FunGameService.SetUserConfigAndReleaseSemaphoreSlim(userid, pc, user);
return msg;
}
else
{
FunGameService.ReleaseUserSemaphoreSlim(userid);
return noSaved;
}
}
[HttpPost("forgeitemcreate")]
public BotReply ForgeItem_Create([FromQuery] long uid = -1, [FromBody] Dictionary<string, int>? materials = null)
{

View File

@ -18,7 +18,7 @@ namespace Oshima.FunGame.WebAPI.Services
{
Markdown = new MarkdownMessage
{
Content = "🎮 CS赛事预测帮助:\r\n"
Content = "🎮 赛事预测系统帮助:\r\n"
+ $"✨ {"".CreateCmdInput()} - 查看所有赛事\r\n"
+ $"✨ {"".CreateCmdInput()} - 查看所有比赛\r\n"
+ $"✨ {"".CreateCmdInput()} - 创建存档后可预测\r\n"
@ -35,7 +35,7 @@ namespace Oshima.FunGame.WebAPI.Services
Button.CreateCmdButton("💰 预测领奖", "预测领奖"),
Button.CreateCmdButton("❓ 预测帮助", "预测帮助"))
};
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
return true;
}
@ -75,11 +75,11 @@ namespace Oshima.FunGame.WebAPI.Services
{
reply.Markdown.Content += "\r\n" + reply2.Markdown.Content;
}
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
}
else
{
await SendAsync(e, "CS赛事预测", "格式:比赛详情 <比赛ID>");
await SendAsync(e, "赛事预测", "格式:比赛详情 <比赛ID>");
}
return true;
}
@ -102,7 +102,7 @@ namespace Oshima.FunGame.WebAPI.Services
Button.CreateCmdButton("📅 比赛列表", "比赛列表"),
Button.CreateCmdButton("📜 我的预测", "我的预测"),
Button.CreateCmdButton("💰 预测领奖", "预测领奖"));
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
}
else
{
@ -119,7 +119,7 @@ namespace Oshima.FunGame.WebAPI.Services
Button.CreateCmdButton("❓ 预测帮助", "预测帮助"),
Button.CreateCmdButton("📜 我的预测", "我的预测"))
};
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
}
return true;
}
@ -132,7 +132,7 @@ namespace Oshima.FunGame.WebAPI.Services
System.Text.RegularExpressions.Match match = GetFirstNumber().Match(detail);
if (match.Success && int.TryParse(match.Value, out int p)) page = p;
BotReply reply = BettingController.GetEventsOverview(page);
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
return true;
}
@ -153,7 +153,7 @@ namespace Oshima.FunGame.WebAPI.Services
{
reply.Keyboard.AppendButtons(2, Button.CreateCmdButton("⚙️ 创建存档", "创建存档"));
}
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
return true;
}
@ -169,7 +169,7 @@ namespace Oshima.FunGame.WebAPI.Services
{
reply.Keyboard.AppendButtons(2, Button.CreateCmdButton("⚙️ 创建存档", "创建存档"));
}
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
return true;
}
@ -179,7 +179,7 @@ namespace Oshima.FunGame.WebAPI.Services
string[] parts = detail.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 3 || !int.TryParse(parts[0], out int mid) || !long.TryParse(parts[^1], out long amt))
{
await SendAsync(e, "CS赛事预测", $"格式:预测 <比赛ID> <选项> <{General.GameplayEquilibriumConstant.InGameCurrency}数>\r\n选项team1 / team2 / score:2:0 / mvp:选手UID");
await SendAsync(e, "赛事预测", $"格式:预测 <比赛ID> <选项> <{General.GameplayEquilibriumConstant.InGameCurrency}数>\r\n选项team1 / team2 / score:2:0 / mvp:选手UID");
return true;
}
string option = string.Join(" ", parts[1..^1]).ToLower();
@ -211,7 +211,7 @@ namespace Oshima.FunGame.WebAPI.Services
}
reply.Keyboard = kb;
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
return true;
}
@ -235,10 +235,10 @@ namespace Oshima.FunGame.WebAPI.Services
Button.CreateCmdButton("📅 比赛列表", "比赛列表"),
Button.CreateCmdButton("⚙️ 继续结算", "结算比赛 ", enter: false),
Button.CreateCmdButton("🔍 比赛详情", $"比赛详情 {mid}"));
await SendAsync(e, "CS赛事预测", reply);
await SendAsync(e, "赛事预测", reply);
}
else
await SendAsync(e, "CS赛事预测", "格式:结算比赛 <比赛ID> winner=team1 result=2:0");
await SendAsync(e, "赛事预测", "格式:结算比赛 <比赛ID> winner=team1 result=2:0");
return true;
}

View File

@ -2144,6 +2144,63 @@ namespace Oshima.FunGame.WebAPI.Services
return result;
}
if (e.Detail.StartsWith("添加商品", StringComparison.CurrentCultureIgnoreCase))
{
string detail = e.Detail["添加商品".Length..].Trim();
// 匹配必需参数地区ID数字商店名称可带双引号物品名称可带双引号以及剩余可选参数部分
string pattern = @"^(?<region>\d+)\s+(?<storeName>(""[^""]*""|\S+))\s+(?<itemName>(""[^""]*""|\S+))\s*(?<options>.*)$";
Match match = Regex.Match(detail, pattern);
if (match.Success)
{
long region = long.Parse(match.Groups["region"].Value);
string storeName = match.Groups["storeName"].Value.Trim('"');
string itemName = match.Groups["itemName"].Value.Trim('"');
string optionsStr = match.Groups["options"].Value.Trim();
// 默认值
double price = 0;
int stock = -1;
int quota = 0;
bool addToNextRefreshGoods = true;
// 解析可选键值对
if (!string.IsNullOrEmpty(optionsStr))
{
string optionPattern = @"(?<key>\w+)=(?<value>[^\s]+)";
foreach (Match opt in Regex.Matches(optionsStr, optionPattern))
{
string key = opt.Groups["key"].Value.ToLower();
string val = opt.Groups["value"].Value;
switch (key)
{
case "price":
_ = double.TryParse(val, out price);
break;
case "stock":
_ = int.TryParse(val, out stock);
break;
case "quota":
_ = int.TryParse(val, out quota);
break;
case "refresh":
// 支持 是/否 或 true/false 或 1/0
addToNextRefreshGoods = val == "1" ||
bool.TryParse(val, out bool b) && b ||
val.Equals("是", StringComparison.OrdinalIgnoreCase) ||
val.Equals("yes", StringComparison.OrdinalIgnoreCase);
break;
}
}
}
BotReply reply = Controller.SystemStoreAddGoods(uid, region, storeName, itemName, price, stock, quota, addToNextRefreshGoods);
await SendAsync(e, "添加商品", reply);
}
return result;
}
if (e.Detail.StartsWith("查地区", StringComparison.CurrentCultureIgnoreCase) || e.Detail.StartsWith("查询地区", StringComparison.CurrentCultureIgnoreCase))
{
string detail = e.Detail.Replace("查地区", "").Replace("查询地区", "").Trim();