| @@ -20,9 +20,21 @@ namespace GameClass.GameObj | |||
| public Gadget[] PropInChest => propInChest; | |||
| private long openStartTime = 0; | |||
| public long OpenStartTime => openStartTime; | |||
| public long OpenStartTime | |||
| { | |||
| get | |||
| { | |||
| lock (gameObjLock) return openStartTime; | |||
| } | |||
| } | |||
| private Character? whoOpen = null; | |||
| public Character? WhoOpen => whoOpen; | |||
| public Character? WhoOpen | |||
| { | |||
| get | |||
| { | |||
| lock (gameObjLock) return whoOpen; | |||
| } | |||
| } | |||
| public bool Open(Character character) | |||
| { | |||
| lock (gameObjLock) | |||
| @@ -47,15 +47,7 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| private int lockDegree = 0; | |||
| public int LockDegree | |||
| { | |||
| get => Interlocked.CompareExchange(ref lockDegree, -1, -1); | |||
| } | |||
| public int AddLockDegree(int add) | |||
| { | |||
| return Interlocked.Add(ref lockDegree, add); | |||
| } | |||
| public AtomicInt LockDegree { get; } = new AtomicInt(0); | |||
| private long openStartTime = 0; | |||
| public long OpenStartTime | |||
| @@ -106,7 +98,7 @@ namespace GameClass.GameObj | |||
| { | |||
| if (!isOpen) return false; | |||
| if (whoLockOrOpen != null) return false; | |||
| Interlocked.Exchange(ref lockDegree, 0); | |||
| LockDegree.Set(0); | |||
| whoLockOrOpen = character; | |||
| return true; | |||
| } | |||
| @@ -23,20 +23,7 @@ namespace GameClass.GameObj | |||
| return false; | |||
| } | |||
| private bool powerSupply = false; | |||
| public bool PowerSupply | |||
| { | |||
| get | |||
| { | |||
| lock (gameObjLock) | |||
| return powerSupply; | |||
| } | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| powerSupply = value; | |||
| } | |||
| } | |||
| public AtomicBool PowerSupply { get; } = new(false); | |||
| private long openStartTime = 0; | |||
| public long OpenStartTime | |||
| @@ -49,9 +36,10 @@ namespace GameClass.GameObj | |||
| } | |||
| public bool TryToOpen() | |||
| { | |||
| if (!PowerSupply) return false; | |||
| lock (gameObjLock) | |||
| { | |||
| if (!powerSupply || openStartTime > 0) return false; | |||
| if (openStartTime > 0) return false; | |||
| openStartTime = Environment.TickCount64; | |||
| return true; | |||
| } | |||
| @@ -17,24 +17,14 @@ namespace GameClass.GameObj | |||
| public override bool IgnoreCollideExecutor(IGameObj targetObj) | |||
| { | |||
| if (!canOpen) return true; | |||
| if (!CanOpen) return true; | |||
| if (!IsOpen) return false; | |||
| if (targetObj.Type != GameObjType.Character) | |||
| return true; // 非玩家不碰撞 | |||
| return false; | |||
| } | |||
| private bool canOpen = false; | |||
| public bool CanOpen | |||
| { | |||
| get => canOpen; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| canOpen = value; | |||
| } | |||
| } | |||
| public AtomicBool CanOpen { get; } = new(false); | |||
| private bool isOpen = false; | |||
| public bool IsOpen | |||
| @@ -26,7 +26,7 @@ namespace GameClass.GameObj | |||
| { | |||
| Random r = new Random(Environment.TickCount); | |||
| EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); | |||
| emergencyExit.CanOpen = true; | |||
| emergencyExit.CanOpen.Set(true); | |||
| Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); | |||
| } | |||
| finally | |||
| @@ -41,7 +41,7 @@ namespace GameClass.GameObj | |||
| try | |||
| { | |||
| foreach (Doorway doorway in GameObjDict[GameObjType.Doorway]) | |||
| doorway.PowerSupply = true; | |||
| doorway.PowerSupply.Set(true); | |||
| } | |||
| finally | |||
| { | |||
| @@ -513,7 +513,7 @@ namespace Gaming | |||
| { | |||
| if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null) | |||
| return false; | |||
| if (doorToLock.AddLockDegree(GameData.checkInterval * player.SpeedOfOpeningOrLocking) >= GameData.basicSpeedOfOpeningOrLocking) | |||
| if (doorToLock.LockDegree.Add(GameData.checkInterval * player.SpeedOfOpeningOrLocking) >= GameData.basicSpeedOfOpeningOrLocking) | |||
| return false; | |||
| return true; | |||
| }, | |||
| @@ -311,7 +311,7 @@ namespace Gaming | |||
| if (student.CharacterType == CharacterType.StraightAStudent) | |||
| { | |||
| ((WriteAnswers)student.FindActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation = 0; | |||
| ((WriteAnswers)student.FindActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation.Set(0); | |||
| } | |||
| student.SetDegreeOfTreatment0(); | |||
| @@ -227,7 +227,7 @@ namespace Gaming | |||
| if (generator.Repair(((WriteAnswers)activeSkill).DegreeOfMeditation, player)) | |||
| gameMap.AddNumOfRepairedGenerators(); | |||
| Debugger.Output(player, "uses WriteAnswers in" + generator.ToString() + "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | |||
| ((WriteAnswers)activeSkill).DegreeOfMeditation = 0; | |||
| ((WriteAnswers)activeSkill).DegreeOfMeditation.Set(0); | |||
| } | |||
| }, | |||
| () => | |||
| @@ -25,8 +25,8 @@ namespace Gaming // 被动技能开局时就释放,持续到游戏结束 | |||
| () => gameMap.Timer.IsGaming && !player.IsRemoved, | |||
| () => | |||
| { | |||
| if (player.Commandable() && player.PlayerState != PlayerStateType.Fixing) activeSkill.DegreeOfMeditation += learningDegree * GameData.frameDuration; | |||
| else activeSkill.DegreeOfMeditation = 0; | |||
| if (player.Commandable() && player.PlayerState != PlayerStateType.Fixing) activeSkill.DegreeOfMeditation.Add(learningDegree * GameData.frameDuration); | |||
| else activeSkill.DegreeOfMeditation.Set(0); | |||
| //Debugger.Output(player, "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| @@ -174,12 +174,7 @@ namespace Preparation.Interface | |||
| public override int SkillCD => GameData.commonSkillCD; | |||
| public override int DurationTime => 0; | |||
| private int degreeOfMeditation = 0; | |||
| public int DegreeOfMeditation | |||
| { | |||
| get => Interlocked.CompareExchange(ref degreeOfMeditation, 0, 0); | |||
| set => Interlocked.Exchange(ref degreeOfMeditation, value); | |||
| } | |||
| public AtomicInt DegreeOfMeditation { get; } = new(0); | |||
| } | |||
| public class SummonGolem : ActiveSkill | |||
| @@ -1,51 +0,0 @@ | |||
| using System.Threading; | |||
| namespace Preparation.Utility | |||
| { | |||
| //理论上结构体最好不可变,这里采用了可变结构。 | |||
| public struct 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 Set(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 void CompareExchange(int b, int c) => Interlocked.CompareExchange(ref v, b, c); | |||
| /// <returns>返回操作前的值</returns> | |||
| public int CompareExReturnOri(int b, int c) => Interlocked.CompareExchange(ref v, b, c); | |||
| } | |||
| public struct AtomicBool | |||
| { | |||
| private int v;//v==0为false,v!=0(v==1或v==-1)为true | |||
| public AtomicBool(bool x) | |||
| { | |||
| v = x ? 1 : 0; | |||
| } | |||
| public override string ToString() => (Interlocked.CompareExchange(ref v, -1, -1) == 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 Set(bool value) => (Interlocked.Exchange(ref v, value ? 1 : 0) != 0); | |||
| /// <returns>赋值前的值是否与将赋予的值不相同</returns> | |||
| public bool TrySet(bool value) | |||
| { | |||
| int ori = Interlocked.CompareExchange(ref v, value ? 1 : 0, value ? 1 : 0); | |||
| return value ? (ori == 0) : (ori != 0); | |||
| } | |||
| public bool Invert() => Interlocked.Add(ref v, -1) != 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; | |||
| } | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| using System; | |||
| using System.Threading; | |||
| namespace Preparation.Utility | |||
| { | |||
| //理论上结构体最好不可变,这里采用了可变结构。 | |||
| //其对应属性不应当有set访问器,避免不安全的=赋值 | |||
| public struct 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 Set(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 void CompareExchange(int newV, int compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); | |||
| /// <returns>返回操作前的值</returns> | |||
| public int CompareExReturnOri(int newV, int compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); | |||
| } | |||
| public struct AtomicBool | |||
| { | |||
| private int v;//v==0为false,v!=0(v==1或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 Set(bool value) => (Interlocked.Exchange(ref v, value ? 1 : 0) != 0); | |||
| /// <returns>赋值前的值是否与将赋予的值不相同</returns> | |||
| public bool TrySet(bool value) | |||
| { | |||
| return (Interlocked.CompareExchange(ref v, value ? 1 : 0, value ? 0 : 1) ^ (value ? 1 : 0)) != 0; | |||
| } | |||
| public bool Invert() => Interlocked.Add(ref v, -1) != 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; | |||
| } | |||
| public struct IntProgressContinuously | |||
| { | |||
| private long endT = long.MaxValue; | |||
| private long needT; | |||
| public IntProgressContinuously(long needTime) | |||
| { | |||
| this.needT = needTime; | |||
| } | |||
| 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 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 double GetProgressDouble() | |||
| { | |||
| long cutime = Interlocked.CompareExchange(ref endT, -2, -2) - Environment.TickCount64; | |||
| if (cutime <= 0) return 1; | |||
| return 1.0 - ((double)cutime / Interlocked.CompareExchange(ref needT, -2, -2)); | |||
| } | |||
| public bool Start(long needTime) | |||
| { | |||
| //规定只有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 IntProgressContinuously is " + needTime.ToString() + ",which is too small."); | |||
| Interlocked.Exchange(ref this.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 void TryStop() | |||
| { | |||
| if (Environment.TickCount64 < Interlocked.CompareExchange(ref endT, -2, -2)) | |||
| Interlocked.Exchange(ref endT, long.MaxValue); | |||
| } | |||
| //增加新的写操作可能导致不安全 | |||
| } | |||
| } | |||