From ce07a1e86a8700db514a7b1eabdc9858a792e1c9 Mon Sep 17 00:00:00 2001 From: zznty <94796179+zznty@users.noreply.github.com> Date: Mon, 13 Nov 2023 23:17:39 +0700 Subject: [PATCH] actually now its usable --- Kits/Commands.cs | 25 +++ Kits/Config.cs | 20 ++ Kits/FodyWeavers.xml | 3 + Kits/KitManager.cs | 178 ++++++++++++++++++ Kits/KitViewModel.cs | 62 ++++++ Kits/Kits.csproj | 47 +++++ Kits/Plugin.cs | 50 +++++ Kits/Views/DefinitionIdEditor.xaml | 18 ++ Kits/Views/DefinitionIdEditor.xaml.cs | 12 ++ Kits/Views/EditButton.cs | 20 ++ Kits/Views/EditButton.xaml | 9 + Kits/Views/ProperCollectionEditor.cs | 21 +++ Kits/Views/ProperCollectionEditor.xaml | 35 ++++ {LuckPerms.Loader => Kits}/manifest.xml | 6 +- Kits/schema.xsd | 73 +++++++ LightPerms/LightPerms.csproj | 5 +- LuckPerms.Loader/LuckPerms.Loader.csproj | 49 ++--- LuckPerms.Loader/Plugin.cs | 82 +++++--- LuckPerms.Loader/packages.lock.json | 9 +- .../LuckPerms.Torch.Api.nuspec | 15 ++ .../buildTransitive/LuckPerms.Torch.Api.props | 5 + LuckPerms.Torch/Impl/LpTorchBootstrap.cs | 2 +- LuckPerms.Torch/Impl/LpTorchPlugin.cs | 45 ++++- LuckPerms.Torch/LuckPerms.Torch.csproj | 25 +-- LuckPerms.Torch/ModApi/ModApiManager.cs | 3 +- .../PlatformApi/LuckPermsPlatformManager.cs | 61 ++++++ LuckPerms.Torch/Plugin.cs | 55 +----- LuckPerms.Torch/Resources/config.yml | 5 +- LuckPerms.Torch/libs/sqlite-jdbc-3.43.2.2.jar | Bin 0 -> 13210271 bytes LuckPerms.Torch/packages.lock.json | 6 + Torch.Loader/Torch.Loader.csproj | 14 ++ .../buildTransitive/Torch.Loader.targets | 29 +++ TorchPlugins.sln | 39 ++++ heh/DbManager.cs | 43 +++++ heh/FodyWeavers.xml | 3 + heh/StringExtensions.cs | 35 ++++ heh/Utils/ChangeListener.cs | 71 +++++++ heh/Utils/ChildChangeListener.cs | 131 +++++++++++++ heh/Utils/CollectionChangeListener.cs | 123 ++++++++++++ heh/Utils/ProperPersistent.cs | 84 +++++++++ heh/heh.csproj | 21 +++ 41 files changed, 1401 insertions(+), 138 deletions(-) create mode 100644 Kits/Commands.cs create mode 100644 Kits/Config.cs create mode 100644 Kits/FodyWeavers.xml create mode 100644 Kits/KitManager.cs create mode 100644 Kits/KitViewModel.cs create mode 100644 Kits/Kits.csproj create mode 100644 Kits/Plugin.cs create mode 100644 Kits/Views/DefinitionIdEditor.xaml create mode 100644 Kits/Views/DefinitionIdEditor.xaml.cs create mode 100644 Kits/Views/EditButton.cs create mode 100644 Kits/Views/EditButton.xaml create mode 100644 Kits/Views/ProperCollectionEditor.cs create mode 100644 Kits/Views/ProperCollectionEditor.xaml rename {LuckPerms.Loader => Kits}/manifest.xml (55%) create mode 100644 Kits/schema.xsd create mode 100644 LuckPerms.Torch.Api/LuckPerms.Torch.Api.nuspec create mode 100644 LuckPerms.Torch.Api/buildTransitive/LuckPerms.Torch.Api.props create mode 100644 LuckPerms.Torch/PlatformApi/LuckPermsPlatformManager.cs create mode 100644 LuckPerms.Torch/libs/sqlite-jdbc-3.43.2.2.jar create mode 100644 Torch.Loader/Torch.Loader.csproj create mode 100644 Torch.Loader/buildTransitive/Torch.Loader.targets create mode 100644 heh/DbManager.cs create mode 100644 heh/FodyWeavers.xml create mode 100644 heh/StringExtensions.cs create mode 100644 heh/Utils/ChangeListener.cs create mode 100644 heh/Utils/ChildChangeListener.cs create mode 100644 heh/Utils/CollectionChangeListener.cs create mode 100644 heh/Utils/ProperPersistent.cs create mode 100644 heh/heh.csproj diff --git a/Kits/Commands.cs b/Kits/Commands.cs new file mode 100644 index 0000000..ef26804 --- /dev/null +++ b/Kits/Commands.cs @@ -0,0 +1,25 @@ +using Sandbox.Game.World; +using Torch.API.Managers; +using Torch.Commands; +using Torch.Commands.Permissions; +using VRage.Game.ModAPI; +namespace Kits; + +public class Commands : CommandModule +{ + [Command("kit")] + [Permission(MyPromoteLevel.None)] + public void GetKit(string name) + { + var manager = Context.Torch.CurrentSession.Managers.GetManager(); + var player = (MyPlayer)Context.Player; + + if (!manager.CanGiveKit(player, name, out var reason)) + { + Context.Respond(reason, "Error"); + return; + } + manager.GiveKit(player, player.Character.GetInventoryBase(), name); + Context.Respond($"You have got kit {name}"); + } +} diff --git a/Kits/Config.cs b/Kits/Config.cs new file mode 100644 index 0000000..210c0f2 --- /dev/null +++ b/Kits/Config.cs @@ -0,0 +1,20 @@ +using System.Collections.ObjectModel; +using System.Xml.Schema; +using System.Xml.Serialization; +using Kits.Views; +using Torch; +using Torch.Views; + +namespace Kits; + +[XmlRoot()] +public class Config : ViewModel +{ + [Display(Name = "Kits", EditorType = typeof(EditButton))] + [XmlArrayItem("Kit")] + public ObservableCollection Kits { get; set; } = new(); + + [XmlAttribute(Form = XmlSchemaForm.Qualified, Namespace = "http://www.w3.org/2001/XMLSchema-instance")] + // ReSharper disable once InconsistentNaming + public string noNamespaceSchemaLocation = "Kits.v1.0.6.xsd"; +} diff --git a/Kits/FodyWeavers.xml b/Kits/FodyWeavers.xml new file mode 100644 index 0000000..5a02dd9 --- /dev/null +++ b/Kits/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Kits/KitManager.cs b/Kits/KitManager.cs new file mode 100644 index 0000000..00ecf30 --- /dev/null +++ b/Kits/KitManager.cs @@ -0,0 +1,178 @@ +using heh; +using net.luckperms.api; +using NLog; +using PetaPoco; +using Sandbox.Game; +using Sandbox.Game.Entities; +using Sandbox.Game.GameSystems.BankingAndCurrency; +using Sandbox.Game.Multiplayer; +using Sandbox.Game.World; +using Torch.API; +using Torch.API.Managers; +using Torch.Managers; +using Torch.Server.Managers; +using VRage; +using VRage.Game.Entity; +using VRage.Library.Utils; +using VRage.ObjectBuilders; +namespace Kits; + +public class KitManager : Manager, IKitManager +{ + private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); + + private readonly Config _config; + + [Dependency] + private readonly IDbManager _dbManager = null!; + + [Dependency] + private readonly MultiplayerManagerDedicated _multiplayerManager = null!; + + private IDatabase _db = null!; + + public KitManager(ITorchBase torchInstance, Config config) : base(torchInstance) + { + _config = config; + } + + public override void Attach() + { + base.Attach(); + _db = _dbManager.Create("kits"); + MyVisualScriptLogicProvider.RespawnShipSpawned += RespawnShipSpawned; + } + private void RespawnShipSpawned(long shipEntityId, long playerId, string respawnShipPrefabName) + { + if (!MyEntities.TryGetEntityById(shipEntityId, out MyCubeGrid grid) || + !Sync.Players.TryGetPlayerId(playerId, out var playerClientId) || + Sync.Players.GetPlayerById(playerClientId) is not { } player) + return; + foreach (var kit in _config.Kits.Where(b => CanGiveRespawnKit(player, b, respawnShipPrefabName, out _))) + { + GiveKit(player, grid.GetFatBlocks().First(b => b is MyCargoContainer or MyCockpit).GetInventoryBase(), kit); + } + } + + public void GiveKit(MyPlayer player, MyInventoryBase inventory, string kitName) + { + GiveKit(player, inventory, GetKit(kitName)); + } + public bool CanGiveKit(MyPlayer player, string kitName, out string reason) + { + return CanGiveKit(player, GetKit(kitName), out reason); + } + public bool CanGiveRespawnKit(MyPlayer player, string kitName, string respawnName, out string reason) + { + return CanGiveRespawnKit(player, GetKit(kitName), respawnName, out reason); + } + public KitViewModel GetKit(string kitName) + { + return _config.Kits.First(b => b.Name == kitName); + } + public bool TryGetKit(string kitName, out KitViewModel? kit) + { + kit = _config.Kits.FirstOrDefault(b => b.Name == kitName); + return kit is not null; + } + + public void GiveKit(MyPlayer player, MyInventoryBase inventory, KitViewModel kit) + { + if (kit.UseCooldownMinutes > 0) + { + CheckTable(); + _db.Insert(new PlayerCooldown {Id = player.Id.SteamId.ToString(), KitName = kit.Name, LastUsed = DateTime.Now}); + } + + MyBankingSystem.ChangeBalance(player.Identity.IdentityId, kit.UseCost); + + foreach (var item in kit.Items.Where(b => b.Probability >= 1 || b.Probability < MyRandom.Instance.GetRandomFloat(0, 1))) + { + inventory.AddItems((MyFixedPoint)item.Amount, MyObjectBuilderSerializer.CreateNewObject(item.Id)); + } + + Log.Info($"Given kit {kit.Name} to {player.DisplayName} ({player.Id.SteamId})"); + } + + public bool CanGiveKit(MyPlayer player, KitViewModel kit, out string reason) + { + reason = string.Empty; + + var level = MySession.Static.GetUserPromoteLevel(player.Id.SteamId); + if (level < kit.RequiredPromoteLevel || + !string.IsNullOrEmpty(kit.LpPermission)) + { + var api = LuckPermsProvider.get(); + var torchPlayer = _multiplayerManager.Players[player.Id.SteamId]; + + if (!api.getPlayerAdapter(typeof(IPlayer)).getPermissionData(torchPlayer).checkPermission(kit.LpPermission).asBoolean()) + { + reason = "Not enough rights to acquire this"; + return false; + } + } + + if (kit.UseCost > 0 && kit.UseCost > MyBankingSystem.GetBalance(player.Identity.IdentityId)) + { + reason = "Not enough money to acquire this"; + return false; + } + + if (kit.UseCooldownMinutes <= 0) + return true; + + var sql = Sql.Builder.Where("id = @0", player.Id.SteamId).Append("AND kit_name = @0", kit.Name); + CheckTable(); + var playerCooldown = _db.SingleOrDefault(sql); + var cooldown = DateTime.Now - playerCooldown?.LastUsed; + + if (cooldown is null) + return true; + + if (cooldown > TimeSpan.FromMinutes(kit.UseCooldownMinutes)) + { + _db.Delete(sql); + return true; + } + + reason = $"Next use available in {TimeSpan.FromMinutes(kit.UseCooldownMinutes) - cooldown:dd\\.hh\\:mm\\:ss}"; + return false; + + } + public bool CanGiveRespawnKit(MyPlayer player, KitViewModel kit, string respawnName, out string reason) + { + reason = "Invalid respawn name"; + return kit.RespawnPodWildcards.Any(respawnName.Glob) && CanGiveKit(player, kit, out reason); + } + + private void CheckTable() + { + _db.Execute("create table if not exists cooldown (uid INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT NOT NULL, kit_name TEXT NOT NULL, last_used DATETIME NOT NULL)"); + } +} + +[TableName("cooldown")] +[PrimaryKey(nameof(Uid), AutoIncrement = true)] +public class PlayerCooldown +{ + [Column] + public long Uid { get; set; } + [Column] + public string Id { get; set; } = string.Empty; + [Column] + public string KitName { get; set; } = string.Empty; + [Column] + public DateTime LastUsed { get; set; } +} + +public interface IKitManager : IManager +{ + void GiveKit(MyPlayer player, MyInventoryBase inventory, string kitName); + void GiveKit(MyPlayer player, MyInventoryBase inventory, KitViewModel kit); + bool CanGiveKit(MyPlayer player, string kitName, out string reason); + bool CanGiveKit(MyPlayer player, KitViewModel kit, out string reason); + bool CanGiveRespawnKit(MyPlayer player, KitViewModel kit, string respawnName, out string reason); + bool CanGiveRespawnKit(MyPlayer player, string kitName, string respawnName, out string reason); + KitViewModel GetKit(string kitName); + bool TryGetKit(string kitName, out KitViewModel? kit); +} diff --git a/Kits/KitViewModel.cs b/Kits/KitViewModel.cs new file mode 100644 index 0000000..089670b --- /dev/null +++ b/Kits/KitViewModel.cs @@ -0,0 +1,62 @@ +using System.Collections.ObjectModel; +using System.Xml.Serialization; +using Kits.Views; +using Torch; +using Torch.Views; +using VRage.Game.ModAPI; +using VRage.ObjectBuilders; + +namespace Kits; + +public class KitViewModel : ViewModel +{ + [Display(Name = "Name", GroupName = "General")] + [XmlAttribute] + public string Name { get; set; } = "unnamed"; + [Display(Name = "Cost", GroupName = "Usage", Description = "Credits cost to use this kit")] + public long UseCost { get; set; } = 0; + [Display(Name = "Cooldown Minutes", GroupName = "Usage", Description = "Cooldown to use this kit per player in minutes")] + public ulong UseCooldownMinutes { get; set; } = 0; + [Display(Name = "Required Promote Level", GroupName = "Conditions", Description = "Minimal Promote Level to use this kit")] + public MyPromoteLevel RequiredPromoteLevel { get; set; } = MyPromoteLevel.None; + [Display(Name = "Lp Permission", GroupName = "Conditions", Description = "Luck Perms permission to use this kit (leave empty to disable, example: kits.vip)")] + public string LpPermission { get; set; } = ""; + [Display(Name = "Respawn Pod Wildcards", GroupName = "Usage", Description = "Respawn pod name wildcard to filter usage of kit, leave empty to disable")] + public ObservableCollection RespawnPodWildcards { get; set; } = new(); + [Display(Name = "Items", GroupName = "General", EditorType = typeof(EditButton))] + [XmlArrayItem("Item")] + public ObservableCollection Items { get; set; } = new(); + + public override string ToString() + { + return Name; + } +} +public class KitItemViewModel : ViewModel +{ + [Display(Name = "Id", EditorType = typeof(DefinitionIdEditor), Description = "TypeId/SubtypeId. Only items are allowed. for e.g Component/SteelPlate, Ore/Stone, PhysicalGunObject/RapidFireAutomaticRifleItem")] + public DefinitionId Id { get; set; } = new(); + [Display(Name = "Probability", Description = "Probability of the item. 1 is 100%, 0 is 0%")] + public float Probability { get; set; } = 1; + [Display(Name = "Amount")] + public float Amount { get; set; } = 0; + + [XmlIgnore] + public string Name => Id.ToString(); + + public override string ToString() + { + return Id.ToString(); + } +} + +public class DefinitionId : ViewModel +{ + [XmlAttribute] + public string TypeId { get; set; } = "type"; + [XmlAttribute] + public string SubtypeId { get; set; } = "subtype"; + + public override string ToString() => $"{TypeId}/{SubtypeId}"; + public static implicit operator SerializableDefinitionId(DefinitionId id) => new(MyObjectBuilderType.ParseBackwardsCompatible(id.TypeId), id.SubtypeId); +} diff --git a/Kits/Kits.csproj b/Kits/Kits.csproj new file mode 100644 index 0000000..0b04b09 --- /dev/null +++ b/Kits/Kits.csproj @@ -0,0 +1,47 @@ + + + + net48 + enable + enable + x64 + 10 + true + + + + none + + + + + + + + + + + + PreserveNewest + + + + + + + + + + + EditButton.xaml + + + ProperCollectionEditor.xaml + + + + + + + + diff --git a/Kits/Plugin.cs b/Kits/Plugin.cs new file mode 100644 index 0000000..54fa108 --- /dev/null +++ b/Kits/Plugin.cs @@ -0,0 +1,50 @@ +using System.IO; +using System.Windows.Controls; +using heh; +using heh.Utils; +using Kits.Views; +using Torch; +using Torch.API; +using Torch.API.Managers; +using Torch.API.Plugins; +using Torch.API.Session; +using Torch.Views; + +namespace Kits; + +public class Plugin : TorchPluginBase, IWpfPlugin +{ + private ProperPersistent _config = null!; + + public override void Init(ITorchBase torch) + { + base.Init(torch); + CheckConfigSchema(); + _config = new(Path.Combine(StoragePath, "Kits.xml")); + + Torch.Managers.AddManager(DbManager.Static); + Torch.Managers.GetManager().AddFactory(s => new KitManager(s.Torch, _config.Data)); + } + + private void CheckConfigSchema() + { + var files = Directory.EnumerateFiles(StoragePath, "Kits.*.xsd").ToList(); + if (files.Any() && files[0].Substring(files[0].IndexOf('.') + 1, Manifest.Version.Length) == Manifest.Version) + return; + + foreach (var file in files) + { + File.Delete(file); + } + + using var resource = typeof(Plugin).Assembly.GetManifestResourceStream("Kits.schema.xsd"); + using var stream = File.Create(Path.Combine(StoragePath, $"Kits.{Manifest.Version}.xsd")); + resource?.CopyTo(stream); + } + + public UserControl GetControl() => new PropertyGrid + { + Margin = new(3), + DataContext = _config.Data + }; +} diff --git a/Kits/Views/DefinitionIdEditor.xaml b/Kits/Views/DefinitionIdEditor.xaml new file mode 100644 index 0000000..d930cd5 --- /dev/null +++ b/Kits/Views/DefinitionIdEditor.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/Kits/Views/DefinitionIdEditor.xaml.cs b/Kits/Views/DefinitionIdEditor.xaml.cs new file mode 100644 index 0000000..bd4a1d4 --- /dev/null +++ b/Kits/Views/DefinitionIdEditor.xaml.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace Kits.Views; + +public partial class DefinitionIdEditor : UserControl +{ + public DefinitionIdEditor() + { + InitializeComponent(); + } +} + diff --git a/Kits/Views/EditButton.cs b/Kits/Views/EditButton.cs new file mode 100644 index 0000000..cb4aa67 --- /dev/null +++ b/Kits/Views/EditButton.cs @@ -0,0 +1,20 @@ +using System.Windows; +using System.Windows.Controls; +namespace Kits.Views; + +public partial class EditButton : UserControl +{ + public EditButton() + { + InitializeComponent(); + } + private void ButtonBase_OnClick(object sender, RoutedEventArgs e) + { + new ProperCollectionEditor + { + DataContext = DataContext, + WindowStartupLocation = WindowStartupLocation.CenterOwner, + Owner = Window.GetWindow(this) + }.ShowDialog(); + } +} diff --git a/Kits/Views/EditButton.xaml b/Kits/Views/EditButton.xaml new file mode 100644 index 0000000..7ae0287 --- /dev/null +++ b/Kits/Views/EditButton.xaml @@ -0,0 +1,9 @@ + +