添加活动和活动中心,添加单位,修改任务系统

This commit is contained in:
milimoe 2025-02-07 01:28:07 +08:00
parent 7bc06f1440
commit e24346bf57
Signed by: milimoe
GPG Key ID: 05D280912DA6C69E
2 changed files with 233 additions and 251 deletions

View File

@ -1,177 +0,0 @@
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Testing.Solutions
{
public enum ActivityState
{
Future,
Upcoming,
InProgress,
Ended
}
public enum RedeemResult
{
Success,
StockNotEnough,
PointsNotEnough
}
public class Activity(long id, string name, DateTime startTime, DateTime endTime)
{
public long Id { get; set; } = id;
public string Name { get; set; } = name;
public DateTime StartTime { get; set; } = startTime;
public DateTime EndTime { get; set; } = endTime;
public ActivityState State { get; private set; } = ActivityState.Future;
public List<Quest> Quests { get; set; } = [];
public Store Store { get; set; } = new Store();
// 事件
public event EventHandler<UserAccessEventArgs>? UserAccessCheck;
public void UpdateState()
{
ActivityState newState;
DateTime now = DateTime.Now;
if (now < StartTime)
{
newState = ActivityState.Future;
}
else if (now >= StartTime && now < StartTime.AddHours(1))
{
newState = ActivityState.Upcoming;
}
else if (now >= StartTime && now < EndTime)
{
newState = ActivityState.InProgress;
}
else
{
newState = ActivityState.Ended;
}
if (State != newState)
{
State = newState;
}
}
public bool AllowUserAccess(long userId)
{
UserAccessEventArgs args = new(userId, State, StartTime, EndTime);
UserAccessCheck?.Invoke(this, args);
return args.AllowAccess;
}
public void AddQuest(Quest quest)
{
Quests.Add(quest);
}
public void RemoveQuest(Quest quest)
{
Quests.Remove(quest);
}
public void UpdateQuestStatus(long questId, QuestState newStatus)
{
var quest = Quests.FirstOrDefault(q => q.Id == questId);
if (quest != null)
{
quest.Status = newStatus;
Console.WriteLine($"活动状态已改变为:{newStatus}");
}
}
}
public class UserAccessEventArgs(long userId, ActivityState activityState, DateTime startTime, DateTime endTime) : EventArgs
{
public long UserId { get; } = userId;
public ActivityState ActivityState { get; } = activityState;
public DateTime StartTime { get; } = startTime;
public DateTime EndTime { get; } = endTime;
public bool AllowAccess { get; set; } = false; // 默认不允许访问
}
public class Points(long userId, int amount = 0)
{
public long UserId { get; set; } = userId;
public int Amount { get; set; } = amount;
public void AddPoints(int amount)
{
Amount += amount;
}
public void RemovePoints(int amount)
{
if (Amount >= amount)
{
Amount -= amount;
}
else
{
throw new InvalidOperationException("积分不足!");
}
}
}
public class Store
{
public List<Item> Items { get; set; } = [];
public Dictionary<long, int> ItemPrices { get; set; } = []; // ItemId, Price
public Dictionary<long, int> ItemStocks { get; set; } = []; // ItemId, Stock
/// <summary>
/// 添加物品到商店
/// </summary>
/// <param name="item">物品</param>
/// <param name="price">价格</param>
/// <param name="stock">库存</param>
public void AddItem(Item item, int price, int stock)
{
Items.Add(item);
ItemPrices[item.Id] = price;
ItemStocks[item.Id] = stock;
}
public void RemoveItem(Item item)
{
Items.Remove(item);
ItemPrices.Remove(item.Id);
ItemStocks.Remove(item.Id);
}
public RedeemResult TryRedeemItem(Points points, long itemId)
{
if (!ItemPrices.TryGetValue(itemId, out int price))
{
throw new ArgumentException($"商品 {itemId} 不存在!");
}
if (!ItemStocks.TryGetValue(itemId, out int stock))
{
throw new ArgumentException($"商品 {itemId} 不存在!");
}
if (stock <= 0)
{
return RedeemResult.StockNotEnough; // 库存不足
}
if (points.Amount < price)
{
return RedeemResult.PointsNotEnough; // 积分不足
}
points.RemovePoints(price);
ItemStocks[itemId]--; // 减少库存
// 可选:记录兑换记录
return RedeemResult.Success; // 兑换成功
}
}
}

