| @@ -20,9 +20,21 @@ namespace GameClass.GameObj | |||||
| public Gadget[] PropInChest => propInChest; | public Gadget[] PropInChest => propInChest; | ||||
| private long openStartTime = 0; | private long openStartTime = 0; | ||||
| public long OpenStartTime => openStartTime; | |||||
| public long OpenStartTime | |||||
| { | |||||
| get | |||||
| { | |||||
| lock (gameObjLock) return openStartTime; | |||||
| } | |||||
| } | |||||
| private Character? whoOpen = null; | private Character? whoOpen = null; | ||||
| public Character? WhoOpen => whoOpen; | |||||
| public Character? WhoOpen | |||||
| { | |||||
| get | |||||
| { | |||||
| lock (gameObjLock) return whoOpen; | |||||
| } | |||||
| } | |||||
| public bool Open(Character character) | public bool Open(Character character) | ||||
| { | { | ||||
| lock (gameObjLock) | 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; | private long openStartTime = 0; | ||||
| public long OpenStartTime | public long OpenStartTime | ||||
| @@ -106,7 +98,7 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| if (!isOpen) return false; | if (!isOpen) return false; | ||||
| if (whoLockOrOpen != null) return false; | if (whoLockOrOpen != null) return false; | ||||
| Interlocked.Exchange(ref lockDegree, 0); | |||||
| LockDegree.Set(0); | |||||
| whoLockOrOpen = character; | whoLockOrOpen = character; | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -23,20 +23,7 @@ namespace GameClass.GameObj | |||||
| return false; | 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; | private long openStartTime = 0; | ||||
| public long OpenStartTime | public long OpenStartTime | ||||
| @@ -49,9 +36,10 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| public bool TryToOpen() | public bool TryToOpen() | ||||
| { | { | ||||
| if (!PowerSupply) return false; | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| if (!powerSupply || openStartTime > 0) return false; | |||||
| if (openStartTime > 0) return false; | |||||
| openStartTime = Environment.TickCount64; | openStartTime = Environment.TickCount64; | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -17,24 +17,14 @@ namespace GameClass.GameObj | |||||
| public override bool IgnoreCollideExecutor(IGameObj targetObj) | public override bool IgnoreCollideExecutor(IGameObj targetObj) | ||||
| { | { | ||||
| if (!canOpen) return true; | |||||
| if (!CanOpen) return true; | |||||
| if (!IsOpen) return false; | if (!IsOpen) return false; | ||||
| if (targetObj.Type != GameObjType.Character) | if (targetObj.Type != GameObjType.Character) | ||||
| return true; // 非玩家不碰撞 | return true; // 非玩家不碰撞 | ||||
| return false; | 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; | private bool isOpen = false; | ||||
| public bool IsOpen | public bool IsOpen | ||||
| @@ -26,7 +26,7 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| Random r = new Random(Environment.TickCount); | Random r = new Random(Environment.TickCount); | ||||
| EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); | 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()); | Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); | ||||
| } | } | ||||
| finally | finally | ||||
| @@ -41,7 +41,7 @@ namespace GameClass.GameObj | |||||
| try | try | ||||
| { | { | ||||
| foreach (Doorway doorway in GameObjDict[GameObjType.Doorway]) | foreach (Doorway doorway in GameObjDict[GameObjType.Doorway]) | ||||
| doorway.PowerSupply = true; | |||||
| doorway.PowerSupply.Set(true); | |||||
| } | } | ||||
| finally | finally | ||||
| { | { | ||||
| @@ -513,7 +513,7 @@ namespace Gaming | |||||
| { | { | ||||
| if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null) | if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null) | ||||
| return false; | return false; | ||||
| if (doorToLock.AddLockDegree(GameData.checkInterval * player.SpeedOfOpeningOrLocking) >= GameData.basicSpeedOfOpeningOrLocking) | |||||
| if (doorToLock.LockDegree.Add(GameData.checkInterval * player.SpeedOfOpeningOrLocking) >= GameData.basicSpeedOfOpeningOrLocking) | |||||
| return false; | return false; | ||||
| return true; | return true; | ||||
| }, | }, | ||||
| @@ -311,7 +311,7 @@ namespace Gaming | |||||
| if (student.CharacterType == CharacterType.StraightAStudent) | if (student.CharacterType == CharacterType.StraightAStudent) | ||||
| { | { | ||||
| ((WriteAnswers)student.FindActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation = 0; | |||||
| ((WriteAnswers)student.FindActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation.Set(0); | |||||
| } | } | ||||
| student.SetDegreeOfTreatment0(); | student.SetDegreeOfTreatment0(); | ||||
| @@ -227,7 +227,7 @@ namespace Gaming | |||||
| if (generator.Repair(((WriteAnswers)activeSkill).DegreeOfMeditation, player)) | if (generator.Repair(((WriteAnswers)activeSkill).DegreeOfMeditation, player)) | ||||
| gameMap.AddNumOfRepairedGenerators(); | gameMap.AddNumOfRepairedGenerators(); | ||||
| Debugger.Output(player, "uses WriteAnswers in" + generator.ToString() + "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | 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, | () => 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()); | //Debugger.Output(player, "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | ||||
| }, | }, | ||||
| timeInterval: GameData.frameDuration, | timeInterval: GameData.frameDuration, | ||||
| @@ -174,12 +174,7 @@ namespace Preparation.Interface | |||||
| public override int SkillCD => GameData.commonSkillCD; | public override int SkillCD => GameData.commonSkillCD; | ||||
| public override int DurationTime => 0; | 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 | 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); | |||||
| } | |||||
| //增加新的写操作可能导致不安全 | |||||
| } | |||||
| } | |||||