This commit is contained in:
Putoo
2026-07-07 18:43:01 +08:00
parent 7f29fd46b8
commit 037e845622
37 changed files with 854 additions and 106 deletions

View File

@@ -10,6 +10,7 @@ namespace Application.Domain
{
public enum BusEventsName
{
HandleOnHook,//处理挂机
PutFightAward,//战斗奖励事件
}
}

View File

@@ -13,5 +13,12 @@
var fightService = App.GetService<IGameFightService>();
await fightService.HandleFight(data);
}
[EventSubscribe(BusEventsEnum.BusEventsName.HandleOnHook, NumRetries = 0,RetryTimeout = 999999999)]
public async Task HandleOnHook(EventHandlerExecutingContext context)
{
var hookService = App.GetService<IOnHookService>();
await hookService.HandleHook();
}
}
}

View File

@@ -2,6 +2,15 @@
public static class GameEnum
{
public enum JobType
{
single,//1次
alway,//永久
}
public enum JobCode
{
OnHook,//定时任务
}
public enum PropCode//游戏资源编码
{
Monster,//怪物

View File

@@ -10,4 +10,10 @@ public class MapEnum
add_blood,
add_copper,
}
public enum MapCode
{
DEF_MAP,
Dup_Map
}
}

View File

@@ -0,0 +1,10 @@
namespace Application.Domain;
public interface IGameAutoJobService
{
Task<List<game_job>> GetJobData();
Task<game_job> GetJobInfo(string jobId);
Task StartJob();
Task StopJob(string jobId);
Task HandleJob(game_job data);
}

View File

@@ -0,0 +1,12 @@
namespace Application.Domain;
public interface IOnHookService
{
Task<game_onhook> GetUserOnHook(string userId);
Task<bool> StartOnHook(string userId,string scene, long copper, long exp, string name, string award, decimal score,
int time, int onHookTime);
Task<bool> StopOnHook(string userId);
Task HandleHook();
}

View File

@@ -57,7 +57,7 @@ public interface IUnitUserAttrService
#region BUFF状态
Task<List<unit_user_state>> GetUserStateData(string userId, string scene = "Default");
Task<decimal> GetUserStateDataTotal(string userId, string scene = "Default");
Task<bool> AddUserState(string userId, string groupId, string name, string scene, string tips,
List<AttrItem> attr, int time, int count = 1);

View File

@@ -0,0 +1,64 @@
using Photon.Core.Timer;
namespace Application.Domain;
public class GameAutoJobService(ISqlSugarClient DbClient, IRedisCache redis,ITimerJobManager jobManager) : IGameAutoJobService, ITransient
{
public async Task<List<game_job>> GetJobData()
{
var db = DbClient.AsTenant().GetConnectionWithAttr<game_job>();
return await db.Queryable<game_job>().Where(it => it.state == 1).ToListAsync();
}
public async Task<game_job> GetJobInfo(string jobId)
{
string key = string.Format(BaseCache.BaseCacheKey,"JobData");
if (await redis.HExistsHashAsync(key, jobId))
{
return await redis.GetHashAsync<game_job>(key, jobId);
}
var db = DbClient.AsTenant().GetConnectionWithAttr<game_job>();
var data = await db.Queryable<game_job>().Where(it => it.jobId == jobId).SingleAsync();
await redis.AddHashAsync(key, jobId, data);
return data;
}
public async Task StartJob()
{
Console.WriteLine(">>>开始执行定时任务>>>");
var jobData = await GetJobData();
if (jobData.Count > 0)
{
foreach (var item in jobData)
{
await jobManager.CreateAndStartTask(item.jobId, item.code, item.cron);
Console.WriteLine($"-已启动--->{item.name}");
}
}
Console.WriteLine("<<<定时任务初始化完成<<<");
await Task.CompletedTask;
}
public async Task StopJob(string jobId)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<game_job>();
bool result = await db.Updateable<game_job>().SetColumns(it => it.state == 0).Where(it => it.jobId == jobId)
.ExecuteCommandAsync() > 0;
if (result)
{
await jobManager.DeleteTask(jobId);
}
}
public async Task HandleJob(game_job data)
{
if (data.code == nameof(GameEnum.JobCode.OnHook))//挂机
{
var _eventPublisher = App.GetService<IEventPublisher>();
await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleOnHook,
data));
}
}
}