View File

@ -1,9 +1,7 @@
using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity; using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Testing.Solutions; using Milimoe.FunGame.Core.Model;
using ActivityState = Milimoe.FunGame.Testing.Solutions.ActivityState;
using RedeemResult = Milimoe.FunGame.Testing.Solutions.RedeemResult;
namespace Milimoe.FunGame.Testing.Tests namespace Milimoe.FunGame.Testing.Tests
{ {
@ -11,99 +9,260 @@ namespace Milimoe.FunGame.Testing.Tests
{ {
public ActivityExample() public ActivityExample()
{ {
// 创建活动 DateTime date1 = new(2025, 1, 1, 0, 0, 0);
Activity activity = new(1, "新年活动", new DateTime(2025, 1, 1, 0, 0, 0), new DateTime(2025, 1, 15, 23, 59, 59)); DateTime date1End = new(2025, 1, 15, 23, 59, 59);
DateTime date2 = new(2025, 1, 16, 0, 0, 0);
DateTime date2End = new(2025, 1, 31, 23, 59, 59);
DateTime date3 = new(2025, 2, 1, 0, 0, 0);
DateTime date3End = new(2025, 2, 9, 23, 59, 59);
// 添加任务 for (int i = 1; i <= 3; i++)
Quest continuousQuest = new()
{ {
Id = 1, Activity activity;
Name = "每日登录", // 创建活动
Description = "每日登录游戏", if (i == 1)
EstimatedMinutes = 1, {
Awards = new Dictionary<string, int> { { "积分", 10 } }, activity = new(i, $"新年活动-阶段{i}", date1, date1End);
QuestType = QuestType.Continuous }
}; else if (i == 2)
Quest immediateQuest = new() {
{ activity = new(i, $"新年活动-阶段{i}", date2, date2End);
Id = 2, }
Name = "新手引导", else
Description = "完成新手引导", {
Awards = new Dictionary<string, int> { { "积分", 20 } }, activity = new(i, $"新年活动-阶段{i}", date3, date3End);
QuestType = QuestType.Immediate }
};
Quest progressiveQuest = new()
{
Id = 3,
Name = "击败Boss",
Description = "击败Boss",
Awards = new Dictionary<string, int> { { "积分", 30 } },
QuestType = QuestType.Progressive,
MaxProgress = 10,
Progress = 5
};
activity.AddQuest(continuousQuest);
activity.AddQuest(immediateQuest);
activity.AddQuest(progressiveQuest);
// 添加商店物品 // 添加任务,需要注意的是,这些任务是全服玩家参与的任务,而不是每个玩家自己的任务。
Item item1 = Factory.GetItem(); /// 如果需要添加玩家自己的任务,需要做额外工作,可使用 <see cref="EntityModuleConfig{Quest}"> 类。
item1.Id = 1; Quest quest = new()
item1.Name = "金币"; {
item1.Description = "游戏金币"; Id = 1,
Item item2 = Factory.GetItem(); Name = "击败Boss",
item2.Id = 2; Description = "全服玩家累计击败100个Boss",
item2.Name = "道具"; CreditsAward = 10000,
item2.Description = "游戏道具"; MaterialsAward = 800,
activity.Store.AddItem(item1, 100, 10); Awards = [],
activity.Store.AddItem(item2, 200, 10); QuestType = QuestType.Progressive,
MaxProgress = 100
};
activity.Quests.Add(quest);
// 纳入活动中心管理
EventCenter.Instance.AddActivity("新年活动", activity);
}
// 订阅玩家获取活动信息事件
EventCenter.Instance.RegisterUserGetActivityInfoEventHandler("新年活动", e =>
{
// 玩家获取活动信息时,需要显示对应其账号的任务信息
// 首先,使用 EntityModuleConfig 创建一个存档管理器
EntityModuleConfig<Quest> quests = new(e.Activity.Name, e.UserId.ToString());
// 获取任务列表,如果没有,我们需要为之生成
quests.LoadConfig();
if (quests.Count == 0)
{
GenerateQuest(quests);
}
SyncQuestStateToActivity(e.Activity, quests);
// 先显示活动的信息
Console.WriteLine(e.Activity.ToString(false));
// 再显示任务信息
List<Quest> list = new(e.Activity.Quests);
list.AddRange(quests.Values);
Console.WriteLine("=== 任务列表 ===");
Console.WriteLine(string.Join("\r\n", list));
});
// 订阅用户访问检查事件 // 订阅用户访问检查事件
activity.UserAccessCheck += (sender, e) => EventCenter.Instance.RegisterUserAccessEventHandler("新年活动", e =>
{ {
if (e.ActivityState == ActivityState.InProgress) if (e.ActivityState == ActivityState.InProgress)
{ {
e.AllowAccess = true; // 只有进行中状态才允许访问 // 只有进行中状态才允许访问
e.AllowAccess = true;
// 实现活动逻辑例如触发打BOSS任务
if (e.QuestId == 1 && e.Activity.Quests.FirstOrDefault(q => q.Id == 1) is Quest quest)
{
if (quest.Status == QuestState.InProgress)
{
if (Random.Shared.Next(3) > 1)
{
Console.WriteLine($"用户 {e.UserId} 挑战 Boss 成功!");
quest.Progress++;
if (quest.Progress >= quest.MaxProgress)
{
quest.Progress = quest.MaxProgress;
quest.Status = QuestState.Completed;
Console.WriteLine($"任务 [ {quest.Name} ] 完成!全服玩家将获得奖励【{quest.AwardsString}】!");
}
}
else
{
Console.WriteLine($"用户 {e.UserId} 挑战 Boss 失败,下次再来吧。");
}
}
else
{
Console.WriteLine($"用户 {e.UserId} 尝试做任务 [ {quest.Name} ] ,但是这个任务的状态为 {CommonSet.GetQuestStatus(quest.Status)} ,做任务失败!");
}
}
// 接上文,开发者可以在此事件中创建 EntityModuleConfig 对象来为玩家定制任务
// 现在,我们判断当用户访问的不是全服活动时,如何处理定制任务
if (e.QuestId != 1)
{
// 首先,使用 EntityModuleConfig 创建一个存档管理器
EntityModuleConfig<Quest> quests = new(e.Activity.Name, e.UserId.ToString());
// 获取任务列表,如果没有,我们需要为之生成
quests.LoadConfig();
if (quests.Count == 0)
{
GenerateQuest(quests);
}
SyncQuestStateToActivity(e.Activity, quests);
// 找任务
if (quests.Values.FirstOrDefault(q => q.Id == e.QuestId) is Quest quest2)
{
// 写任务的逻辑
Console.WriteLine($"用户 {e.UserId} 尝试做任务 [ {quest2.Name} ]");
if (quest2.QuestType == QuestType.Continuous)
{
// 注意:持续性任务比较特别,需要在持续时间结束后自动结算
Task.Run(async () =>
{
await Task.Delay(1000 * 60 * quest2.EstimatedMinutes);
// 需要做特殊处理
});
}
// 做了任务后要保存
quests.SaveConfig();
}
}
} }
else else
{ {
Console.WriteLine($"用户 {e.UserId} 尝试访问活动,但当前状态为 {e.ActivityState},不允许访问。"); Console.WriteLine($"用户 {e.UserId} 尝试访问活动,但当前状态为 {e.ActivityState},不允许访问。");
} }
}; });
// 模拟用户访问 // 模拟用户访问
long userId = 123; long userId = 123;
Points points = new(userId, 30000); string input = Console.ReadLine() ?? "";
while (true) while (input.Trim() != "quit")
{ {
activity.UpdateState(); // 定时更新活动状态 if (input == "1")
if (activity.AllowUserAccess(userId))
{ {
Console.WriteLine(string.Join("\r\n", activity.Quests)); Activity? a = EventCenter.Instance.GetActivity("新年活动", "新年活动-阶段1");
if (a != null && a.AllowUserAccess(userId))
Console.WriteLine($"用户 {userId} 成功访问活动!");
// 模拟用户兑换物品
RedeemResult result = activity.Store.TryRedeemItem(points, 1);
switch (result)
{ {
case RedeemResult.Success: Console.WriteLine($"用户 {userId} 成功访问活动 {a.Name}");
Console.WriteLine($"用户 {userId} 成功兑换了 {item1.Name}");
break;
case RedeemResult.StockNotEnough:
Console.WriteLine($"用户 {userId} 兑换 {item1.Name} 失败,库存不足!");
break;
case RedeemResult.PointsNotEnough:
Console.WriteLine($"用户 {userId} 兑换 {item1.Name} 失败,积分不足!");
break;
} }
Console.WriteLine($"用户 {userId} 当前积分:{points.Amount}");
} }
else if (input == "2")
//Thread.Sleep(1000); // 每秒检查一次 {
Console.ReadLine(); Activity? a = EventCenter.Instance.GetActivity("新年活动", "新年活动-阶段2");
if (a != null && a.AllowUserAccess(userId))
{
Console.WriteLine($"用户 {userId} 成功访问活动 {a.Name}");
}
}
else if (input == "31")
{
Activity? a = EventCenter.Instance.GetActivity("新年活动", "新年活动-阶段3");
if (a != null && a.AllowUserAccess(userId, 1))
{
Console.WriteLine($"用户 {userId} 成功访问活动 {a.Name} 和任务1");
}
}
else if (input == "32")
{
Activity? a = EventCenter.Instance.GetActivity("新年活动", "新年活动-阶段3");
if (a != null && a.AllowUserAccess(userId, 2))
{
Console.WriteLine($"用户 {userId} 成功访问活动 {a.Name} 和任务2");
}
}
else if (input == "33")
{
Activity? a = EventCenter.Instance.GetActivity("新年活动", "新年活动-阶段3");
if (a != null && a.AllowUserAccess(userId, 3))
{
Console.WriteLine($"用户 {userId} 成功访问活动 {a.Name} 和任务3");
}
}
else if (input == "4")
{
// 显示所有活动
Console.WriteLine($"新年活动正在火热进行中!");
foreach (Activity activity in EventCenter.Instance["新年活动"])
{
activity.GetActivityInfo(userId);
}
Store? store = EventCenter.Instance.GetStore("新年活动");
if (store != null)
{
Console.WriteLine($"新年活动商店:[ {store.Name} ],请游玩活动项目后进入商店兑换纪念品!");
}
}
input = Console.ReadLine() ?? "";
} }
EventCenter.Instance.UnRegisterUserAccess("新年活动");
EventCenter.Instance.UnRegisterUserGetActivityInfo("新年活动");
}
private void GenerateQuest(EntityModuleConfig<Quest> quests)
{
// 生成任务
quests.Add("签到", new()
{
Id = 2,
Name = "签到",
Description = "每日登录游戏即可完成签到",
CreditsAward = 10,
MaterialsAward = 10,
Awards = [],
QuestType = QuestType.Immediate
});
quests.Add("新手引导", new()
{
Id = 3,
Name = "新手引导",
Description = "完成新手引导",
EstimatedMinutes = 1,
CreditsAward = 10,
MaterialsAward = 10,
Awards = [],
QuestType = QuestType.Continuous
});
// 保存,下次会读取
quests.SaveConfig();
}
private void SyncQuestStateToActivity(Activity activity, EntityModuleConfig<Quest> quests)
{
// 使任务的状态与活动同步
foreach (Quest quest in quests.Values)
{
if (activity.Status == ActivityState.InProgress)
{
// 只有进度式任务需要修改进行状态,其他类型是开始任务时修改
if (quest.Status == QuestState.NotStarted && quest.QuestType == QuestType.Progressive)
{
quest.Status = QuestState.InProgress;
}
}
else if (activity.Status == ActivityState.Ended)
{
// 活动结束了,还没开始或者没做完的任务就不能再做了,标记为未完成
if (quest.Status == QuestState.NotStarted || quest.Status == QuestState.InProgress)
{
quest.Status = QuestState.Missed;
}
}
}
// 保存,下次会读取
quests.SaveConfig();
} }
} }
} }