From ba86dad0f2c3398aea0ea1901d5299ca8e6866b8 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Sat, 28 Oct 2023 22:35:08 +0800 Subject: [PATCH] feat(SafeValue): :zap: add some SafeValue --- logic/GameClass/GameObj/Areas/Construction.cs | 2 +- logic/GameClass/GameObj/Areas/Home.cs | 2 +- logic/GameClass/GameObj/Areas/Wormhole.cs | 2 +- logic/GameClass/GameObj/Ship.cs | 8 +- logic/Preparation/Interface/IHome.cs | 2 +- logic/Preparation/Interface/IShip.cs | 8 +- logic/Preparation/Utility/SafeValue.cs | 778 -------------- logic/Preparation/Utility/SafeValue/Atomic.cs | 90 ++ .../Utility/SafeValue/InTheRange.cs | 999 ++++++++++++++++++ .../Utility/SafeValue/TimeBased.cs | 512 +++++++++ 10 files changed, 1613 insertions(+), 790 deletions(-) delete mode 100644 logic/Preparation/Utility/SafeValue.cs create mode 100644 logic/Preparation/Utility/SafeValue/Atomic.cs create mode 100644 logic/Preparation/Utility/SafeValue/InTheRange.cs create mode 100644 logic/Preparation/Utility/SafeValue/TimeBased.cs diff --git a/logic/GameClass/GameObj/Areas/Construction.cs b/logic/GameClass/GameObj/Areas/Construction.cs index b1bd2653..b49697da 100644 --- a/logic/GameClass/GameObj/Areas/Construction.cs +++ b/logic/GameClass/GameObj/Areas/Construction.cs @@ -5,7 +5,7 @@ namespace GameClass.GameObj.Areas; public class Construction : Immovable { - public LongWithVariableRange HP => throw new NotImplementedException(); + public LongInTheVariableRange HP => throw new NotImplementedException(); public override bool IsRigid => constructionType == ConstructionType.Community; public override ShapeType Shape => ShapeType.Square; private ConstructionType constructionType = ConstructionType.Null; diff --git a/logic/GameClass/GameObj/Areas/Home.cs b/logic/GameClass/GameObj/Areas/Home.cs index d32cc1ef..369477bc 100644 --- a/logic/GameClass/GameObj/Areas/Home.cs +++ b/logic/GameClass/GameObj/Areas/Home.cs @@ -7,7 +7,7 @@ namespace GameClass.GameObj.Areas; public class Home : Immovable, IHome { public AtomicLong TeamID => throw new NotImplementedException(); - public LongWithVariableRange HP => throw new NotImplementedException(); + public LongInTheVariableRange HP => throw new NotImplementedException(); public long Score => throw new NotImplementedException(); public override bool IsRigid => false; public override ShapeType Shape => ShapeType.Square; diff --git a/logic/GameClass/GameObj/Areas/Wormhole.cs b/logic/GameClass/GameObj/Areas/Wormhole.cs index c68a813e..83ddda46 100644 --- a/logic/GameClass/GameObj/Areas/Wormhole.cs +++ b/logic/GameClass/GameObj/Areas/Wormhole.cs @@ -7,7 +7,7 @@ namespace GameClass.GameObj.Areas; public class Wormhole : Immovable, IWormhole { - public LongWithVariableRange HP => throw new NotImplementedException(); + public LongInTheVariableRange HP => throw new NotImplementedException(); public List Entrance => throw new NotImplementedException(); public List Content => throw new NotImplementedException(); public override bool IsRigid => HP > GameData.WormholeHP / 2; diff --git a/logic/GameClass/GameObj/Ship.cs b/logic/GameClass/GameObj/Ship.cs index 4d031c44..0f1b07bc 100644 --- a/logic/GameClass/GameObj/Ship.cs +++ b/logic/GameClass/GameObj/Ship.cs @@ -21,16 +21,16 @@ public override bool IgnoreCollideExecutor(IGameObj targetObj) return true; return false; } - public LongWithVariableRange HP { get; } - public LongWithVariableRange Armor { get; } - public LongWithVariableRange Shield { get; } + public LongInTheVariableRange HP { get; } + public LongInTheVariableRange Armor { get; } + public LongInTheVariableRange Shield { get; } private ShipType shipType = ShipType.Null; public ShipType ShipType => shipType; private ShipStateType shipState = ShipStateType.Null; public ShipStateType ShipState => shipState; private readonly IOccupation occupation; public IOccupation Occupation => occupation; - public IntNumUpdateByCD BulletNum { get; } + public IntNumUpdateEachCD BulletNum { get; } private IProducer? producer = null; public IProducer? ProducerModule => producer; private IConstructor? constructor = null; diff --git a/logic/Preparation/Interface/IHome.cs b/logic/Preparation/Interface/IHome.cs index 76cf7443..02857a37 100644 --- a/logic/Preparation/Interface/IHome.cs +++ b/logic/Preparation/Interface/IHome.cs @@ -5,7 +5,7 @@ namespace Preparation.Interface public interface IHome { public AtomicLong TeamID { get; } - public LongWithVariableRange HP { get; } + public LongInTheVariableRange HP { get; } public long Score { get; } public void AddScore(long add); } diff --git a/logic/Preparation/Interface/IShip.cs b/logic/Preparation/Interface/IShip.cs index b02092ec..5827b74a 100644 --- a/logic/Preparation/Interface/IShip.cs +++ b/logic/Preparation/Interface/IShip.cs @@ -5,12 +5,12 @@ namespace Preparation.Interface public interface IShip : IMovable { public AtomicLong TeamID { get; } - public LongWithVariableRange HP { get; } - public LongWithVariableRange Armor { get; } - public LongWithVariableRange Shield { get; } + public LongInTheVariableRange HP { get; } + public LongInTheVariableRange Armor { get; } + public LongInTheVariableRange Shield { get; } public ShipType ShipType { get; } public ShipStateType ShipState { get; } - public IntNumUpdateByCD BulletNum { get; } + public IntNumUpdateEachCD BulletNum { get; } public long SetShipState(RunningStateType running, ShipStateType value = ShipStateType.Null, IGameObj? obj = null); public bool ResetShipState(long state, RunningStateType running = RunningStateType.Null, ShipStateType value = ShipStateType.Null, IGameObj? obj = null); } diff --git a/logic/Preparation/Utility/SafeValue.cs b/logic/Preparation/Utility/SafeValue.cs deleted file mode 100644 index 5f73bb17..00000000 --- a/logic/Preparation/Utility/SafeValue.cs +++ /dev/null @@ -1,778 +0,0 @@ -using System; -using System.Threading; - -namespace Preparation.Utility -{ - //理论上结构体最好不可变,这里采用了可变结构。 - //其对应属性不应当有set访问器,避免不安全的=赋值 - public class AtomicInt - { - private int v; - public AtomicInt(int x) - { - v = x; - } - public override string ToString() => Interlocked.CompareExchange(ref v, -1, -1).ToString(); - public int Get() => Interlocked.CompareExchange(ref v, -1, -1); - public static implicit operator int(AtomicInt aint) => Interlocked.CompareExchange(ref aint.v, -1, -1); - /// 返回操作前的值 - public int SetReturnOri(int value) => Interlocked.Exchange(ref v, value); - public int Add(int x) => Interlocked.Add(ref v, x); - public int Sub(int x) => Interlocked.Add(ref v, -x); - public int Inc() => Interlocked.Increment(ref v); - public int Dec() => Interlocked.Decrement(ref v); - /// 返回操作前的值 - public int CompareExReturnOri(int newV, int compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); - } - - public class AtomicLong - { - private long v; - public AtomicLong(long x) - { - v = x; - } - public override string ToString() => Interlocked.Read(ref v).ToString(); - public long Get() => Interlocked.Read(ref v); - public static implicit operator long(AtomicLong aint) => Interlocked.Read(ref aint.v); - /// 返回操作前的值 - public long SetReturnOri(long value) => Interlocked.Exchange(ref v, value); - public long Add(long x) => Interlocked.Add(ref v, x); - public long Sub(long x) => Interlocked.Add(ref v, -x); - public long Inc() => Interlocked.Increment(ref v); - public long Dec() => Interlocked.Decrement(ref v); - /// 返回操作前的值 - public long CompareExReturnOri(long newV, long compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); - } - - public class AtomicBool - { - private int v;//v==0为false,v==1为true - public AtomicBool(bool x) - { - v = x ? 1 : 0; - } - public override string ToString() => (Interlocked.CompareExchange(ref v, -2, -2) == 0) ? "false" : "true"; - public bool Get() => (Interlocked.CompareExchange(ref v, -1, -1) != 0); - public static implicit operator bool(AtomicBool abool) => (Interlocked.CompareExchange(ref abool.v, -1, -1) != 0); - /// 返回操作前的值 - public bool SetReturnOri(bool value) => (Interlocked.Exchange(ref v, value ? 1 : 0) != 0); - /// 赋值前的值是否与将赋予的值不相同 - public bool TrySet(bool value) - { - return (Interlocked.CompareExchange(ref v, value ? 1 : 0, value ? 0 : 1) ^ (value ? 1 : 0)) != 0; - } - public bool And(bool x) => Interlocked.And(ref v, x ? 1 : 0) != 0; - public bool Or(bool x) => Interlocked.Or(ref v, x ? 1 : 0) != 0; - } - - /// - /// 根据时间推算Start后完成多少进度的进度条(long)。 - /// 只允许Start时修改needTime(请确保大于0); - /// 支持TrySet0使未完成的进度条终止清零;支持Set0使进度条强制终止清零; - /// 通过原子操作实现。 - /// - public class LongProgressByTime - { - private long endT = long.MaxValue; - private long needT; - - public LongProgressByTime(long needTime) - { - if (needTime <= 0) Debugger.Output("Bug:LongProgressByTime.needTime (" + needTime.ToString() + ") is less than 0."); - this.needT = needTime; - } - public LongProgressByTime() - { - this.needT = 0; - } - public long GetEndTime() => Interlocked.CompareExchange(ref endT, -2, -2); - public long GetNeedTime() => Interlocked.CompareExchange(ref needT, -2, -2); - public override string ToString() => "EndTime:" + Interlocked.CompareExchange(ref endT, -2, -2).ToString() + " ms, NeedTime:" + Interlocked.CompareExchange(ref needT, -2, -2).ToString() + " ms"; - public bool IsFinished() - { - return Interlocked.CompareExchange(ref endT, -2, -2) <= Environment.TickCount64; - } - public bool IsOpened() => Interlocked.Read(ref endT) != long.MaxValue; - /// - /// GetProgress<0则表明未开始 - /// - public long GetProgress() - { - long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; - if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); - return Interlocked.CompareExchange(ref needT, -2, -2) - cutime; - } - public long GetNonNegativeProgress() - { - long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; - if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); - long progress = Interlocked.CompareExchange(ref needT, -2, -2) - cutime; - return progress < 0 ? 0 : progress; - } - /// - /// GetProgress<0则表明未开始 - /// - public long GetProgress(long time) - { - long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - time; - if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); - return Interlocked.CompareExchange(ref needT, -2, -2) - cutime; - } - public long GetNonNegativeProgress(long time) - { - long cutime = Interlocked.Read(ref endT) - time; - if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); - long progress = Interlocked.CompareExchange(ref needT, -2, -2) - cutime; - return progress < 0 ? 0 : progress; - } - /// - /// <0则表明未开始 - /// - public static implicit operator long(LongProgressByTime pLong) => pLong.GetProgress(); - - /// - /// GetProgressDouble<0则表明未开始 - /// - public double GetProgressDouble() - { - long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; - if (cutime <= 0) return 1; - long needTime = Interlocked.CompareExchange(ref needT, -2, -2); - if (needTime == 0) return 0; - return 1.0 - ((double)cutime / needTime); - } - public double GetNonNegativeProgressDouble(long time) - { - long cutime = Interlocked.Read(ref endT) - time; - if (cutime <= 0) return 1; - long needTime = Interlocked.CompareExchange(ref needT, -2, -2); - if (needTime <= cutime) return 0; - return 1.0 - ((double)cutime / needTime); - } - - public bool Start(long needTime) - { - if (needTime <= 0) - { - Debugger.Output("Warning:Start LongProgressByTime with the needTime (" + needTime.ToString() + ") which is less than 0."); - return false; - } - //规定只有Start可以修改needT,且需要先访问endTime,从而避免锁(某种程度上endTime可以认为是needTime的锁) - if (Interlocked.CompareExchange(ref endT, Environment.TickCount64 + needTime, long.MaxValue) != long.MaxValue) return false; - if (needTime <= 2) Debugger.Output("Warning:the field of LongProgressByTime is " + needTime.ToString() + ",which is too small."); - Interlocked.Exchange(ref needT, needTime); - return true; - } - public bool Start() - { - long needTime = Interlocked.CompareExchange(ref needT, -2, -2); - if (Interlocked.CompareExchange(ref endT, Environment.TickCount64 + needTime, long.MaxValue) != long.MaxValue) return false; - return true; - } - /// - /// 使进度条强制终止清零 - /// - public void Set0() => Interlocked.Exchange(ref endT, long.MaxValue); - /// - /// 使未完成的进度条终止清零 - /// - public bool TrySet0() - { - if (Environment.TickCount64 < Interlocked.CompareExchange(ref endT, -2, -2)) - { - Interlocked.Exchange(ref endT, long.MaxValue); - return true; - } - return false; - } - //增加其他新的写操作可能导致不安全 - } - - /* - /// - /// 记录(不是根据时间)完成多少进度的进度条(long)。 - /// - public struct IntProgressByAdding - { - private int completedProgress = -1; - private int requiredProgress; - public IntProgressByAdding(int completedProgress, int requiredProgress) - { - this.completedProgress = completedProgress; - this.requiredProgress = requiredProgress; - } - public IntProgressByAdding(int requiredProgress) - { - this.requiredProgress = requiredProgress; - } - public IntProgressByAdding() - { - this.requiredProgress=int.MaxValue; - } - } - */ - - /// - /// 一个保证在[0,maxValue]的可变int,支持可变的maxValue(请确保大于0) - /// - public class IntWithVariableRange - { - private int v; - private int maxV; - private readonly object vLock = new(); - public IntWithVariableRange(int value, int maxValue) - { - if (maxValue < 0) - { - Debugger.Output("Warning:Try to set IntWithVariableRange.maxValue to " + maxValue.ToString() + "."); - maxValue = 0; - } - v = value < maxValue ? value : maxValue; - this.maxV = maxValue; - } - /// - /// 默认使Value=maxValue - /// - public IntWithVariableRange(int maxValue) - { - if (maxValue < 0) - { - Debugger.Output("Warning:Try to set IntWithVariableRange.maxValue to " + maxValue.ToString() + "."); - maxValue = 0; - } - v = this.maxV = maxValue; - } - public IntWithVariableRange() - { - v = this.maxV = int.MaxValue; - } - - public override string ToString() - { - lock (vLock) - { - return "value:" + v.ToString() + " ,maxValue:" + maxV.ToString(); - } - } - public int GetValue() { lock (vLock) return v; } - public static implicit operator int(IntWithVariableRange aint) => aint.GetValue(); - public int GetMaxV() { lock (vLock) return maxV; } - - /// - /// 若maxValue<=0则maxValue设为0并返回False - /// - public bool SetMaxV(int maxValue) - { - if (maxValue < 0) maxValue = 0; - lock (vLock) - { - maxV = maxValue; - if (v > maxValue) v = maxValue; - } - return maxValue > 0; - } - /// - /// 应当保证该maxValue>=0 - /// - public void SetPositiveMaxV(int maxValue) - { - lock (vLock) - { - maxV = maxValue; - if (v > maxValue) v = maxValue; - } - } - /// - /// 应当保证该value>=0 - /// - public int SetPositiveV(int value) - { - lock (vLock) - { - return v = (value > maxV) ? maxV : value; - } - } - public int SetV(int value) - { - if (value < 0) value = 0; - lock (vLock) - { - return v = (value > maxV) ? maxV : value; - } - } - /// - /// 返回实际改变量 - /// - public int AddV(int addV) - { - lock (vLock) - { - int previousV = v; - v += addV; - if (v < 0) v = 0; - if (v > maxV) v = maxV; - return v - previousV; - } - } - /// - /// 应当保证该增加值大于0,返回实际改变量 - /// - public int AddPositiveV(int addPositiveV) - { - lock (vLock) - { - addPositiveV = Math.Min(addPositiveV, maxV - v); - v += addPositiveV; - } - return addPositiveV; - } - /// - /// 应当保证该减少值大于0,返回实际改变量 - /// - public int SubPositiveV(int subPositiveV) - { - lock (vLock) - { - subPositiveV = Math.Min(subPositiveV, v); - v -= subPositiveV; - } - return subPositiveV; - } - - /// - /// 试图加到满,如果无法加到maxValue则不加并返回-1 - /// - public int TryAddAll(int addV) - { - lock (vLock) - { - if (maxV - v <= addV) - { - addV = maxV - v; - v = maxV; - return addV; - } - return 0; - } - } - } - - /// - /// 一个保证在[0,maxValue]的可变long,支持可变的maxValue(请确保大于0) - /// - public class LongWithVariableRange - { - private long v; - private long maxV; - private readonly object vLock = new(); - public LongWithVariableRange(long value, long maxValue) - { - if (maxValue < 0) - { - Debugger.Output("Warning:Try to set SafaValues.LongWithVariableRange.maxValue to " + maxValue.ToString() + "."); - maxValue = 0; - } - v = value < maxValue ? value : maxValue; - this.maxV = maxValue; - } - /// - /// 默认使Value=maxValue - /// - public LongWithVariableRange(long maxValue) - { - if (maxValue < 0) - { - Debugger.Output("Warning:Try to set SafaValues.LongWithVariableRange.maxValue to " + maxValue.ToString() + "."); - maxValue = 0; - } - v = this.maxV = maxValue; - } - public LongWithVariableRange() - { - v = this.maxV = long.MaxValue; - } - - public override string ToString() - { - lock (vLock) - { - return "value:" + v.ToString() + " ,maxValue:" + maxV.ToString(); - } - } - public long GetValue() { lock (vLock) return v; } - public static implicit operator long(LongWithVariableRange aint) => aint.GetValue(); - public long GetMaxV() { lock (vLock) return maxV; } - - /// - /// 若maxValue<=0则maxValue设为0并返回False - /// - public bool SetMaxV(long maxValue) - { - if (maxValue < 0) maxValue = 0; - lock (vLock) - { - maxV = maxValue; - if (v > maxValue) v = maxValue; - } - return maxValue > 0; - } - /// - /// 应当保证该maxValue>=0 - /// - public void SetPositiveMaxV(long maxValue) - { - lock (vLock) - { - maxV = maxValue; - if (v > maxValue) v = maxValue; - } - } - /// - /// 应当保证该value>=0 - /// - public long SetPositiveV(long value) - { - lock (vLock) - { - return v = (value > maxV) ? maxV : value; - } - } - public long SetV(long value) - { - if (value < 0) value = 0; - lock (vLock) - { - return v = (value > maxV) ? maxV : value; - } - } - /// - /// 返回实际改变量 - /// - public long AddV(long addV) - { - lock (vLock) - { - long previousV = v; - v += addV; - if (v < 0) v = 0; - if (v > maxV) v = maxV; - return v - previousV; - } - } - /// - /// 应当保证该增加值大于0,返回实际改变量 - /// - public long AddPositiveV(long addPositiveV) - { - lock (vLock) - { - addPositiveV = Math.Min(addPositiveV, maxV - v); - v += addPositiveV; - } - return addPositiveV; - } - /// - /// 应当保证该减少值大于0,返回实际改变量 - /// - public long SubPositiveV(long subPositiveV) - { - lock (vLock) - { - subPositiveV = Math.Min(subPositiveV, v); - v -= subPositiveV; - } - return subPositiveV; - } - - /// - /// 试图加到满,如果无法加到maxValue则不加并返回-1 - /// - public long TryAddAll(long addV) - { - lock (vLock) - { - if (maxV - v <= addV) - { - addV = maxV - v; - v = maxV; - return addV; - } - return -1; - } - } - } - - /// - /// 一个保证在[0,maxNum],每CDms自动+1的int,支持可变的CD、maxNum(请确保大于0) - /// - public class IntNumUpdateByCD - { - private int num; - private int maxNum; - private int cd; - private long updateTime = 0; - private readonly object numLock = new(); - public IntNumUpdateByCD(int num, int maxNum, int cd) - { - if (num < 0) Debugger.Output("Bug:IntNumUpdateByCD.num (" + num.ToString() + ") is less than 0."); - if (maxNum < 0) Debugger.Output("Bug:IntNumUpdateByCD.maxNum (" + maxNum.ToString() + ") is less than 0."); - if (cd <= 0) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 0."); - this.num = (num < maxNum) ? num : maxNum; - this.maxNum = maxNum; - this.cd = cd; - this.updateTime = Environment.TickCount64; - } - /// - /// 默认使num=maxNum - /// - public IntNumUpdateByCD(int maxNum, int cd) - { - if (maxNum < 0) Debugger.Output("Bug:IntNumUpdateByCD.maxNum (" + maxNum.ToString() + ") is less than 0."); - if (cd <= 0) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 0."); - this.num = this.maxNum = maxNum; - this.cd = cd; - } - public IntNumUpdateByCD() - { - this.num = this.maxNum = 0; - this.cd = int.MaxValue; - } - - public int GetMaxNum() { lock (numLock) return maxNum; } - public int GetCD() { lock (numLock) return cd; } - public int GetNum(long time) - { - lock (numLock) - { - if (num < maxNum && time - updateTime >= cd) - { - int add = (int)Math.Min(maxNum - num, (time - updateTime) / cd); - updateTime += add * cd; - return (num += add); - } - return num; - } - } - public static implicit operator int(IntNumUpdateByCD aint) => aint.GetNum(Environment.TickCount64); - - /// - /// 应当保证该subV>=0 - /// - public int TrySub(int subV) - { - if (subV < 0) Debugger.Output("Bug:IntNumUpdateByCD Try to sub " + subV.ToString() + ", which is less than 0."); - long time = Environment.TickCount64; - lock (numLock) - { - if (num < maxNum && time - updateTime >= cd) - { - int add = (int)Math.Min(maxNum - num, (time - updateTime) / cd); - updateTime += add * cd; - num += add; - } - if (num == maxNum) updateTime = time; - num -= subV = Math.Min(subV, num); - } - return subV; - } - /// - /// 应当保证该addV>=0 - /// - public void TryAdd(int addV) - { - if (addV < 0) Debugger.Output("Bug:IntNumUpdateByCD Try to add " + addV.ToString() + ", which is less than 0."); - lock (numLock) - { - num += Math.Min(addV, maxNum - num); - } - } - /// - /// 若maxNum<=0则maxNum及Num设为0并返回False - /// - public bool SetMaxNumAndNum(int maxNum) - { - if (maxNum < 0) maxNum = 0; - lock (numLock) - { - this.num = this.maxNum = maxNum; - } - return maxNum > 0; - } - /// - /// 应当保证该maxnum>=0 - /// - public void SetPositiveMaxNumAndNum(int maxNum) - { - lock (numLock) - { - this.num = this.maxNum = maxNum; - } - } - /// - /// 应当保证该maxnum>=0 - /// - public void SetPositiveMaxNum(int maxNum) - { - lock (numLock) - { - if ((this.maxNum = maxNum) < num) - num = maxNum; - } - } - /// - /// 若maxNum<=0则maxNum及Num设为0并返回False - /// - public bool SetMaxNum(int maxNum) - { - if (maxNum < 0) maxNum = 0; - lock (numLock) - { - if ((this.maxNum = maxNum) < num) - num = maxNum; - } - return maxNum > 0; - } - /// - /// 若num<0则num设为0并返回False - /// - public bool SetNum(int num) - { - lock (numLock) - { - if (num < 0) - { - this.num = 0; - updateTime = Environment.TickCount64; - return false; - } - if (num < maxNum) - { - if (this.num == maxNum) updateTime = Environment.TickCount64; - this.num = num; - } - else this.num = maxNum; - return true; - } - } - /// - /// 应当保证该num>=0 - /// - public void SetPositiveNum(int num) - { - lock (numLock) - { - if (num < maxNum) - { - if (this.num == maxNum) updateTime = Environment.TickCount64; - this.num = num; - } - else this.num = maxNum; - } - } - public void SetCD(int cd) - { - lock (numLock) - { - if (cd <= 0) Debugger.Output("Bug:SetReturnOri IntNumUpdateByCD.cd to " + cd.ToString() + "."); - this.cd = cd; - } - } - } - - /// - /// 一个每CDms自动更新冷却的bool,支持可变的无锁CD,不支持查看当前进度,初始为True - /// - public class BoolCoolingDownByCD - { - private long cd; - private long nextUpdateTime = 0; - public BoolCoolingDownByCD(int cd) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - } - public BoolCoolingDownByCD(long cd) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - } - public BoolCoolingDownByCD(long cd, long startTime) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - this.nextUpdateTime = startTime; - } - - public long GetCD() => Interlocked.Read(ref cd); - - public bool TryUse() - { - long needTime = Interlocked.Exchange(ref nextUpdateTime, long.MaxValue); - if (needTime <= Environment.TickCount64) - { - Interlocked.Exchange(ref nextUpdateTime, Environment.TickCount64 + Interlocked.Read(ref cd)); - return true; - } - Interlocked.Exchange(ref nextUpdateTime, needTime); - return false; - } - public void SetCD(int cd) - { - if (cd <= 1) Debugger.Output("Bug:SetReturnOri IntNumUpdateByCD.cd to " + cd.ToString() + "."); - Interlocked.Exchange(ref this.cd, cd); - } - } - - /// - /// 一个每CDms自动更新的进度条,支持可变的CD,初始为满 - /// - public class LongProgressCoolingDownByCD - { - private int isusing = 0; - private long cd; - private long nextUpdateTime = 0; - public LongProgressCoolingDownByCD(int cd) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - } - public LongProgressCoolingDownByCD(long cd) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - } - public LongProgressCoolingDownByCD(long cd, long startTime) - { - if (cd <= 1) Debugger.Output("Bug:IntNumUpdateByCD.cd (" + cd.ToString() + ") is less than 1."); - this.cd = cd; - this.nextUpdateTime = startTime; - } - - public long GetRemainingTime() - { - long v = Interlocked.Read(ref nextUpdateTime) - Environment.TickCount64; - return v < 0 ? 0 : v; - } - public long GetCD() => Interlocked.Read(ref cd); - - public bool TryUse() - { - if (Interlocked.Exchange(ref isusing, 1) == 1) return false; - long needTime = Interlocked.Read(ref nextUpdateTime); - if (needTime <= Environment.TickCount64) - { - Interlocked.Exchange(ref nextUpdateTime, Environment.TickCount64 + Interlocked.Read(ref cd)); - Interlocked.Exchange(ref isusing, 0); - return true; - } - Interlocked.Exchange(ref isusing, 0); - return false; - } - public void SetCD(int cd) - { - if (cd <= 1) Debugger.Output("Bug:SetReturnOri IntNumUpdateByCD.cd to " + cd.ToString() + "."); - Interlocked.Exchange(ref this.cd, cd); - } - } -} diff --git a/logic/Preparation/Utility/SafeValue/Atomic.cs b/logic/Preparation/Utility/SafeValue/Atomic.cs new file mode 100644 index 00000000..da6ebaa7 --- /dev/null +++ b/logic/Preparation/Utility/SafeValue/Atomic.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading; + +namespace Preparation.Utility +{ + //其对应属性不应当有set访问器,避免不安全的=赋值 + public abstract class Atomic + { + } + + public class AtomicInt : Atomic + { + private int v; + public AtomicInt(int x) + { + v = x; + } + public override string ToString() => Interlocked.CompareExchange(ref v, -1, -1).ToString(); + public int Get() => Interlocked.CompareExchange(ref v, -1, -1); + public static implicit operator int(AtomicInt aint) => Interlocked.CompareExchange(ref aint.v, -1, -1); + /// 返回操作前的值 + public int SetReturnOri(int value) => Interlocked.Exchange(ref v, value); + public int Add(int x) => Interlocked.Add(ref v, x); + public int Sub(int x) => Interlocked.Add(ref v, -x); + public int Inc() => Interlocked.Increment(ref v); + public int Dec() => Interlocked.Decrement(ref v); + /// 返回操作前的值 + public int CompareExReturnOri(int newV, int compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); + } + + public class AtomicLong : Atomic + { + private long v; + public AtomicLong(long x) + { + v = x; + } + public override string ToString() => Interlocked.Read(ref v).ToString(); + public long Get() => Interlocked.Read(ref v); + public static implicit operator long(AtomicLong along) => Interlocked.Read(ref along.v); + /// 返回操作前的值 + public long SetReturnOri(long value) => Interlocked.Exchange(ref v, value); + public long Add(long x) => Interlocked.Add(ref v, x); + public long Sub(long x) => Interlocked.Add(ref v, -x); + public long Inc() => Interlocked.Increment(ref v); + public long Dec() => Interlocked.Decrement(ref v); + /// 返回操作前的值 + public long CompareExReturnOri(long newV, long compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); + } + + public class AtomicDouble : Atomic + { + private double v; + public AtomicDouble(double x) + { + v = x; + } + public override string ToString() => Interlocked.CompareExchange(ref v, -2.0, -2.0).ToString(); + public double Get() => Interlocked.CompareExchange(ref v, -2.0, -2.0); + public static implicit operator double(AtomicDouble adouble) => Interlocked.CompareExchange(ref adouble.v, -2.0, -2.0); + /// 返回操作前的值 + public double SetReturnOri(double value) => Interlocked.Exchange(ref v, value); + /// 返回操作前的值 + public double CompareExReturnOri(double newV, double compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); + } + + public class AtomicBool : Atomic + { + private int v;//v&1==0为false,v&1==1为true + public AtomicBool(bool x) + { + v = x ? 1 : 0; + } + public override string ToString() => ((Interlocked.CompareExchange(ref v, -2, -2) & 1) == 0) ? "false" : "true"; + public bool Get() => ((Interlocked.CompareExchange(ref v, -2, -2) & 1) == 1); + public static implicit operator bool(AtomicBool abool) => abool.Get(); + /// 返回操作前的值 + public bool SetReturnOri(bool value) => ((Interlocked.Exchange(ref v, value ? 1 : 0) & 1) == 1); + /// 赋值前的值是否与将赋予的值不相同 + public bool TrySet(bool value) + { + return ((Interlocked.Exchange(ref v, value ? 1 : 0) & 1) != (value ? 1 : 0)); + } + public bool And(bool x) => (Interlocked.And(ref v, x ? 1 : 0) & 1) == 1; + public bool Or(bool x) => (Interlocked.Or(ref v, x ? 1 : 0) & 1) == 1; + /// 返回操作后的值 + public bool Reverse() => (Interlocked.Increment(ref v) & 1) == 1; + public bool Xor(bool x) => (Interlocked.Add(ref v, x ? 1 : 0) & 1) == 1; + } +} \ No newline at end of file diff --git a/logic/Preparation/Utility/SafeValue/InTheRange.cs b/logic/Preparation/Utility/SafeValue/InTheRange.cs new file mode 100644 index 00000000..3c8a9cae --- /dev/null +++ b/logic/Preparation/Utility/SafeValue/InTheRange.cs @@ -0,0 +1,999 @@ +using System; +using System.Threading; + +namespace Preparation.Utility +{ + //其对应属性不应当有set访问器,避免不安全的=赋值 + + public class InTheVariableRange + { + protected readonly object vLock = new(); + public object VLock => vLock; + private static int numOfClass = 0; + public static int NumOfClass => numOfClass; + public readonly int idInClass; + public int IdInClass => idInClass; + public InTheVariableRange() + { + idInClass = Interlocked.Increment(ref numOfClass); + } + } + + /// + /// 一个保证在[0,maxValue]的可变int,支持可变的maxValue(请确保大于0) + /// + public class IntInTheVariableRange : InTheVariableRange + { + private int v; + private int maxV; + #region 构造与读取 + public IntInTheVariableRange(int value, int maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set IntInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = value < maxValue ? value : maxValue; + this.maxV = maxValue; + } + /// + /// 默认使Value=maxValue + /// + public IntInTheVariableRange(int maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set IntInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = this.maxV = maxValue; + } + public IntInTheVariableRange() : base() + { + v = this.maxV = int.MaxValue; + } + + public override string ToString() + { + lock (vLock) + { + return "value:" + v.ToString() + " , maxValue:" + maxV.ToString(); + } + } + public int GetValue() { lock (vLock) return v; } + public static implicit operator int(IntInTheVariableRange aint) => aint.GetValue(); + public int GetMaxV() { lock (vLock) return maxV; } + public (int, int) GetValueAndMaxV() { lock (vLock) return (v, maxV); } + public bool IsMaxV() { lock (vLock) return v == maxV; } + #endregion + + #region 内嵌读取(在锁的情况下读取内容同时读取其他更基本的外部数据) + public (int, long) GetValue(StartTime startTime) + { + lock (vLock) + { + return (v, startTime.Get()); + } + } + public (int, int, long) GetValueAndMaxValue(StartTime startTime) + { + lock (vLock) + { + return (v, maxV, startTime.Get()); + } + } + #endregion + + #region 普通设置MaxV与Value的值的方法 + /// + /// 若maxValue<=0则maxValue设为0并返回False + /// + public bool SetMaxV(int maxValue) + { + if (maxValue <= 0) + { + lock (vLock) + { + v = maxV = 0; + return false; + } + } + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + return true; + } + /// + /// 应当保证该maxValue>=0 + /// + public void SetPositiveMaxV(int maxValue) + { + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + } + + public int SetV(int value) + { + if (value <= 0) + { + lock (vLock) + { + return v = 0; + } + } + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + /// + /// 应当保证该value>=0 + /// + public int SetPositiveV(int value) + { + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + #endregion + + #region 特殊条件的设置MaxV与Value的值的方法 + /// + /// 如果当前值大于maxValue,则更新maxValue失败 + /// + public bool TrySetMaxV(int maxValue) + { + lock (vLock) + { + if (v > maxValue) return false; + maxV = maxValue; + return true; + } + } + public bool Set0IfNotMaxor0() + { + lock (vLock) + { + if (v < maxV && v > 0) + { + v = 0; + return true; + } + } + return false; + } + public bool Set0IfMax() + { + lock (vLock) + { + if (v == maxV) + { + v = 0; + return true; + } + } + return false; + } + #endregion + + #region 普通运算 + /// 返回实际改变量 + public int AddV(int addV) + { + lock (vLock) + { + int previousV = v; + v += addV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证增加值大于0 + /// + /// 返回实际改变量 + public int AddPositiveV(int addPositiveV) + { + lock (vLock) + { + addPositiveV = Math.Min(addPositiveV, maxV - v); + v += addPositiveV; + } + return addPositiveV; + } + public void MulV(int mulV) + { + if (mulV <= 0) + { + lock (vLock) v = 0; + return; + } + lock (vLock) + { + if (v > maxV / mulV) v = maxV; //避免溢出 + else v *= mulV; + } + } + public void MulV(double mulV) + { + if (mulV <= 0) + { + lock (vLock) v = 0; + return; + } + lock (vLock) + { + if (v > maxV / mulV) v = maxV; //避免溢出 + else v = (int)(v * mulV); + } + } + /// + /// 应当保证乘数大于0 + /// + public void MulPositiveV(int mulPositiveV) + { + lock (vLock) + { + if (v > maxV / mulPositiveV) v = maxV; //避免溢出 + else v *= mulPositiveV; + } + } + /// + /// 应当保证乘数大于0 + /// + public void MulPositiveV(double mulPositiveV) + { + lock (vLock) + { + if (v > maxV / mulPositiveV) v = maxV; //避免溢出 + else v = (int)(v * mulPositiveV); + } + } + /// 返回实际改变量 + public int SubV(int subV) + { + lock (vLock) + { + int previousV = v; + v -= subV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证该减少值大于0 + /// + /// 返回实际改变量 + public int SubPositiveV(int subPositiveV) + { + lock (vLock) + { + subPositiveV = Math.Min(subPositiveV, v); + v -= subPositiveV; + } + return subPositiveV; + } + #endregion + + #region 特殊条件的运算 + /// + /// 试图加到满,如果无法加到maxValue则不加并返回-1 + /// + /// 返回实际改变量 + public int TryAddToMaxV(int addV) + { + lock (vLock) + { + if (maxV - v <= addV) + { + addV = maxV - v; + v = maxV; + return addV; + } + return -1; + } + } + #endregion + + #region 与InTheVariableRange类的运算,运算会影响该对象的值 + public int AddV(IntInTheVariableRange a) + { + if (this.idInClass == a.idInClass) return -1; + bool thisLock = false; + bool thatLock = false; + try + { + if (this.idInClass < a.idInClass) + { + Monitor.Enter(vLock, ref thisLock); + Monitor.Enter(a.VLock, ref thatLock); + } + else + { + Monitor.Enter(a.VLock, ref thatLock); + Monitor.Enter(vLock, ref thisLock); + } + int previousV = v; + v += a.GetValue(); + if (v > maxV) v = maxV; + a.SubPositiveV(v - previousV); + return v - previousV; + } + finally + { + if (thisLock) Monitor.Exit(vLock); + if (thatLock) Monitor.Exit(a.VLock); + } + } + public int SubV(IntInTheVariableRange a) + { + if (this.idInClass == a.idInClass) return -1; + bool thisLock = false; + bool thatLock = false; + try + { + if (this.idInClass < a.idInClass) + { + Monitor.Enter(vLock, ref thisLock); + Monitor.Enter(a.VLock, ref thatLock); + } + else + { + Monitor.Enter(a.VLock, ref thatLock); + Monitor.Enter(vLock, ref thisLock); + } + int previousV = v; + v -= a.GetValue(); + if (v < 0) v = 0; + a.SubPositiveV(previousV - v); + return previousV - v; + } + finally + { + if (thisLock) Monitor.Exit(vLock); + if (thatLock) Monitor.Exit(a.VLock); + } + } + #endregion + + #region 与StartTime类的特殊条件的运算,运算会影响StartTime类的值 + /// + /// 试图加到满,如果加上时间差*速度可以达到MaxV,则加上并使startTime变为long.MaxValue + /// 如果无法加到maxValue则不加 + /// + /// 返回试图加到的值与最大值 + public (int, int, long) TryAddToMaxV(StartTime startTime, double speed = 1.0) + { + lock (vLock) + { + long addV = (long)(startTime.StopIfPassing(maxV - v) * speed); + if (addV < 0) return (v, maxV, startTime.Get()); + if (maxV - v < addV) return (v = maxV, maxV, startTime.Get()); + return ((int)(v + addV), maxV, startTime.Get()); + } + } + /// + /// 增加量为时间差*速度,并将startTime变为long.MaxValue + /// + /// 返回实际改变量 + public int AddV(StartTime startTime, double speed = 1.0) + { + lock (vLock) + { + int previousV = v; + int addV = (int)((Environment.TickCount64 - startTime.Stop()) * speed); + if (addV < 0) v += addV; + else return 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + #endregion + } + + /// + /// 一个保证在[0,maxValue]的可变long,支持可变的maxValue(请确保大于0) + /// + public class LongInTheVariableRange : InTheVariableRange + { + private long v; + private long maxV; + #region 构造与读取 + public LongInTheVariableRange(long value, long maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set SafaValues.LongInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = value < maxValue ? value : maxValue; + this.maxV = maxValue; + } + /// + /// 默认使Value=maxValue + /// + public LongInTheVariableRange(long maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set SafaValues.LongInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = this.maxV = maxValue; + } + public LongInTheVariableRange() : base() + { + v = this.maxV = long.MaxValue; + } + + public override string ToString() + { + lock (vLock) + { + return "value:" + v.ToString() + " , maxValue:" + maxV.ToString(); + } + } + public long GetValue() { lock (vLock) return v; } + public static implicit operator long(LongInTheVariableRange aint) => aint.GetValue(); + public long GetMaxV() { lock (vLock) return maxV; } + public (long, long) GetValueAndMaxV() { lock (vLock) return (v, maxV); } + public bool IsMaxV() + { + lock (vLock) + { + return v == maxV; + } + } + #endregion + + #region 内嵌读取(在锁的情况下读取内容同时读取其他更基本的外部数据) + public (long, long) GetValue(StartTime startTime) + { + lock (vLock) + { + return (v, startTime.Get()); + } + } + public (long, long, long) GetValueAndMaxV(StartTime startTime) + { + lock (vLock) + { + return (v, maxV, startTime.Get()); + } + } + #endregion + + #region 普通设置MaxV与Value的值的方法 + /// + /// 若maxValue<=0则maxValue设为0并返回False + /// + public bool SetMaxV(long maxValue) + { + if (maxValue <= 0) + { + lock (vLock) + { + v = maxV = 0; + return false; + } + } + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + return true; + } + /// + /// 应当保证该maxValue>=0 + /// + public void SetPositiveMaxV(long maxValue) + { + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + } + + public long SetV(long value) + { + if (value <= 0) + { + lock (vLock) + { + return v = 0; + } + } + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + /// + /// 应当保证该value>=0 + /// + public long SetPositiveV(long value) + { + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + #endregion + + #region 普通运算 + /// 返回实际改变量 + public long AddV(long addV) + { + lock (vLock) + { + long previousV = v; + v += addV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证增加值大于0 + /// + /// 返回实际改变量 + public long AddPositiveV(long addPositiveV) + { + lock (vLock) + { + addPositiveV = Math.Min(addPositiveV, maxV - v); + v += addPositiveV; + } + return addPositiveV; + } + public void MulV(long mulV) + { + if (mulV <= 0) + { + lock (vLock) v = 0; + return; + } + lock (vLock) + { + if (v > maxV / mulV) v = maxV; //避免溢出 + else v *= mulV; + } + } + public void MulV(double mulV) + { + if (mulV <= 0) + { + lock (vLock) v = 0; + return; + } + lock (vLock) + { + if (v > maxV / mulV) v = maxV; //避免溢出 + else v = (long)(v * mulV); + } + } + /// + /// 应当保证乘数大于0 + /// + public void MulPositiveV(long mulPositiveV) + { + lock (vLock) + { + if (v > maxV / mulPositiveV) v = maxV; //避免溢出 + else v *= mulPositiveV; + } + } + /// + /// 应当保证乘数大于0 + /// + public void MulPositiveV(double mulPositiveV) + { + lock (vLock) + { + if (v > maxV / mulPositiveV) v = maxV; //避免溢出 + else v = (long)(v * mulPositiveV); + } + } + /// 返回实际改变量 + public long SubV(long subV) + { + lock (vLock) + { + long previousV = v; + v -= subV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证该减少值大于0 + /// + /// 返回实际改变量 + public long SubPositiveV(long subPositiveV) + { + lock (vLock) + { + subPositiveV = Math.Min(subPositiveV, v); + v -= subPositiveV; + } + return subPositiveV; + } + #endregion + + #region 特殊条件的设置MaxV与Value的值的方法 + /// + /// 如果当前值大于maxValue,则更新maxValue失败 + /// + public bool TrySetMaxV(long maxValue) + { + lock (vLock) + { + if (v > maxValue) return false; + maxV = maxValue; + return true; + } + } + + public bool Set0IfNotMax() + { + lock (vLock) + { + if (v < maxV) + { + v = 0; + return true; + } + } + return false; + } + public bool Set0IfMax() + { + lock (vLock) + { + if (v == maxV) + { + v = 0; + return true; + } + } + return false; + } + #endregion + + #region 特殊条件的运算 + /// + /// 试图加到满,如果无法加到maxValue则不加并返回-1 + /// + /// 返回实际改变量 + public long TryAddToMaxV(long addV) + { + lock (vLock) + { + if (maxV - v <= addV) + { + addV = maxV - v; + v = maxV; + return addV; + } + return -1; + } + } + #endregion + + #region 与StartTime类的特殊条件的运算,运算会影响StartTime类的值 + /// + /// 试图加到满,如果加上时间差*速度可以达到MaxV,则加上并使startTime变为long.MaxValue + /// 如果无法加到maxValue则不加 + /// + /// 返回试图加到的值与最大值 + public (long, long, long) TryAddToMaxV(StartTime startTime, double speed = 1.0) + { + lock (vLock) + { + long addV = (long)(startTime.StopIfPassing(maxV - v) * speed); + if (addV < 0) return (v, maxV, startTime.Get()); + if (maxV - v < addV) return (v = maxV, maxV, startTime.Get()); + return (v + addV, maxV, startTime.Get()); + } + } + + /// + /// 增加量为时间差*速度,并将startTime变为long.MaxValue + /// + /// 返回实际改变量 + public long AddV(StartTime startTime, double speed = 1.0) + { + lock (vLock) + { + long previousV = v; + long addV = (Environment.TickCount64 - startTime.Stop()); + if (addV < 0) v += (long)(addV * speed); + else return 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + #endregion + } + + /// + /// 一个保证在[0,maxValue]的可变double,支持可变的maxValue(请确保大于0) + /// + public class DoubleInTheVariableRange : InTheVariableRange + { + private double v; + private double maxV; + #region 构造与读取 + public DoubleInTheVariableRange(double value, double maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set DoubleInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = value < maxValue ? value : maxValue; + this.maxV = maxValue; + } + /// + /// 默认使Value=maxValue + /// + public DoubleInTheVariableRange(double maxValue) : base() + { + if (maxValue < 0) + { + Debugger.Output("Warning:Try to set DoubleInTheVariableRange.maxValue to " + maxValue.ToString() + "."); + maxValue = 0; + } + v = this.maxV = maxValue; + } + public DoubleInTheVariableRange() : base() + { + v = this.maxV = double.MaxValue; + } + + public override string ToString() + { + lock (vLock) + { + return "value:" + v.ToString() + " , maxValue:" + maxV.ToString(); + } + } + public double GetValue() { lock (vLock) return v; } + public static implicit operator double(DoubleInTheVariableRange adouble) => adouble.GetValue(); + public double GetMaxV() { lock (vLock) return maxV; } + public (double, double) GetValueAndMaxV() { lock (vLock) return (v, maxV); } + public bool IsMaxV() + { + lock (vLock) + { + return v == maxV; + } + } + #endregion + + #region 内嵌读取(在锁的情况下读取内容同时读取其他更基本的外部数据) + public (double, long) GetValue(StartTime startTime) + { + lock (vLock) + { + return (v, startTime.Get()); + } + } + public (double, double, long) GetValueAndMaxValue(StartTime startTime) + { + lock (vLock) + { + return (v, maxV, startTime.Get()); + } + } + #endregion + + #region 普通设置MaxV与Value的值的方法 + /// + /// 若maxValue<=0则maxValue设为0并返回False + /// + public bool SetMaxV(double maxValue) + { + if (maxValue <= 0) + { + lock (vLock) + { + v = maxV = 0; + return false; + } + } + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + return true; + } + /// + /// 应当保证该maxValue>=0 + /// + public void SetPositiveMaxV(double maxValue) + { + lock (vLock) + { + maxV = maxValue; + if (v > maxValue) v = maxValue; + } + } + + public double SetV(double value) + { + if (value <= 0) + { + lock (vLock) + { + return v = 0; + } + } + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + /// + /// 应当保证该value>=0 + /// + public double SetPositiveV(double value) + { + lock (vLock) + { + return v = (value > maxV) ? maxV : value; + } + } + #endregion + + #region 普通运算 + /// 返回实际改变量 + public double AddV(double addV) + { + lock (vLock) + { + double previousV = v; + v += addV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证增加值大于0 + /// + /// 返回实际改变量 + public double AddPositiveV(double addPositiveV) + { + lock (vLock) + { + addPositiveV = Math.Min(addPositiveV, maxV - v); + v += addPositiveV; + } + return addPositiveV; + } + public void MulV(double mulV) + { + if (mulV <= 0) + { + lock (vLock) v = 0; + return; + } + lock (vLock) + { + if (v > maxV / mulV) v = maxV; //避免溢出 + else v *= mulV; + } + } + /// + /// 应当保证乘数大于0 + /// + public void MulPositiveV(double mulPositiveV) + { + lock (vLock) + { + if (v > maxV / mulPositiveV) v = maxV; //避免溢出 + else v *= mulPositiveV; + } + } + /// 返回实际改变量 + public double SubV(double subV) + { + lock (vLock) + { + double previousV = v; + v -= subV; + if (v < 0) v = 0; + if (v > maxV) v = maxV; + return v - previousV; + } + } + /// + /// 应当保证该减少值大于0 + /// + /// 返回实际改变量 + public double SubPositiveV(double subPositiveV) + { + lock (vLock) + { + subPositiveV = Math.Min(subPositiveV, v); + v -= subPositiveV; + } + return subPositiveV; + } + #endregion + + #region 特殊条件的设置MaxV与Value的值的方法 + /// + /// 如果当前值大于maxValue,则更新maxValue失败 + /// + public bool TrySetMaxV(double maxValue) + { + lock (vLock) + { + if (v > maxValue) return false; + maxV = maxValue; + return true; + } + } + + public bool Set0IfNotMax() + { + lock (vLock) + { + if (v < maxV) + { + v = 0; + return true; + } + } + return false; + } + public bool Set0IfMax() + { + lock (vLock) + { + if (v == maxV) + { + v = 0; + return true; + } + } + return false; + } + #endregion + + #region 特殊条件的运算 + /// + /// 试图加到满,如果无法加到maxValue则不加并返回-1 + /// + /// 返回实际改变量 + public double TryAddToMaxV(double addV) + { + lock (vLock) + { + if (maxV - v <= addV) + { + addV = maxV - v; + v = maxV; + return addV; + } + return -1; + } + } + #endregion + } +} \ No newline at end of file diff --git a/logic/Preparation/Utility/SafeValue/TimeBased.cs b/logic/Preparation/Utility/SafeValue/TimeBased.cs new file mode 100644 index 00000000..6ed57435 --- /dev/null +++ b/logic/Preparation/Utility/SafeValue/TimeBased.cs @@ -0,0 +1,512 @@ +using System; +using System.Threading; + +namespace Preparation.Utility +{ + //其对应属性不应当有set访问器,避免不安全的=赋值 + + /// + /// 记录上次Start的时间,尚未Start则为long.MaxValue + /// 当前不为long.MaxValue则不能Start + /// + public class StartTime + { + private long _time; + public StartTime(long time) + { + _time = time; + } + public StartTime() { _time = long.MaxValue; } + public long Get() => Interlocked.CompareExchange(ref _time, -2, -2); + public override string ToString() => Get().ToString(); + /// 返回操作前的值 + public long Start() => Interlocked.CompareExchange(ref _time, Environment.TickCount64, long.MaxValue); + /// 返回操作前的值 + public long Stop() => Interlocked.Exchange(ref _time, long.MaxValue); + /// 返回时间差,<0意味着未开始 + public long StopIfPassing(long passedTime) + { + long ans = Environment.TickCount64 - Interlocked.CompareExchange(ref _time, -2, -2); + if (ans > passedTime) + { + Interlocked.Exchange(ref _time, long.MaxValue); + } + return ans; + } + } + + /// + /// 根据时间推算Start后完成多少进度的进度条(long)。 + /// 只允许Start(清零状态的进度条才可以Start)时修改needTime(请确保大于0); + /// 支持InterruptToSet0使未完成的进度条终止清零;支持Set0使进度条强制终止清零; + /// 通过原子操作实现。 + /// + public class TimeBasedProgressOptimizedForInterrupting + { + private long endT = long.MaxValue; + private long needT; + + public TimeBasedProgressOptimizedForInterrupting(long needTime) + { + if (needTime <= 0) Debugger.Output("Bug:TimeBasedProgressOptimizedForInterrupting.needProgress (" + needTime.ToString() + ") is less than 0."); + this.needT = needTime; + } + public TimeBasedProgressOptimizedForInterrupting() + { + this.needT = 0; + } + public long GetEndTime() => Interlocked.CompareExchange(ref endT, -2, -2); + public long GetNeedTime() => Interlocked.CompareExchange(ref needT, -2, -2); + public override string ToString() => "EndTime:" + Interlocked.CompareExchange(ref endT, -2, -2).ToString() + " ms, NeedTime:" + Interlocked.CompareExchange(ref needT, -2, -2).ToString() + " ms"; + public bool IsFinished() + { + return Interlocked.CompareExchange(ref endT, -2, -2) <= Environment.TickCount64; + } + public bool IsStarted() => Interlocked.Read(ref endT) != long.MaxValue; + /// + /// GetProgress<0则表明未开始 + /// + public long GetProgress() + { + long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; + if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); + return Interlocked.CompareExchange(ref needT, -2, -2) - cutime; + } + public long GetNonNegativeProgress() + { + long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; + if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); + long progress = Interlocked.CompareExchange(ref needT, -2, -2) - cutime; + return progress < 0 ? 0 : progress; + } + /// + /// GetProgress<0则表明未开始 + /// + public long GetProgress(long time) + { + long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - time; + if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); + return Interlocked.CompareExchange(ref needT, -2, -2) - cutime; + } + public long GetNonNegativeProgress(long time) + { + long cutime = Interlocked.Read(ref endT) - time; + if (cutime <= 0) return Interlocked.CompareExchange(ref needT, -2, -2); + long progress = Interlocked.CompareExchange(ref needT, -2, -2) - cutime; + return progress < 0 ? 0 : progress; + } + /// + /// <0则表明未开始 + /// + public static implicit operator long(TimeBasedProgressOptimizedForInterrupting pLong) => pLong.GetProgress(); + + /// + /// GetProgressDouble<0则表明未开始 + /// + public double GetProgressDouble() + { + long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; + if (cutime <= 0) return 1; + long needTime = Interlocked.CompareExchange(ref needT, -2, -2); + if (needTime == 0) return 0; + return 1.0 - ((double)cutime / needTime); + } + public double GetNonNegativeProgressDouble(long time) + { + long cutime = Interlocked.Read(ref endT) - time; + if (cutime <= 0) return 1; + long needTime = Interlocked.CompareExchange(ref needT, -2, -2); + if (needTime <= cutime) return 0; + return 1.0 - ((double)cutime / needTime); + } + + public bool Start(long needTime) + { + if (needTime <= 0) + { + Debugger.Output("Warning:Start TimeBasedProgressOptimizedForInterrupting with the needProgress (" + needTime.ToString() + ") which is less than 0."); + return false; + } + //规定只有Start可以修改needT,且需要先访问endTime,从而避免锁(某种程度上endTime可以认为是needTime的锁) + if (Interlocked.CompareExchange(ref endT, Environment.TickCount64 + needTime, long.MaxValue) != long.MaxValue) return false; + if (needTime <= 2) Debugger.Output("Warning:the field of TimeBasedProgressOptimizedForInterrupting is " + needTime.ToString() + ",which is too small."); + Interlocked.Exchange(ref needT, needTime); + return true; + } + public bool Start() + { + long needTime = Interlocked.CompareExchange(ref needT, -2, -2); + if (Interlocked.CompareExchange(ref endT, Environment.TickCount64 + needTime, long.MaxValue) != long.MaxValue) return false; + return true; + } + /// + /// 使进度条强制终止清零 + /// + public void Set0() => Interlocked.Exchange(ref endT, long.MaxValue); + /// + /// 使未完成的进度条终止清零 + /// + public bool InterruptToSet0() + { + if (Environment.TickCount64 < Interlocked.CompareExchange(ref endT, -2, -2)) + { + Interlocked.Exchange(ref endT, long.MaxValue); + return true; + } + return false; + } + //增加其他新的写操作可能导致不安全 + } + + public class TimeBasedProgressAtVariableSpeed + { + public LongInTheVariableRange progress; + public StartTime startTime = new(); + public AtomicDouble speed; + + #region 构造 + public TimeBasedProgressAtVariableSpeed(long needProgress, double speed) + { + if (needProgress <= 0) Debugger.Output("Bug:TimeBasedProgressAtVariableSpeed.needProgress (" + needProgress.ToString() + ") is less than 0."); + this.progress = new(0, needProgress); + this.speed = new(speed); + } + public TimeBasedProgressAtVariableSpeed() + { + this.progress = new(0, 0); + this.speed = new(1.0); + } + #endregion + + #region 读取 + public override string ToString() + { + return "ProgressStored: " + progress.ToString() + + " ; LastStartTime: " + startTime.ToString() + "ms" + + " ; Speed: " + speed.ToString(); + } + public long GetProgressNow() => progress.TryAddToMaxV(startTime, (double)speed).Item1; + public (long, long, long) GetProgressNowAndNeedTimeAndLastStartTime() => progress.TryAddToMaxV(startTime, (double)speed); + public long GetProgressStored() => progress.GetValue(); + public (long, long) GetProgressStoredAndNeedTime() => progress.GetValueAndMaxV(); + public (long, long, long) GetProgressStoredAndNeedTimeAndLastStartTime() => progress.GetValueAndMaxV(startTime); + + public bool IsFinished() + { + long progressNow, needTime; + (progressNow, needTime, _) = progress.TryAddToMaxV(startTime); + return progressNow == needTime; + } + public bool IsProgressing() + { + long progressNow, needTime, startT; + (progressNow, needTime, startT) = progress.TryAddToMaxV(startTime); + return (startT != long.MaxValue && progressNow != needTime); + } + #endregion + + public bool Start(long needTime) + { + if (needTime <= 2) + { + Debugger.Output("Warning:Start TimeBasedProgressAtVariableSpeed with the needProgress (" + needTime.ToString() + ") which is less than 0."); + return false; + } + if (startTime.Start() != long.MaxValue) return false; + progress.SetMaxV(needTime); + return true; + } + public bool Start() + { + return startTime.Start() == long.MaxValue; + } + /// + /// 使进度条强制终止清零 + /// + public void Set0() + { + startTime.Stop(); + progress.SetPositiveV(0); + } + /// + /// 使进度条暂停 + /// + public bool Pause() + { + return progress.AddV(startTime, (double)speed) != 0; + } + } + + /// + /// 冷却时间为可变的CDms的bool,不支持查看当前进度,初始为True + /// + public class BoolUpdateEachCD + { + private long cd; + private long nextUpdateTime = 0; + public BoolUpdateEachCD(int cd) + { + if (cd <= 1) Debugger.Output("Bug:BoolUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + } + public BoolUpdateEachCD(long cd) + { + if (cd <= 1) Debugger.Output("Bug:BoolUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + } + public BoolUpdateEachCD(long cd, long startTime) + { + if (cd <= 1) Debugger.Output("Bug:BoolUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + this.nextUpdateTime = startTime; + } + + public long GetCD() => Interlocked.Read(ref cd); + + public bool TryUse() + { + long needTime = Interlocked.Exchange(ref nextUpdateTime, long.MaxValue); + if (needTime <= Environment.TickCount64) + { + Interlocked.Exchange(ref nextUpdateTime, Environment.TickCount64 + Interlocked.Read(ref cd)); + return true; + } + Interlocked.Exchange(ref nextUpdateTime, needTime); + return false; + } + public void SetCD(int cd) + { + if (cd <= 1) Debugger.Output("Bug:BoolUpdateEachCD.cd to " + cd.ToString() + "."); + Interlocked.Exchange(ref this.cd, cd); + } + } + + /// + /// 冷却时间为可变的CDms的进度条,初始为满 + /// + public class LongProgressUpdateEachCD + { + private int isusing = 0; + private long cd; + private long nextUpdateTime = 0; + public LongProgressUpdateEachCD(int cd) + { + if (cd <= 1) Debugger.Output("Bug:LongProgressUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + } + public LongProgressUpdateEachCD(long cd) + { + if (cd <= 1) Debugger.Output("Bug:LongProgressUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + } + public LongProgressUpdateEachCD(long cd, long startTime) + { + if (cd <= 1) Debugger.Output("Bug:LongProgressUpdateEachCD.cd (" + cd.ToString() + ") is less than 1."); + this.cd = cd; + this.nextUpdateTime = startTime; + } + + public long GetRemainingTime() + { + long v = Interlocked.Read(ref nextUpdateTime) - Environment.TickCount64; + return v < 0 ? 0 : v; + } + public long GetCD() => Interlocked.Read(ref cd); + + public bool TryUse() + { + if (Interlocked.Exchange(ref isusing, 1) == 1) return false; + long needTime = Interlocked.Read(ref nextUpdateTime); + if (needTime <= Environment.TickCount64) + { + Interlocked.Exchange(ref nextUpdateTime, Environment.TickCount64 + Interlocked.Read(ref cd)); + Interlocked.Exchange(ref isusing, 0); + return true; + } + Interlocked.Exchange(ref isusing, 0); + return false; + } + public void SetCD(int cd) + { + if (cd <= 1) Debugger.Output("Bug:Set LongProgressUpdateEachCD.cd to " + cd.ToString() + "."); + Interlocked.Exchange(ref this.cd, cd); + } + } + + /// + /// 一个保证在[0,maxNum],每CDms自动+1的int,支持可变的CD、maxNum(请确保大于0) + /// + public class IntNumUpdateEachCD + { + private int num; + private int maxNum; + private int cd; + private long updateTime = 0; + private readonly object numLock = new(); + public IntNumUpdateEachCD(int num, int maxNum, int cd) + { + if (num < 0) Debugger.Output("Bug:IntNumUpdateEachCD.num (" + num.ToString() + ") is less than 0."); + if (maxNum < 0) Debugger.Output("Bug:IntNumUpdateEachCD.maxNum (" + maxNum.ToString() + ") is less than 0."); + if (cd <= 0) Debugger.Output("Bug:IntNumUpdateEachCD.cd (" + cd.ToString() + ") is less than 0."); + this.num = (num < maxNum) ? num : maxNum; + this.maxNum = maxNum; + this.cd = cd; + this.updateTime = Environment.TickCount64; + } + /// + /// 默认使num=maxNum + /// + public IntNumUpdateEachCD(int maxNum, int cd) + { + if (maxNum < 0) Debugger.Output("Bug:IntNumUpdateEachCD.maxNum (" + maxNum.ToString() + ") is less than 0."); + if (cd <= 0) Debugger.Output("Bug:IntNumUpdateEachCD.cd (" + cd.ToString() + ") is less than 0."); + this.num = this.maxNum = maxNum; + this.cd = cd; + } + public IntNumUpdateEachCD() + { + this.num = this.maxNum = 0; + this.cd = int.MaxValue; + } + + public int GetMaxNum() { lock (numLock) return maxNum; } + public int GetCD() { lock (numLock) return cd; } + public int GetNum(long time) + { + lock (numLock) + { + if (num < maxNum && time - updateTime >= cd) + { + int add = (int)Math.Min(maxNum - num, (time - updateTime) / cd); + updateTime += add * cd; + return (num += add); + } + return num; + } + } + public static implicit operator int(IntNumUpdateEachCD aint) => aint.GetNum(Environment.TickCount64); + + /// + /// 应当保证该subV>=0 + /// + public int TrySub(int subV) + { + if (subV < 0) Debugger.Output("Bug:IntNumUpdateEachCD Try to sub " + subV.ToString() + ", which is less than 0."); + long time = Environment.TickCount64; + lock (numLock) + { + if (num < maxNum && time - updateTime >= cd) + { + int add = (int)Math.Min(maxNum - num, (time - updateTime) / cd); + updateTime += add * cd; + num += add; + } + if (num == maxNum) updateTime = time; + num -= subV = Math.Min(subV, num); + } + return subV; + } + /// + /// 应当保证该addV>=0 + /// + public void TryAdd(int addV) + { + if (addV < 0) Debugger.Output("Bug:IntNumUpdateEachCD Try to add " + addV.ToString() + ", which is less than 0."); + lock (numLock) + { + num += Math.Min(addV, maxNum - num); + } + } + /// + /// 若maxNum<=0则maxNum及Num设为0并返回False + /// + public bool SetMaxNumAndNum(int maxNum) + { + if (maxNum < 0) maxNum = 0; + lock (numLock) + { + this.num = this.maxNum = maxNum; + } + return maxNum > 0; + } + /// + /// 应当保证该maxnum>=0 + /// + public void SetPositiveMaxNumAndNum(int maxNum) + { + lock (numLock) + { + this.num = this.maxNum = maxNum; + } + } + /// + /// 应当保证该maxnum>=0 + /// + public void SetPositiveMaxNum(int maxNum) + { + lock (numLock) + { + if ((this.maxNum = maxNum) < num) + num = maxNum; + } + } + /// + /// 若maxNum<=0则maxNum及Num设为0并返回False + /// + public bool SetMaxNum(int maxNum) + { + if (maxNum < 0) maxNum = 0; + lock (numLock) + { + if ((this.maxNum = maxNum) < num) + num = maxNum; + } + return maxNum > 0; + } + /// + /// 若num<0则num设为0并返回False + /// + public bool SetNum(int num) + { + lock (numLock) + { + if (num < 0) + { + this.num = 0; + updateTime = Environment.TickCount64; + return false; + } + if (num < maxNum) + { + if (this.num == maxNum) updateTime = Environment.TickCount64; + this.num = num; + } + else this.num = maxNum; + return true; + } + } + /// + /// 应当保证该num>=0 + /// + public void SetPositiveNum(int num) + { + lock (numLock) + { + if (num < maxNum) + { + if (this.num == maxNum) updateTime = Environment.TickCount64; + this.num = num; + } + else this.num = maxNum; + } + } + public void SetCD(int cd) + { + lock (numLock) + { + if (cd <= 0) Debugger.Output("Bug:Set IntNumUpdateEachCD.cd to " + cd.ToString() + "."); + this.cd = cd; + } + } + } +} \ No newline at end of file