View File

@@ -0,0 +1,167 @@
using Newtonsoft.Json;
namespace Application.Domain;
public class OnHookService(ISqlSugarClient DbClient, IRedisCache redis) : IOnHookService, ITransient
{
public async Task<game_onhook> GetUserOnHook(string userId)
{
string key = string.Format(UserCache.BaseCacheKey, "OnHook");
if (await redis.HExistsHashAsync(key, userId))
{
return await redis.GetHashAsync<game_onhook>(key, userId);
}
var db = DbClient.AsTenant().GetConnectionWithAttr<game_onhook>();
var data = await db.Queryable<game_onhook>().Where(it => it.userId == userId).SingleAsync();
if (data == null)
{
data = new game_onhook();
data.userId = userId;
data.scene = "";
data.copper = 0;
data.exp = 0;
data.status = 0;
data.name = "";
data.award = "";
data.score = 0;
data.time = 0;
data.uptime = DateTime.Now;
data.endTime = DateTime.Now;
data.stopTime = TimeExtend.GetTimeStampSeconds;
data.sumExp = 0;
data.sumCopper = 0;
await db.Insertable(data).ExecuteCommandAsync();
}
await redis.AddHashAsync(key, userId, data);
return data;
}
private async Task ClearOnHookCache(string userId)
{
string key = string.Format(UserCache.BaseCacheKey, "OnHook");
await redis.DelHashAsync(key, userId);
}
public async Task<bool> StartOnHook(string userId, string scene, long copper, long exp, string name, string award,
decimal score,
int time, int onHookTime)
{
game_onhook data = new game_onhook();
data.userId = userId;
data.scene = scene;
data.copper = copper;
data.exp = exp;
data.status = 1;
data.name = name;
data.award = award;
data.score = score;
data.time = time;
data.uptime = DateTime.Now;
DateTime end = DateTime.Now.AddHours(onHookTime);
data.endTime = end;
data.stopTime = TimeExtend.GetTimeStampBySeconds(end);
data.sumExp = 0;
data.sumCopper = 0;
var db = DbClient.AsTenant().GetConnectionWithAttr<game_onhook>();
bool result = await db.Saveable(data).ExecuteCommandAsync() > 0;
if (result)
{
await ClearOnHookCache(userId);
}
return result;
}
public async Task<bool> StopOnHook(string userId)
{
bool result = true;
var onHook = await GetUserOnHook(userId);
if (onHook.status == 1)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<game_onhook>();
result = await db.Updateable<game_onhook>().SetColumns(it => it.status == 0)
.Where(it => it.userId == userId).ExecuteCommandAsync() > 0;
if (result)
{
await ClearOnHookCache(userId);
}
}
return result;
}
private async Task<bool> UpdateOnHook(string userId, long exp, long copper)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<game_onhook>();
var result = await db.Updateable<game_onhook>()
.SetColumnsIF(exp > 0, it => it.sumExp == it.sumExp + exp)
.SetColumnsIF(copper > 0, it => it.sumCopper == it.sumCopper + copper)
.SetColumns(it => it.uptime == DateTime.Now)
.Where(it => it.userId == userId).ExecuteCommandAsync() > 0;
if (result)
{
await ClearOnHookCache(userId);
}
return result;
}
public async Task HandleHook()
{
long onTime = TimeExtend.GetTimeStampSeconds;
var accService = App.GetService<IUnitUserAccService>();
var attrService = App.GetService<IUnitUserAttrService>();
var db = DbClient.AsTenant().GetConnectionWithAttr<game_onhook>();
var data = await db.Queryable<game_onhook>().Where(it => it.status == 1).ToListAsync();
foreach (var hook in data)
{
if (hook.stopTime < onTime)
{
await StopOnHook(hook.userId);
continue;
}
var userAttr = await attrService.GetUserAttrModel(hook.userId, hook.scene);
if (userAttr.score < hook.score)
{
await StopOnHook(hook.userId);
continue;
}
int allTime = TimeAssist.TimeDiffSeconds((DateTime)hook.uptime, DateTime.Now) * 1000;
int opCount = Convert.ToInt32(allTime / hook.time);
long exp = Convert.ToInt64(hook.exp * (1.0m + userAttr.addExp) * opCount);
long copper = Convert.ToInt64(hook.copper * (1.0m + userAttr.addGold) * opCount);
List<TowerGet> award = new List<TowerGet>();
if (!string.IsNullOrEmpty(hook.award))
{
var awardModel = JsonConvert.DeserializeObject<MonsterAwardModel>(hook.award);
if (awardModel.type == nameof(MonsterEnum.AwardCode.Default))
{
var getAward = GameBus.GetRandomGoods(awardModel.award, opCount, userAttr.burst);
award.AddRange(getAward);
}
}
if (await UpdateOnHook(hook.userId, exp, copper))
{
if (exp > 0)
{
await attrService.UpdateUserExp(hook.userId, exp);
}
if (copper > 0)
{
await accService.UpdateUserCopper(hook.userId, 1, copper, "挂机获得");
}
if (award.Count > 0)
{
await GameBus.UpdateBag(hook.userId, 1, award, "挂机获得");
}
}
}
}
}

