日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

定时修改列表 服务器版,Unity定时回调(服务端不依赖Update)

發布時間:2024/9/20 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 定时修改列表 服务器版,Unity定时回调(服务端不依赖Update) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

服務器的話就沒有Update了 所以我們要吧計時器從Mono和他自帶的計時方法剝離出來

管理類只做一些簡單的調用 啟動Update

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System;

///

/// 支持時間定時,幀定時

/// 定時任務可循環 取消 替換

///

public class TimerSys : MonoBehaviour

{

//單例

public static TimerSys Instance;

PETimer pt = new PETimer();

public void Init()

{

Instance = this;

pt.SetLog((string info)=> {

Debug.Log("PETimerLog" + info);

});

}

private void Update()

{

pt.Update();

}

///

/// 添加一個計時器

///

///

///

///

///

///

public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

return pt.AddTimeTask(callBack, delay, count, timeUnit);

}

///

/// 移除一個計時器

///

///

///

public bool DeleteTimeTask(int tid)

{

return pt.DeleteTimeTask(tid);

}

///

/// 替換

///

///

///

///

///

///

///

public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

return pt.ReplaceTimeTask(tid, callBack, delay, count, timeUnit);

}

///

/// 添加一個幀計時器

///

///

///

///

///

///

public int AddFrameTask(Action callBack, int delay, int count = 1)

{

return pt.AddFrameTask(callBack, delay, count);

}

///

/// 移除一個幀計時器

///

///

///

public bool DeleteFrameTask(int tid)

{

return pt.DeleteFrameTask(tid);

}

///

/// 替換幀計時器

///

///

///

///

///

///

///

public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)

{

return pt.ReplaceFrameTask(tid, callBack, delay, count);

}

}

把其他邏輯放到另外的類里面

using System.Collections.Generic;

using System;

public class PETimeTask

{

public int tid;

public double destTime;//單位:毫秒

public Action callBack;

public double delay;

public int count;//次數

public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)

{

this.tid = tid;

this.destTime = destTime;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public class PEFrameTask

{

public int tid;

public int destFrame;//單位:毫秒

public Action callBack;

public int delay;

public int count;//次數

public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)

{

this.tid = tid;

this.destFrame = destFrame;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public enum EPETimeUnit

{

Millisecond = 0,

Second,

Minute,

Hour,

Day

}

///

/// 支持時間定時,幀定時

/// 定時任務可循環 取消 替換

///

public class PETimer

{

Action taskLog;

//聲明鎖

static readonly string obj = "lock";

//C#的計時 計算機元年

DateTime startDateTime = new DateTime(1970,1,1,0,0,0);

double nowTime;

int tid;

List tids = new List();

///

/// tid緩存回收

///

List recTids = new List();

///

/// 臨時列表 支持多線程操作 錯開時間操作 避免使用鎖 提升操作效率

///

List tmpTimes = new List();

List taskTimes = new List();

int frameCounter;

List tmpFrames = new List();

List taskFrames = new List();

public PETimer()

{

tids.Clear();

recTids.Clear();

tmpTimes.Clear();

taskTimes.Clear();

tmpFrames.Clear();

taskFrames.Clear();

}

public void Update()

{

CheckTimeTask();

CheckFrameTask();

if (recTids.Count > 0)

{

RecycleTid();

}

}

void CheckTimeTask()

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpTimes.Count; i++)

{

taskTimes.Add(tmpTimes[i]);

}

tmpTimes.Clear();

nowTime = GetUTCMilliseconds();

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskTimes.Count; i++)

{

PETimeTask task = taskTimes[i];

//nowTime>task.destTime 1 nowTime

if (nowTime.CompareTo(task.destTime)<0)

{

continue;

}

else

{

try

{

//時間到 callBack不為空調用

task.callBack?.Invoke();

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskTimes.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destTime += task.delay;

}

}

}

}

void CheckFrameTask()

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpFrames.Count; i++)

