NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (타이머 만들기)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 타이머 액션은 등록한 시점부터 시간이 흐르기 시작해서 조건의 타이머 체크 액션에서 설정한 시간이 지났는지를 확인할 수 있도록 해줍니다. 예를 들어서 타이머를 등록하고, 60초가 지났는지 체크할 수 있는데요. 시간이 지났다면 타이머 체크 액션은 참이 됩니다. 여러개의 타이머를 등록해두고, 타이머에 따라서 조건을 만들고 로직을 처리할 수 있습니다. 우선, 타이머를 어떻게 등록할 수 있는지 알아보고, 다음 시간에 타이머 체크를 만들면서 테스트 해볼께요.

     

    아래와 같이 타이머 액션을 하나 추가했습니다.

    public class AddTimerModel : BaseModel

     

    현재 타이머가 등록된 시간을 확인할 수 있도록 속성을 하나 만들어줍니다.

    [LocalizedCategory("Data")]
    [LocalizedDisplayName("Result")]
    [LocalizedDescription("Result")]
    [Browsable(true)]
    [DefaultValue(null)]
    [EditorAttribute(typeof(MultilineStringEditor), typeof(UITypeEditor))]
    public string? Result { get; set; }

     

    사용자가 설정해야 할 속성은 총 5개입니다. 타이머를 등록하거나 수정 또는 삭제할 수 있는 AddUpdateRemove 옵션을 제공해야 합니다.

    [LocalizedCategory("Action")]
    [LocalizedDisplayName("ProcessOption")]
    [LocalizedDescription("ProcessOption")]
    [Browsable(true)]
    [DefaultValue(typeof(Definition.AddUpdateRemove), "Add")]
    public Ai.Definition.AddUpdateRemove ProcessOption { get; set; } = Definition.AddUpdateRemove.Add;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("IsFirstStart")]
    [LocalizedDescription("IsFirstStart")]
    [Browsable(true)]
    [DefaultValue(false)]
    public bool IsFirstStart { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("TimerName")]
    [LocalizedDescription("TimerName")]
    [Browsable(true)]
    [DefaultValue(false)]
    public string? TimerName { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("IsGlobal")]
    [LocalizedDescription("IsGlobal")]
    [Browsable(true)]
    [DefaultValue(false)]
    public bool IsGlobal { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("IsParent")]
    [LocalizedDescription("IsParent")]
    [Browsable(true)]
    [DefaultValue(false)]
    public bool IsParent { get; set; }

     

    엔지엠 매크로는 글로벌하게 모든 스크립트가 접근 가능한 메모리 영역이 있고, 플레이어가 실행하는 서브 스크립트 영역이 있습니다. 그리고, 자기 자신을 가리키는 스크립트가 있는데요. 이들의 관계에 따라서 다른 메모리 공간에 타이머가 등록됩니다. 모든 스크립트가 접근 가능한 영역은 IsGlobal로 설정 가능합니다. 그리고, 자기 자신을 만든 부모 플레이어는 IsParent 속성을 True로 설정하면 됩니다.

     

    타이머를 각각 관리하기 위해 전역(Global), 부모(Parent), Self(자신)에 저장이 가능합니다. 타이머를 체크할 때도 각각의 영역에 맞는 곳에서 가져와야 합니다. 그리고, 이전 엔지엠 매크로에서는 아이디를 사용하다보니 여러가지 문제가 발생했습니다. 엔지엠 매크로의 아이디는 액션이 이동할 때 사용하는 유니크한 아이디입니다. 따라서, 사용자 제약으로 인해 동일한 아이디를 설정할 수 없도록 되어 있습니다. 그렇다보니 타이머 a를 등록하고, 동일한 스크립트에서 타이머 a를 수정하는 작업이 안됩니다. 물론, 복사 붙여넣기로 우회해서 사용할 수 있습니다. 다만, 이런식으로 사용하는건 규칙에 위배되기 때문에 좋은 방식은 아닙니다.

     

    새로운 엔지엠 매크로는 아이디와 같이 사용하지 않도록 타이머 이름이라는 속성을 사용해서 관리할 수 있도록 했습니다. 따라서, 중복된 아이디 체크에 걸리지 않고, 타이머만의 아이디로 접근 및 수정, 삭제가 가능합니다. 사용자의 실수를 줄이기 위해서 어느정도 제약이 필요하기 때문에 아이디는 중복될 수 없도록 하고, 타이머와 같이 관리가 필요한 개체들은 별도의 이름으로 설정하도록 하겠습니다.

     

    타이머를 등록하는 코드는 간단하게 구현할 수 있습니다. 중복된 코드가 있어서 뭔가 복잡해 보이지만, 타이머가 등록될 위치에 따라서 저장하도록 처리하면 됩니다. if ~ else if ~ else처럼 각각의 옵션에 따라서 처리되도록 구현되어 있습니다. 아래 코드를 보면 아시겠지만, IsGlobal이 가장 우선 적용되고 그다음에 IsParent가 적용됩니다. 그래서, IsGlobal과 IsParent를 둘다 True로 설정하면 IsGlobal에만 타이머가 등록됩니다.

    public override string? Execute(IPlayer player)
    {
        Result = null;
    
        var id = base.Execute(player);
    
        var timerName = Ai.Common.Helper.GetMatches(player, GetType().GetProperty(nameof(TimerName)), TimerName);
    
        if (!Ai.Common.Helper.NullCheckAndWriteLine(player, nameof(timerName), timerName))
            return id;
    
        if (IsGlobal)
        {
            switch (ProcessOption)
            {
                case Definition.AddUpdateRemove.Add:
                    System.DateTime currentDT = System.DateTime.Now;
                    player.Manager.Timers.Add(timerName, new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now));
                    break;
                case Definition.AddUpdateRemove.Update:
                    if (player.Manager.Timers.ContainsKey(timerName))
                        player.Manager.Timers[timerName] = new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now);
                    break;
                case Definition.AddUpdateRemove.Remove:
                    if (player.Manager.Timers.ContainsKey(timerName))
                        player.Manager.Timers.Remove(timerName);
                    break;
            }
    
            Result = player.Manager.Timers[timerName].Item2.ToString("yyyy-MM-dd HH:mm:ss.fff");
        }
        else if (IsParent)
        {
            if (!player.HasParent)
            {
                player.Manager.Output.WarningWriteLine(player.Manager.Client.ResxMessage.GetString("NotFoundParentPlayerCancel"));
                return id;
            }
    
            switch (ProcessOption)
            {
                case Definition.AddUpdateRemove.Add:
                    System.DateTime currentDT = System.DateTime.Now;
                    player.Parent.Timers.Add(timerName, new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now));
                    break;
                case Definition.AddUpdateRemove.Update:
                    if (player.Parent.Timers.ContainsKey(timerName))
                        player.Parent.Timers[timerName] = new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now);
                    break;
                case Definition.AddUpdateRemove.Remove:
                    if (player.Parent.Timers.ContainsKey(timerName))
                        player.Parent.Timers.Remove(timerName);
                    break;
            }
    
            Result = player.Parent.Timers[timerName].Item2.ToString("yyyy-MM-dd HH:mm:ss.fff");
        }
        else
        {
            switch (ProcessOption)
            {
                case Definition.AddUpdateRemove.Add:
                    System.DateTime currentDT = System.DateTime.Now;
                    player.Timers.Add(timerName, new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now));
                    break;
                case Definition.AddUpdateRemove.Update:
                    if (player.Timers.ContainsKey(timerName))
                        player.Timers[timerName] = new Tuple<bool, System.DateTime>(IsFirstStart, System.DateTime.Now);
                    break;
                case Definition.AddUpdateRemove.Remove:
                    if (player.Timers.ContainsKey(timerName))
                        player.Timers.Remove(timerName);
                    break;
            }
    
            Result = player.Timers[timerName].Item2.ToString("yyyy-MM-dd HH:mm:ss.fff");
        }
    
        return id;
    }

     

    타이머는 타이머 이름이 필수 입력 값입니다. 이 값이 없으면 아래 그림과 같이 경고 메세지가 출력창에 표시됩니다.

    4tokqx1.jpeg

     

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.