From 54ff3a05efb436556fc97fd05afb18bcfa11b945 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Wed, 12 Oct 2016 17:48:39 +0200 Subject: [PATCH] Implemented CS:GO headshot and kill event Implemented CS:GO active weapon Implemented events delay Fixed event triggers Fixed event time reset --- .../CounterStrike/CounterStrikeDataModel.cs | 29 +++------ .../Games/CounterStrike/CounterStrikeModel.cs | 50 ++++++++++++++- .../Layers/Conditions/EventCondition.cs | 13 ++-- .../Layers/Models/EventPropertiesModel.cs | 61 +++++++++++++++++-- .../Models/KeyboardEventPropertiesModel.cs | 40 ++++-------- .../Profiles/Layers/Models/LayerModel.cs | 8 +++ .../Profiles/LayerEditorViewModel.cs | 10 ++- .../Profiles/ProfileEditorViewModel.cs | 11 +++- 8 files changed, 157 insertions(+), 65 deletions(-) diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs index 20dd851d4..6e76b2e87 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs @@ -1,4 +1,5 @@ using Artemis.Models.Interfaces; +using Newtonsoft.Json; namespace Artemis.Modules.Games.CounterStrike { @@ -47,6 +48,10 @@ namespace Artemis.Modules.Games.CounterStrike public class State { + [JsonIgnore] + public bool made_kill { get; set; } + [JsonIgnore] + public bool made_headshot { get; set; } public int health { get; set; } public int armor { get; set; } public bool helmet { get; set; } @@ -58,15 +63,8 @@ namespace Artemis.Modules.Games.CounterStrike public int round_killhs { get; set; } } - public class Weapon0 - { - public string name { get; set; } - public string paintkit { get; set; } - public string type { get; set; } - public string state { get; set; } - } - public class Weapon1 + public class Weapon { public string name { get; set; } public string paintkit { get; set; } @@ -77,19 +75,12 @@ namespace Artemis.Modules.Games.CounterStrike public string state { get; set; } } - public class Weapon2 - { - public string name { get; set; } - public string paintkit { get; set; } - public string type { get; set; } - public string state { get; set; } - } - public class Weapons { - public Weapon0 weapon_0 { get; set; } - public Weapon1 weapon_1 { get; set; } - public Weapon2 weapon_2 { get; set; } + public Weapon active_weapon { get; set; } + public Weapon weapon_0 { get; set; } + public Weapon weapon_1 { get; set; } + public Weapon weapon_2 { get; set; } } public class MatchStats diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs index 8a7893c5d..6287b3e19 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs @@ -12,6 +12,11 @@ namespace Artemis.Modules.Games.CounterStrike { public class CounterStrikeModel : GameModel { + private DateTime _lastHeadshot; + private int _lastHeadshots; + private DateTime _lastKill; + private int _lastKills; + public CounterStrikeModel(MainManager mainManager) : base(mainManager, SettingsProvider.Load(), new CounterStrikeDataModel()) { @@ -42,7 +47,46 @@ namespace Artemis.Modules.Games.CounterStrike public override void Update() { - // TODO: Set up active weapon in the datamodel + if (DataModel == null) + return; + + var dm = (CounterStrikeDataModel) DataModel; + if (dm.player != null) + { + // Detect active weapon + if (dm.player.weapons.weapon_0?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_0; + else if (dm.player.weapons.weapon_1?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_1; + else if (dm.player.weapons.weapon_2?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_2; + + // Detect a kill + if (dm.player.state.round_kills > _lastKills) + { + dm.player.state.made_kill = true; + _lastKill = DateTime.Now; + } + else if (dm.player.state.made_kill && (DateTime.Now - _lastKill > TimeSpan.FromMilliseconds(500))) + dm.player.state.made_kill = false; + _lastKills = dm.player.state.round_kills; + + // Detect a headshot + if (dm.player.state.round_killhs > _lastHeadshots) + { + dm.player.state.made_headshot = true; + _lastHeadshot = DateTime.Now; + } + else if (dm.player.state.made_headshot && (DateTime.Now - _lastHeadshot > TimeSpan.FromMilliseconds(500))) + dm.player.state.made_headshot = false; + _lastHeadshots = dm.player.state.round_killhs; + + // Detect a round win + + // Detect a round loss + } + + DataModel = dm; } public void HandleGameData(object sender, GameDataReceivedEventArgs e) @@ -56,7 +100,9 @@ namespace Artemis.Modules.Games.CounterStrike // Parse the JSON try { - DataModel = JsonConvert.DeserializeObject(jsonString); + if (DataModel == null) + DataModel = new CounterStrikeDataModel(); + JsonConvert.PopulateObject(jsonString, DataModel); } catch (Exception ex) { diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs index 5a7adc7d0..0f2ae4d53 100644 --- a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs +++ b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs @@ -9,13 +9,16 @@ namespace Artemis.Profiles.Layers.Conditions { public bool ConditionsMet(LayerModel layer, IDataModel dataModel) { - var conditionsMet = layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel)); - layer.EventProperties.Update(layer, conditionsMet); + lock (layer.Properties.Conditions) + { + var conditionsMet = layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel)); + layer.EventProperties.Update(layer, conditionsMet); - if (conditionsMet && layer.EventProperties.MustTrigger) - layer.EventProperties.TriggerEvent(layer); + if (conditionsMet && layer.EventProperties.CanTrigger) + layer.EventProperties.TriggerEvent(layer); - return conditionsMet && layer.EventProperties.MustDraw; + return layer.EventProperties.MustDraw; + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs index 8acd950da..b13f3487a 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Newtonsoft.Json; namespace Artemis.Profiles.Layers.Models @@ -10,10 +12,10 @@ namespace Artemis.Profiles.Layers.Models public TimeSpan TriggerDelay { get; set; } [JsonIgnore] - public bool MustTrigger { get; set; } + public bool CanTrigger { get; set; } [JsonIgnore] - public DateTime AnimationStart { get; set; } + public DateTime EventTriggerTime { get; set; } [JsonIgnore] public bool MustDraw { get; set; } @@ -21,23 +23,70 @@ namespace Artemis.Profiles.Layers.Models /// /// Resets the event's properties and triggers it /// - public abstract void TriggerEvent(LayerModel layer); + public virtual void TriggerEvent(LayerModel layer) + { + if (!CanTrigger) + return; + + if (TriggerDelay > TimeSpan.Zero) + { + if (EventCanTriggerTime == DateTime.MinValue) + EventCanTriggerTime = DateTime.Now; + + if (DateTime.Now - EventCanTriggerTime < TriggerDelay) + return; + + EventCanTriggerTime = DateTime.MinValue; + } + + CanTrigger = false; + MustDraw = true; + EventTriggerTime = DateTime.Now; + layer.Properties.AnimationProgress = 0.0; + } + + public DateTime EventCanTriggerTime { get; set; } + /// /// Gets whether the event should stop /// /// /// - public abstract bool MustStop(LayerModel layer); + public virtual bool MustStop(LayerModel layer) + { + if (ExpirationType == ExpirationType.Time) + { + if (EventTriggerTime == DateTime.MinValue) + return false; + return DateTime.Now - EventTriggerTime > Length; + } + if (ExpirationType == ExpirationType.Animation) + return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer); + + return true; + } // Called every frame, if parent conditions met. public void Update(LayerModel layerModel, bool conditionsMet) { - if (MustStop(layerModel)) + if (EventCanTriggerTime > DateTime.MinValue && (DateTime.Now - EventCanTriggerTime > TriggerDelay)) + { + CanTrigger = true; + TriggerEvent(layerModel); + return; + } + + if (MustDraw && MustStop(layerModel)) MustDraw = false; if (!conditionsMet) - MustTrigger = true; + CanTrigger = true; + } + + protected bool DelayExpired() + { + return EventCanTriggerTime > DateTime.MinValue && DateTime.Now - EventCanTriggerTime >= TriggerDelay; } } diff --git a/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs index ce0cb8bd2..76c9cfb08 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs @@ -1,5 +1,4 @@ using System; -using Artemis.Profiles.Layers.Types.Keyboard; using Artemis.Profiles.Layers.Types.KeyboardGif; namespace Artemis.Profiles.Layers.Models @@ -8,40 +7,23 @@ namespace Artemis.Profiles.Layers.Models { public override void TriggerEvent(LayerModel layer) { - var keyboardProperties = layer.Properties as KeyboardPropertiesModel; - if (keyboardProperties == null) - throw new ArgumentException("Layer's properties cannot be null " + - "and must be of type KeyboardPropertiesModel"); - if (!MustTrigger) - return; + if (CanTrigger && DelayExpired()) + { + if (layer.GifImage != null) + layer.GifImage.CurrentFrame = 0; + } - MustTrigger = false; - MustDraw = true; - keyboardProperties.AnimationProgress = 0.0; - if (layer.GifImage != null) - layer.GifImage.CurrentFrame = 0; + base.TriggerEvent(layer); } public override bool MustStop(LayerModel layer) { - var keyboardProperties = layer.Properties as KeyboardPropertiesModel; - if (keyboardProperties == null) - throw new ArgumentException("Layer's properties cannot be null " + - "and must be of type KeyboardPropertiesModel"); + if (ExpirationType != ExpirationType.Animation) + return base.MustStop(layer); - switch (ExpirationType) - { - case ExpirationType.Time: - if (AnimationStart == DateTime.MinValue) - return false; - return DateTime.Now - Length > AnimationStart; - case ExpirationType.Animation: - if (layer.LayerType is KeyboardGifType) - return layer.GifImage?.CurrentFrame >= layer.GifImage?.FrameCount - 1; - return layer.LayerAnimation == null || layer.LayerAnimation.MustExpire(layer); - default: - return true; - } + if (layer.LayerType is KeyboardGifType) + return layer.GifImage?.CurrentFrame >= layer.GifImage?.FrameCount - 1; + return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs index 68d968013..e3bd0b529 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs @@ -242,5 +242,13 @@ namespace Artemis.Profiles.Layers.Models } #endregion + + public void SetupCondition() + { + if (IsEvent && !(LayerCondition is EventCondition)) + LayerCondition = new EventCondition(); + else if (!IsEvent && !(LayerCondition is DataModelCondition)) + LayerCondition = new DataModelCondition(); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs index 839e84abc..aac0629c6 100644 --- a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using Artemis.Models.Interfaces; using Artemis.Profiles.Layers.Abstract; +using Artemis.Profiles.Layers.Conditions; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Types.Keyboard; @@ -175,7 +176,9 @@ namespace Artemis.ViewModels.Profiles // TODO: EventPropVM must have layer too if (EventPropertiesViewModel != null) Layer.EventProperties = EventPropertiesViewModel.GetAppliedProperties(); - + + Layer.SetupCondition(); + // Don't bother checking for a GIF path unless the type is GIF if (!(Layer.LayerType is KeyboardGifType)) return; @@ -215,6 +218,11 @@ namespace Artemis.ViewModels.Profiles // that would upset the child layers' relations (sounds like Dr. Phil amirite?) var currentObj = Clone(Layer); currentObj.Children.Clear(); + + // Apply the IsEvent boolean + currentObj.SetupCondition(); + ProposedLayer.SetupCondition(); + var current = JsonConvert.SerializeObject(currentObj, Formatting.Indented); var proposed = JsonConvert.SerializeObject(ProposedLayer, Formatting.Indented); diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index cbce56fdc..0fd5e12ff 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -546,8 +546,13 @@ namespace Artemis.ViewModels.Profiles return; var newProfile = GeneralHelpers.Clone(SelectedProfile); - newProfile.Name = - await DialogService.ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); + newProfile.Name = await DialogService + .ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); + + // Null when the user cancelled + if (string.IsNullOrEmpty(newProfile.Name)) + return; + // Verify the name while (ProfileProvider.GetAll().Contains(newProfile)) { @@ -555,7 +560,7 @@ namespace Artemis.ViewModels.Profiles await DialogService.ShowInputDialog("Name already in use", "Please enter a unique profile name"); // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name)) + if (string.IsNullOrEmpty(newProfile.Name)) return; }