{

taskFrames.Add(tmpFrames[i]);

}

tmpFrames.Clear();

frameCounter += 1;

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskFrames.Count; i++)

{

PEFrameTask task = taskFrames[i];

if (frameCounter < task.destFrame)

{

continue;

}

else

{

try

{

//時間到 callBack不為空調用

task.callBack?.Invoke();

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskFrames.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destFrame += task.delay;

}

}

}

}

#region TimeTask

///

/// 添加一個計時器

///

///

///

///

///

///

public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

//時間單位換算 最小毫秒

if (timeUnit != EPETimeUnit.Millisecond)

{

switch (timeUnit)

{

case EPETimeUnit.Second:

delay = delay * 1000;

break;

case EPETimeUnit.Minute:

delay = delay * 1000 * 60;

break;

case EPETimeUnit.Hour:

delay = delay * 1000 * 60 * 60;

break;

case EPETimeUnit.Day:

delay = delay * 1000 * 60 * 60 * 24;

break;

default:

LogInfo("Add Task TimeUnit Type error");

break;

}

}

int tid = GetTid();

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

tmpTimes.Add(new PETimeTask(tid, nowTime+delay, callBack, delay, count));

tids.Add(tid);

return tid;

}

///

/// 移除一個計時器

///

///

///

public bool DeleteTimeTask(int tid)