View File

@@ -121,17 +121,17 @@ public class GameChatService : IGameChatService, ITransient
chat.sign = sign;
chat.state = 1;
chat.addTime = DateTime.Now;
chat.sort = TimeExtend.GetTimeStampSeconds;
chat.sort = TimeExtend.GetTimeStampMilliseconds;
chat.delTime = TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddDays(3));
chat.opUser = "";
switch (code)
{
case "Region":
chat.sort += 300; //五分钟
chat.sort += 300 * 1000; //五分钟
break;
case "Dress":
chat.sort += 600; //10分钟
chat.sort += 600 * 1000; //10分钟
break;
case "System":
chat.delTime = TimeExtend.GetTimeStampBySeconds(DateTime.Now.AddHours(6));

View File

@@ -102,8 +102,8 @@ public class GameFightService(ISqlSugarClient DbClient, IRedisCache redis) : IGa
string scene, string mapId,
string userId, long exp = 0, long copper = 0, long petExp = 0, string award = "", string pars = "")
{
long addTime = TimeExtend.GetTimeStampSeconds;
long endTime = addTime + 24 * 60 * 60;
long addTime = TimeExtend.GetTimeStampMilliseconds;
long endTime = TimeExtend.GetTimeStampSeconds + 24 * 60 * 60;
List<game_fight_data> fights = new List<game_fight_data>();
@@ -170,7 +170,7 @@ public class GameFightService(ISqlSugarClient DbClient, IRedisCache redis) : IGa
public async Task<bool> SetFightWin(game_fight_data fightData, string winUser,bool setDefMap=true)
{
bool result = false;
long okTime = TimeExtend.GetTimeStampSeconds;
long okTime = TimeExtend.GetTimeStampMilliseconds;
var db = DbClient.AsTenant().GetConnectionWithAttr<game_fight_data>();
if (fightData.code == nameof(GameEnum.FightCode.PVE))
{

View File

@@ -243,6 +243,8 @@ public class GameMapService(ISqlSugarClient DbClient, IRedisCache redis) : IGame
else
{
//更新挂机,结束挂机
var hookService = App.GetService<IOnHookService>();
await hookService.StopOnHook(userId);
}
if (mapInfo == null)

View File

@@ -649,6 +649,17 @@ public class UnitUserAttrService(ISqlSugarClient DbClient, IRedisCache redis) :
await redis.DelHashAsync(key, userId);
}
public async Task<decimal> GetUserStateDataTotal(string userId, string scene = "Default")
{
var data = await GetUserStateData(userId, scene);
List<AttrItem> result = new List<AttrItem>();
foreach (var item in data)
{
result.AddRange(item.attr);
}
return GameAttrTool.GetAttrItemValue(nameof(GameEnum.AttrCode.AddExp), result, 0);
}
#endregion
#region

View File

@@ -0,0 +1,24 @@
using Photon.Core.Timer;
using Quartz;
namespace Application.Domain;
public class AutoJob: ITimerAutoJob
{
public async Task Execute(IJobExecutionContext context)
{
string jobId = context.JobDetail.Key.Name;
if (!string.IsNullOrEmpty(jobId))
{
var jobService = App.GetService<IGameAutoJobService>();
var jobData = await jobService.GetJobInfo(jobId);
if (jobData != null)
{
await jobService.HandleJob(jobData);
if (jobData.opType == nameof(GameEnum.JobType.single))
{
await jobService.StopJob(jobId);
}
}
}
}
}

View File

@@ -0,0 +1,69 @@
using Photon.Core.Timer;
using Quartz;
using Quartz.Spi;
namespace Application.Domain;
public class JobStart: ITimerAutoStart
{
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
public JobStart(
ISchedulerFactory schedulerFactory,
IJobFactory jobFactory)
{
_schedulerFactory = schedulerFactory;
_jobFactory = jobFactory;
}
public IScheduler Scheduler { get; private set; }
public async Task StartAsync(CancellationToken cancellationToken)
{
Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
Scheduler.JobFactory = _jobFactory;
// 创建作业
var job = JobBuilder.Create<AutoJob>()
.WithIdentity("DayHandle", "Handle")
.Build();
// 创建触发器
var trigger = TriggerBuilder.Create()
.WithIdentity($"DayHandle_trigger", "Handle")
.WithCronSchedule("0 0 0 * * ? ")
.Build();
await Scheduler.ScheduleJob(job, trigger, cancellationToken);
await Scheduler.Start(cancellationToken);
Console.WriteLine("----航海时代V3自动程序已启动-----");
}
public async Task Begin()
{
Scheduler = await _schedulerFactory.GetScheduler();
Scheduler.JobFactory = _jobFactory;
// 创建作业
var job = JobBuilder.Create<AutoJob>()
.WithIdentity("111", "test")
.Build();
// 创建触发器
var trigger = TriggerBuilder.Create()
.WithIdentity($"111_trigger", "test")
.WithCronSchedule("0/1 * * * * ? ")
.Build();
await Scheduler.ScheduleJob(job, trigger);
await Scheduler.Start();
Console.WriteLine("----探玩驿站自动程序已启动-----");
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Scheduler?.Shutdown(cancellationToken);
}
}

View File

@@ -0,0 +1,57 @@
using Photon.Core.Timer;
using Quartz;
namespace Application.Domain;
public class TimerJobManager : ITimerJobManager
{
private readonly IScheduler _scheduler;
public TimerJobManager(IScheduler scheduler)
{
_scheduler = scheduler;
}
public async Task CreateAndStartTask(string jobId, string group, string cronExpression)
{
// 创建作业
var job = JobBuilder.Create<AutoJob>()
.WithIdentity(jobId, group)
.Build();
// 创建触发器
var trigger = TriggerBuilder.Create()
.WithIdentity($"{jobId}_trigger", group)
.WithCronSchedule(cronExpression)
.Build();
// 安排作业
await _scheduler.ScheduleJob(job, trigger);
// 启动调度器(如果尚未启动)
if (!_scheduler.IsStarted)
{
await _scheduler.Start();
}
}
public async Task PauseTask(string jobId)
{
await _scheduler.PauseJob(new JobKey(jobId, "default"));
}
public async Task ResumeTask(string jobId, string group)
{
await _scheduler.ResumeJob(new JobKey(jobId, group));
}
public async Task DeleteTask(string jobId, string group)
{
await _scheduler.DeleteJob(new JobKey(jobId, group));
}
public async Task DeleteTask(string jobId)
{
await _scheduler.DeleteJob(new JobKey(jobId));
}
}