using Godot; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using BITKit.Core.Entites; using BITKit.Packages.Core.LazyLoad; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace BITKit; /// /// 单例SCADA Service,从http接口获取json后解析为指定数据 /// public partial class SCADAService : Node,IProvider,IActivable { public const string _CurrentAngle="CurrentAngle"; public const string _CurrentRotation="CurrentRotation"; /// /// 在构造函数中注入依赖 /// public SCADAService() { BITApp.ServiceCollection.AddSingleton(this); } /// /// 获取json的Url /// private readonly DataReference _url = new("SCADA_GetInfos"); /// /// 是否固定控制的Entity,如果固定,只会刷新一次,如果不固定,每帧都会刷新 /// [Export] private bool fixedEntities; /// /// 是否启用 /// [Export] public bool Enabled { get; set; } = true; /// /// 已加载的Entity /// private readonly Dictionary _entities = new(); /// /// 获取Entity并加载依赖 /// public override async void _Ready() { if (!fixedEntities) return; await UniTask.Yield(); LoadAllEntities(); BIT4Log.Log($"已加载{_entities.Count}个设备"); if (string.IsNullOrEmpty(_url)) { BIT4Log.Warning("SCADA Url为空"); } else { BIT4Log.Log($"已找到SCADA_GetInfos:\t{_url.Get()}"); } } /// /// 内部方法,从EntityService加载所有Entity /// private void LoadAllEntities() { foreach (var entity in DI.Get().Entities) { if (entity.TryGetComponent(out var deviceComponent)) { _entities.Add(deviceComponent.Id,deviceComponent.Entity); } } } /// /// 从http请求json /// /// /// 解析json /// /// 从SCADA获取的Json public void Set(string json) { if(Enabled is false)return; //首先从result中获取数组 var jArray = JsonConvert.DeserializeObject(json)["result"]!.ToObject(); //然后遍历所有数组的内容 foreach (var element in jArray) { //获取数组元素的Id var id = element["id"]!.ToObject(); //通过Id查找已加载的Entity if (!_entities.TryGetValue(id, out var entity)) continue; //加载数组中的"value"为json var _key = element["value"]!.ToString(); string _json; if (_key.Substring(0) is "\"") { _json = element["value"]!.ToObject(); } else { _json = element["value"].ToString(); } //获取被加载为string的json var obj = JsonConvert.DeserializeObject(_json); //反序列化string为原始json var value = JObject.Parse(obj!.ToString()!); //提交json和entity ProcessEntity(value,entity); } } /// /// 提交jObject数据和Entity进行解析和处理 /// /// json [result] [index] [value] 中的原始json /// 引用实体,如PLC-ZL private static void ProcessEntity(JObject jObject, IEntity entity) { //从Entity中加载所有Rotation Component var rotationComponents = entity .Components .Where(x => x is RotationComponent) .Select((x => (RotationComponent)x)); //遍历所有Rotation Component foreach (var rotationComponent in rotationComponents) { //加载rotation需要的path,如 var angle = value["J1"] var path = rotationComponent.Path; //加载以获取到的角度 var rawAngle = jObject[path]!.ToObject(); //补间角度 var currentAngle = rotationComponent.CurrentAngle = Mathf.Lerp(rotationComponent.CurrentAngle, rawAngle, 90 * BITAppForGodot.DeltaTime); //最终角度 = 当前角度*角度权重 + 角度偏移 + 原始角度 var euler = currentAngle * rotationComponent.Weight + rotationComponent.Offset + rotationComponent.OriginalEuler; //为Node3D.Rotation提交最后的角度计算结果 euler.X = Mathf.DegToRad(euler.X); euler.Y = Mathf.DegToRad(euler.Y); euler.Z = Mathf.DegToRad(euler.Z); rotationComponent.node3D.Rotation = euler; //rotationComponent.RotationDegrees = euler; rotationComponent.SetMeta(_CurrentAngle,(int)rawAngle); rotationComponent.SetMeta(_CurrentRotation,euler); } } public string Get() { throw new NotImplementedException(); } public void SetActive(bool active) => Enabled = active; }