{

bool exist = false;

for (int i = 0; i < taskTimes.Count; i++)

{

PETimeTask task = taskTimes[i];

if (task.tid == tid)

{

taskTimes.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

if (!exist)

{

for (int i = 0; i < tmpTimes.Count; i++)

{

PETimeTask task = tmpTimes[i];

if (task.tid == tid)

{

tmpTimes.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

}

return exist;

}

///

/// 替換

///

///

///

///

///

///

///

public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

//時間單位換算 最小毫秒

if (timeUnit != EPETimeUnit.Millisecond)

{

switch (timeUnit)

{

case EPETimeUnit.Second:

delay = delay * 1000;

break;

case EPETimeUnit.Minute:

delay = delay * 1000 * 60;

break;

case EPETimeUnit.Hour:

delay = delay * 1000 * 60 * 60;

break;

case EPETimeUnit.Day:

delay = delay * 1000 * 60 * 60 * 24;

break;

default:

LogInfo("Add Task TimeUnit Type error");

break;

}

}

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

PETimeTask newTask = new PETimeTask(tid, nowTime+delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskTimes.Count; i++)

{

if (taskTimes[i].tid == tid)

{

taskTimes[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpTimes.Count; i++)

{

if (tmpTimes[i].tid == tid)

{

tmpTimes[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

#region FrameTask

///

/// 添加一個幀計時器

///

///

///

///

///

///

public int AddFrameTask(Action callBack, int delay, int count = 1)

{

int tid = GetTid();

taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));

tids.Add(tid);

return tid;

}

///

/// 移除一個幀計時器

///

///

///

public bool DeleteFrameTask(int tid)

{

bool exist = false;

for (int i = 0; i < taskFrames.Count; i++)

{

PEFrameTask task = taskFrames[i];

if (task.tid == tid)

{

taskFrames.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

if (!exist)

{

for (int i = 0; i < tmpFrames.Count; i++)

{

PEFrameTask task = tmpFrames[i];

if (task.tid == tid)

{

tmpFrames.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

}

return exist;

}

///

/// 替換幀計時器

///

///

///

///

///

///

///

public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)

{

PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskFrames.Count; i++)

{

if (taskFrames[i].tid == tid)

{

taskFrames[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpFrames.Count; i++)

{

if (tmpFrames[i].tid == tid)

{

tmpFrames[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

public void SetLog(Action log)

{

taskLog = log;

}

#region Tool Methonds

int GetTid()

{

lock (obj)

{

tid += 1;

//安全代碼,以防萬一(服務器)

while (true)

{

if (tid == int.MaxValue)

{

tid = 0;

}

//最后一個歸0后從新賦值唯一id

bool used = false;

for (int i = 0; i < tids.Count; i++)

{

if (tid == tids[i])

{

used = true;

break;

}

}

if (!used)

{

break;

}

else

{

tid += 1;

}

}

}

return tid;

}

///

/// tid回收

///

void RecycleTid()

{

for (int i = 0; i < recTids.Count; i++)

{

int tid = recTids[i];

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

}

recTids.Clear();

}

void LogInfo(string info)

{

taskLog?.Invoke(info);

}

///

/// 獲取時間的方法

///

///

double GetUTCMilliseconds()

{

//Now是本機時間

//現在世界標準時間-計算機元年時間

TimeSpan ts = DateTime.UtcNow - startDateTime;

//返回TimeSpan值表示的毫秒數

return ts.TotalMilliseconds;

}

#endregion

}

調用類不用改變

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System;

///

/// 支持時間定時,幀定時

/// 定時任務可循環 取消 替換

///

public class TimerSys : MonoBehaviour

{

//單例

public static TimerSys Instance;

PETimer pt = new PETimer();

public void Init()

{

Instance = this;

pt.SetLog((string info)=> {

Debug.Log("PETimerLog" + info);

});

}

private void Update()

{

pt.Update();

}

///

/// 添加一個計時器

///

///

///

///

///

///

public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

return pt.AddTimeTask(callBack, delay, count, timeUnit);

}

///

/// 移除一個計時器

///

///

///

public bool DeleteTimeTask(int tid)

{

return pt.DeleteTimeTask(tid);

}

///

/// 替換

///

///

///

///

///

///

///

public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

return pt.ReplaceTimeTask(tid, callBack, delay, count, timeUnit);

}

///

/// 添加一個幀計時器

///

///

///

///

///

///

public int AddFrameTask(Action callBack, int delay, int count = 1)

{

return pt.AddFrameTask(callBack, delay, count);

}

///

/// 移除一個幀計時器

///

///

///

public bool DeleteFrameTask(int tid)

{

return pt.DeleteFrameTask(tid);

}

///

/// 替換幀計時器

///

///

///

///

///

///

///

public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)

{

return pt.ReplaceFrameTask(tid, callBack, delay, count);

}

}

image.png

都沒問題 打開VS新建控制臺程序

image.png

image.png

image.png

找到路徑把之前PETimer代碼粘貼過來 這樣

image.png

進入VS

image.png

選中這倆包括在項目中

image.png

然后在Program里main函數寫調用

然后服務器用計時器定時數量龐大 把計算量分離出來

using System.Collections.Generic;

using System;

using System.Timers;

public class PETimeTask

{

public int tid;

public double destTime;//單位:毫秒

public Action callBack;

public double delay;

public int count;//次數

public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)

{

this.tid = tid;

this.destTime = destTime;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public class PEFrameTask

{

public int tid;

public int destFrame;//單位:毫秒

public Action callBack;

public int delay;

public int count;//次數

public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)

{

this.tid = tid;

this.destFrame = destFrame;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public enum EPETimeUnit

{

Millisecond = 0,

Second,

Minute,

Hour,

Day

}

///

/// 支持時間定時,幀定時

/// 定時任務可循環 取消 替換

///

public class PETimer

{

Action taskLog;

//聲明鎖

static readonly string obj = "lock";

//C#的計時 計算機元年

DateTime startDateTime = new DateTime(1970,1,1,0,0,0,0);

double nowTime;

Timer srvTimer;

int tid;

List tids = new List();

///

/// tid緩存回收

///

List recTids = new List();

///

/// 臨時列表 支持多線程操作 錯開時間操作 避免使用鎖 提升操作效率

///

List tmpTimes = new List();

List taskTimes = new List();

int frameCounter;

List tmpFrames = new List();

List taskFrames = new List();

///

///

///

/// 調用運行間隔服務器用

public PETimer(int interval=0)

{

tids.Clear();

recTids.Clear();

tmpTimes.Clear();

taskTimes.Clear();

tmpFrames.Clear();

taskFrames.Clear();

if (interval!=0)

{

srvTimer = new Timer(interval) {

AutoReset = true //設置是否循環

};

srvTimer.Elapsed += (object sender, ElapsedEventArgs arg) => {

Update();

};

srvTimer.Start();

}

}

public void Update()

{

CheckTimeTask();

CheckFrameTask();

if (recTids.Count > 0)

{

RecycleTid();

}

}

void CheckTimeTask()

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpTimes.Count; i++)

{

taskTimes.Add(tmpTimes[i]);

}

tmpTimes.Clear();

nowTime = GetUTCMilliseconds();

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskTimes.Count; i++)

{

PETimeTask task = taskTimes[i];

//nowTime>task.destTime 1 nowTime

if (nowTime.CompareTo(task.destTime)<0)

{

continue;

}

else

{

try

{

//時間到 callBack不為空調用

task.callBack?.Invoke();

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskTimes.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destTime += task.delay;

}

}

}

}

void CheckFrameTask()

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpFrames.Count; i++)

{

taskFrames.Add(tmpFrames[i]);

}

tmpFrames.Clear();

frameCounter += 1;

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskFrames.Count; i++)

{

PEFrameTask task = taskFrames[i];

if (frameCounter < task.destFrame)

{

continue;

}

else

{

try

{

//時間到 callBack不為空調用

task.callBack?.Invoke();

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskFrames.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destFrame += task.delay;

}

}

}

}

#region TimeTask

///

/// 添加一個計時器

///

///

///

///

///

///

public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

//時間單位換算 最小毫秒

if (timeUnit != EPETimeUnit.Millisecond)

{

switch (timeUnit)

{

case EPETimeUnit.Second:

delay = delay * 1000;

break;

case EPETimeUnit.Minute:

delay = delay * 1000 * 60;

break;

case EPETimeUnit.Hour:

delay = delay * 1000 * 60 * 60;

break;

case EPETimeUnit.Day:

delay = delay * 1000 * 60 * 60 * 24;

break;

default:

LogInfo("Add Task TimeUnit Type error");

break;

}

}

int tid = GetTid();

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

tmpTimes.Add(new PETimeTask(tid, nowTime+delay, callBack, delay, count));

tids.Add(tid);

return tid;

}

///

/// 移除一個計時器

///

///

///

public bool DeleteTimeTask(int tid)

{

bool exist = false;

for (int i = 0; i < taskTimes.Count; i++)

{

PETimeTask task = taskTimes[i];

if (task.tid == tid)

{

taskTimes.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

if (!exist)

{

for (int i = 0; i < tmpTimes.Count; i++)

{

PETimeTask task = tmpTimes[i];

if (task.tid == tid)

{

tmpTimes.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

}

return exist;

}

///

/// 替換

///

///

///

///

///

///

///

public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

//時間單位換算 最小毫秒

if (timeUnit != EPETimeUnit.Millisecond)

{

switch (timeUnit)

{

case EPETimeUnit.Second:

delay = delay * 1000;

break;

case EPETimeUnit.Minute:

delay = delay * 1000 * 60;

break;

case EPETimeUnit.Hour:

delay = delay * 1000 * 60 * 60;

break;

case EPETimeUnit.Day:

delay = delay * 1000 * 60 * 60 * 24;

break;

default:

LogInfo("Add Task TimeUnit Type error");

break;

}

}

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

PETimeTask newTask = new PETimeTask(tid, nowTime+delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskTimes.Count; i++)

{

if (taskTimes[i].tid == tid)

{

taskTimes[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpTimes.Count; i++)

{

if (tmpTimes[i].tid == tid)

{

tmpTimes[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

#region FrameTask

///

/// 添加一個幀計時器

///

///

///

///

///

///

public int AddFrameTask(Action callBack, int delay, int count = 1)

{

int tid = GetTid();

taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));

tids.Add(tid);

return tid;

}

///

/// 移除一個幀計時器

///

///

///

public bool DeleteFrameTask(int tid)

{

bool exist = false;

for (int i = 0; i < taskFrames.Count; i++)

{

PEFrameTask task = taskFrames[i];

if (task.tid == tid)

{

taskFrames.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

if (!exist)

{

for (int i = 0; i < tmpFrames.Count; i++)

{

PEFrameTask task = tmpFrames[i];

if (task.tid == tid)

{

tmpFrames.RemoveAt(i);

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

exist = true;

break;

}

}

}

return exist;

}

///

/// 替換幀計時器

///

///

///

///

///

///

///

public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)

{

PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskFrames.Count; i++)

{

if (taskFrames[i].tid == tid)

{

taskFrames[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpFrames.Count; i++)

{

if (tmpFrames[i].tid == tid)

{

tmpFrames[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

public void SetLog(Action log)

{

taskLog = log;

}

#region Tool Methonds

int GetTid()

{

lock (obj)

{

tid += 1;

//安全代碼,以防萬一(服務器)

while (true)

{

if (tid == int.MaxValue)

{

tid = 0;

}

//最后一個歸0后從新賦值唯一id

bool used = false;

for (int i = 0; i < tids.Count; i++)

{

if (tid == tids[i])

{

used = true;

break;

}

}

if (!used)

{

break;

}

else

{

tid += 1;

}

}

}

return tid;

}

///

/// tid回收

///

void RecycleTid()

{

for (int i = 0; i < recTids.Count; i++)

{

int tid = recTids[i];

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

}

recTids.Clear();

}

void LogInfo(string info)

{

taskLog?.Invoke(info);

}

///

/// 獲取時間的方法

///

///

double GetUTCMilliseconds()

{

//Now是本機時間

//現在世界標準時間-計算機元年時間

TimeSpan ts = DateTime.UtcNow - startDateTime;

//返回TimeSpan值表示的毫秒數

return ts.TotalMilliseconds;

}

#endregion

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using System.Timers;

class Program

{

static void Main(string[] args)

{

//Test1();

//TimerTest();

Test2();

//阻塞讓cw顯示出來

Console.ReadKey();

}

///

/// 在獨立線程檢測并處理

///

private static void Test2()

{

PETimer pt = new PETimer(50);

pt.AddTimeTask(() => {

Console.WriteLine($"Time:{DateTime.Now}");

Console.WriteLine($"Process線程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");

}, 1000, 0);

}

private static void TimerTest()

{

//不聲明會有二義性 每隔50毫秒循環一次 看線程ID 里面封裝有一個線程池 看誰空閑調用誰

System.Timers.Timer t = new System.Timers.Timer(50);

t.AutoReset = true;//可以一直觸發事件

t.Elapsed += (object sender, ElapsedEventArgs arg) => {

Console.WriteLine($"Time:{DateTime.Now}");

Console.WriteLine($"Process線程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");

};

t.Start();

}

///

/// 在主線程檢測并處理

///

private static void Test1()

{

PETimer pt = new PETimer();

pt.SetLog((string info) => {

Console.WriteLine($"ConsoleLog{info}");

});

pt.AddTimeTask(() => {

Console.WriteLine($"Time:{DateTime.Now}");

Console.WriteLine($"Process線程ID:{Thread.CurrentThread.ManagedThreadId.ToString()}");

},1000,0);

while (true)

{

pt.Update();

//休眠20毫秒 不然CPU占用率高

Thread.Sleep(20);

}

}

}

然后就OK了

image.png

然后因為多線程 加上鎖 把數據做安全一點 不然不同線程同時修改就當機了 當然也可能死鎖發生

using System.Collections.Generic;

using System;

using System.Timers;

public class PETimeTask

{

public int tid;

public double destTime;//單位:毫秒

public Action callBack;

public double delay;

public int count;//次數

public PETimeTask(int tid, double destTime, Action callBack, double delay, int count)

{

this.tid = tid;

this.destTime = destTime;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public class PEFrameTask

{

public int tid;

public int destFrame;//單位:毫秒

public Action callBack;

public int delay;

public int count;//次數

public PEFrameTask(int tid, int destFrame, Action callBack, int delay, int count)

{

this.tid = tid;

this.destFrame = destFrame;

this.callBack = callBack;

this.count = count;

this.delay = delay;

}

}

public enum EPETimeUnit

{

Millisecond = 0,

Second,

Minute,

Hour,

Day

}

///

/// 支持時間定時,幀定時

/// 定時任務可循環 取消 替換

///

public class PETimer

{

Action taskLog;

Action, int> taskHandle;

//聲明鎖

static readonly string lockTid = "lockTid";

//C#的計時 計算機元年

DateTime startDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);

double nowTime;

Timer srvTimer;

int tid;

List tids = new List();

///

/// tid緩存回收

///

List recTids = new List();

static readonly string lockTime = "lockTime";

///

/// 臨時列表 支持多線程操作 錯開時間操作 避免使用鎖 提升操作效率

///

List tmpTimes = new List();

List taskTimes = new List();

List tmpDelTimes = new List();

int frameCounter;

static readonly string lockFrame = "lockFrame";

List tmpFrames = new List();

List taskFrames = new List();

List tmpDelFrames = new List();

///

///

///

/// 調用運行間隔服務器用

public PETimer(int interval = 0)

{

if (interval != 0)

{

srvTimer = new Timer(interval)

{

AutoReset = true //設置是否循環

};

srvTimer.Elapsed += (object sender, ElapsedEventArgs arg) =>

{

Update();

};

srvTimer.Start();

}

}

public void Update()

{

CheckTimeTask();

CheckFrameTask();

DelTimeTask();

DelFrameTask();

if (recTids.Count > 0)

{

lock (lockTid)

RecycleTid();

}

}

void DelFrameTask()

{

if (tmpDelFrames.Count > 0)

{

lock (lockFrame)

{

for (int i = 0; i < tmpDelFrames.Count; i++)

{

bool isDel = false;

int delTid = tmpDelFrames[i];

for (int j = 0; j < taskFrames.Count; j++)

{

if (taskFrames[i].tid == delTid)

{

taskFrames.RemoveAt(j);

recTids.Add(delTid);

isDel = true;

LogInfo("Del taskTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

break;

}

}

if (isDel)

{

continue;

}

for (int j = 0; j < tmpFrames.Count; j++)

{

if (tmpFrames[i].tid == delTid)

{

tmpFrames.RemoveAt(j);

recTids.Add(delTid);

LogInfo("Del tmpTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

}

}

}

tmpDelFrames.Clear();

}

}

}

void DelTimeTask()

{

if (tmpDelTimes.Count > 0)

{

lock (lockTime)

{

for (int i = 0; i < tmpDelTimes.Count; i++)

{

bool isDel = false;

int delTid = tmpDelTimes[i];

for (int j = 0; j < taskTimes.Count; j++)

{

if (taskTimes[i].tid == delTid)

{

taskTimes.RemoveAt(j);

recTids.Add(delTid);

isDel = true;

LogInfo("Del taskTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

break;

}

}

if (isDel)

{

continue;

}

for (int j = 0; j < tmpTimes.Count; j++)

{

if (tmpTimes[i].tid == delTid)

{

tmpTimes.RemoveAt(j);

recTids.Add(delTid);

LogInfo("Del tmpTimeList ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

}

}

}

tmpDelTimes.Clear();

}

}

}

void CheckTimeTask()

{

//增加臨時列表 因為服務器循環比update快 為了數據安全

if (tmpTimes.Count > 0)

{

lock (lockTime)

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpTimes.Count; i++)

{

taskTimes.Add(tmpTimes[i]);

}

tmpTimes.Clear();

}

}

nowTime = GetUTCMilliseconds();

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskTimes.Count; i++)

{

PETimeTask task = taskTimes[i];

//nowTime>task.destTime 1 nowTime

if (nowTime.CompareTo(task.destTime) < 0)

{

continue;

}

else

{

try

{

if (taskHandle != null)

{

taskHandle(task.callBack, task.tid);

}

else

{

//時間到 callBack不為空調用

task.callBack?.Invoke(task.tid);

}

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskTimes.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destTime += task.delay;

}

}

}

}

void CheckFrameTask()

{

if (tmpFrames.Count > 0)

{

lock (lockFrame)

{

//加入緩存區中的定時任務

for (int i = 0; i < tmpFrames.Count; i++)

{

taskFrames.Add(tmpFrames[i]);

}

tmpFrames.Clear();

}

}

frameCounter += 1;

//遍歷檢測任務是否到達條件

for (int i = 0; i < taskFrames.Count; i++)

{

PEFrameTask task = taskFrames[i];

if (frameCounter < task.destFrame)

{

continue;

}

else

{

try

{

if (taskHandle != null)

{

taskHandle(task.callBack, task.tid);

}

else

{

//時間到 callBack不為空調用

task.callBack?.Invoke(task.tid);

}

}

catch (Exception e)

{

LogInfo(e.ToString());

}

if (task.count == 1)

{

taskFrames.RemoveAt(i);

i--;

recTids.Add(task.tid);

}

else

{

if (task.count != 0)

{

task.count -= 1;

}

//重新賦值時間

task.destFrame += task.delay;

}

}

}

}

#region TimeTask

///

/// 添加一個計時器

///

///

///

///

///

///

public int AddTimeTask(Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

ChangeTimeWithType(ref delay, timeUnit);

int tid = GetTid();

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

lock (lockTime)

tmpTimes.Add(new PETimeTask(tid, nowTime + delay, callBack, delay, count));

return tid;

}

///

/// 移除一個計時器

///

///

///

public void DeleteTimeTask(int tid)

{

lock (lockTime)

{

tmpDelTimes.Add(tid);

LogInfo("TmpDel ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());

}

}

///

/// 替換 不涉及數據增刪不用去改 自己改的慢就完蛋

///

///

///

///

///

///

///

public bool ReplaceTimeTask(int tid, Action callBack, float delay, int count = 1, EPETimeUnit timeUnit = EPETimeUnit.Millisecond)

{

ChangeTimeWithType(ref delay, timeUnit);

//從游戲開始到現在的時間

nowTime = GetUTCMilliseconds();

PETimeTask newTask = new PETimeTask(tid, nowTime + delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskTimes.Count; i++)

{

if (taskTimes[i].tid == tid)

{

taskTimes[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpTimes.Count; i++)

{

if (tmpTimes[i].tid == tid)

{

tmpTimes[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

#region FrameTask

///

/// 添加一個幀計時器

///

///

///

///

///

///

public int AddFrameTask(Action callBack, int delay, int count = 1)

{

int tid = GetTid();

lock (lockFrame)

taskFrames.Add(new PEFrameTask(tid, frameCounter + delay, callBack, delay, count));

return tid;

}

///

/// 移除一個幀計時器

///

///

///

public void DeleteFrameTask(int tid)

{

lock (lockFrame)

{

tmpDelFrames.Add(tid);

}

}

///

/// 替換幀計時器

///

///

///

///

///

///

///

public bool ReplaceFrameTask(int tid, Action callBack, int delay, int count = 1)

{

PEFrameTask newTask = new PEFrameTask(tid, frameCounter + delay, callBack, delay, count);

bool isRep = false;

for (int i = 0; i < taskFrames.Count; i++)

{

if (taskFrames[i].tid == tid)

{

taskFrames[i] = newTask;

isRep = true;

break;

}

}

if (!isRep)

{

for (int i = 0; i < tmpFrames.Count; i++)

{

if (tmpFrames[i].tid == tid)

{

tmpFrames[i] = newTask;

isRep = true;

break;

}

}

}

return isRep;

}

#endregion

public void SetLog(Action log)

{

taskLog = log;

}

public void SetHandle(Action, int> handle)

{

taskHandle = handle;

}

///

/// 重置

///

public void Reset()

{

tid = 0;

tids.Clear();

recTids.Clear();

tmpTimes.Clear();

taskTimes.Clear();

tmpFrames.Clear();

taskFrames.Clear();

taskLog = null;

srvTimer.Stop();

}

//累加而不是 now now的話打斷點也會變化

public DateTime GetLocalDateTime()

{

return TimeZone.CurrentTimeZone.ToLocalTime(startDateTime.AddMilliseconds(nowTime));

}

public double GetMillisendsTime()

{

return nowTime;

}

public int GetYear()

{

return GetLocalDateTime().Year;

}

public int GetMonth()

{

return GetLocalDateTime().Month;

}

public int GetDay()

{

return GetLocalDateTime().Day;

}

public int GetDayOfWeek()

{

return (int)GetLocalDateTime().DayOfWeek;

}

public string GetLocalTimeStr()

{

DateTime dt = GetLocalDateTime();

string str = $"{GetTimeStr(dt.Hour)}:{GetTimeStr(dt.Minute)}:{GetTimeStr(dt.Second)}";

return str;

}

#region Tool Methonds

int GetTid()

{

lock (lockTid)

{

tid += 1;

//安全代碼,以防萬一(服務器)

while (true)

{

if (tid == int.MaxValue)

{

tid = 0;

}

//最后一個歸0后從新賦值唯一id

bool used = false;

for (int i = 0; i < tids.Count; i++)

{

if (tid == tids[i])

{

used = true;

break;

}

}

if (!used)

{

tids.Add(tid);

break;

}

else

{

tid += 1;

}

}

}

return tid;

}

///

/// tid回收

///

void RecycleTid()

{

for (int i = 0; i < recTids.Count; i++)

{

int tid = recTids[i];

for (int j = 0; j < tids.Count; j++)

{

if (tids[j] == tid)

{

tids.RemoveAt(j);

break;

}

}

}

recTids.Clear();

}

void LogInfo(string info)

{

taskLog?.Invoke(info);

}

///

/// 獲取時間的方法

///

///

double GetUTCMilliseconds()

{

//Now是本機時間

//現在世界標準時間-計算機元年時間

TimeSpan ts = DateTime.UtcNow - startDateTime;

//返回TimeSpan值表示的毫秒數

return ts.TotalMilliseconds;

}

void ChangeTimeWithType(ref float delay, EPETimeUnit timeUnit)

{

//時間單位換算 最小毫秒

if (timeUnit != EPETimeUnit.Millisecond)

{

switch (timeUnit)

{

case EPETimeUnit.Second:

delay = delay * 1000;

break;

case EPETimeUnit.Minute:

delay = delay * 1000 * 60;

break;

case EPETimeUnit.Hour:

delay = delay * 1000 * 60 * 60;

break;

case EPETimeUnit.Day:

delay = delay * 1000 * 60 * 60 * 24;

break;

default:

LogInfo("Add Task TimeUnit Type error");

break;

}

}

}

string GetTimeStr(int time)

{

if (time < 10)

{

return $"0{time}";

}

else

{

return time.ToString();

}

}

#endregion

}

image.png

然后我自己優化了下很簡單的 沒用泛型反射因為這樣會影響性能 畢竟服務器可是管所有客戶端 客戶端的計時器優化差點也沒問題

這個是源碼

https://github.com/1004019267/PETimer/tree/master

總結

以上是生活随笔為你收集整理的定时修改列表 服务器版,Unity定时回调(服务端不依赖Update)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。