Иконка ресурса

FREE RustExportData : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Newtonsoft.Json;
using RustExportData;
using System.Linq;
using System.Reflection;
using Oxide.Classes;
using Oxide.Classes.Destructibles;
using Oxide.Core;
using Rust;
using UnityEngine;
using Component = UnityEngine.Component;
using Debug = UnityEngine.Debug;
using Time = UnityEngine.Time;
using Utility = Oxide.Classes.Utility;

namespace Oxide.Plugins
{
    [Info("Rust Export Data", "Skipcast", "1.0.0")]
    public class RustExportData : RustPlugin
    {
        // debug
        [ChatCommand("look")]
        void ChatCmd_Look(BasePlayer player)
        {
            var lookObject = PhysicsUtility.GetLookTarget(player);

            if (lookObject == null)
            {
                player.ChatMessage("Nothing found.");
                return;
            }

            string layerName = LayerMask.LayerToName(lookObject.layer);
            player.ChatMessage("[" + lookObject.tag + "] " + layerName + ": " + lookObject.name + " (" + String.Join(", ", (lookObject.transform.GetComponents<Component>().Select(comp => comp.GetType().Name)).ToArray()) + ")");

            if (lookObject.transform.parent != null)
            {
                player.ChatMessage("Parent:");
                var parent = lookObject.transform.parent.gameObject;
                string parentLayerName = LayerMask.LayerToName(parent.layer);
                player.ChatMessage("[" + parent.tag + "] " + layerName + ": " + parent.name + " (" + String.Join(", ", (parent.transform.GetComponents<Component>().Select(comp => comp.GetType().Name)).ToArray()) + ")");
            }
        }

        private static readonly string[] excludeList =
        {
            "ammo.rocket.smoke", // WIP Smoke Rocket
            "generator.wind.scrap", // Wind Turbine
        };

        private static readonly Dictionary<string, float> ovenTemperatures = new Dictionary<string, float>();

        private List<GameObject> destroyablePrefabObjects;
        private Dictionary<GameObject, ItemDefinition> destroyableItemDefinitions;
        private List<ItemDefinition> ammoDefinitions; 
        
        void OnServerInitialized()
        {
            TOD_Sky.Instance.Cycle.Hour = 12;
            
            if (Config["UploadUrl"] == null)
                Debug.LogError("[RustExportData] Config UploadUrl not defined.");

            if (Config["UploadPassword"] == null)
                Debug.LogError("[RustExportData] Config UploadPassword not defined.");
        }

        protected override void LoadDefaultConfig()
        {
            Config.Clear();
            Config["UploadPassword"] = "CHANGEME";
            Config["UploadUrl"] = "https://CHANGEME/upload";
            SaveConfig();
        }
        
        [ConsoleCommand("calcrust.upload")]
        void ConsoleCmd_Upload(ConsoleSystem.Arg arg)
        {
            if (arg.IsClientside)
                return;
            
            string data = JsonConvert.SerializeObject(ParseData());
            data = Utility.EncodeDataUri(data);
            webrequest.EnqueuePost((string) Config["UploadUrl"], "data=" + data, (statusCode, result) =>
            {
                Debug.Log("Response: " + new {statusCode, result});
            }, this, new Dictionary<string, string> {{"pw", (string) Config["UploadPassword"]}});
        }

        [ConsoleCommand("calcrust.export")]
        void ConsoleCmd_Export(ConsoleSystem.Arg arg)
        {
            if (arg.IsClientside)
                return;

            var data = ParseData();
            Interface.Oxide.DataFileSystem.WriteObject("RustExportData", data);
            Debug.Log("Exported to [server_identity]/oxide/data/RustExportData.json.");
        }

        [ConsoleCommand("calcrust.uploadurl")]
        void ConsoleCmd_UploadUrl(ConsoleSystem.Arg arg)
        {
            if (arg.IsClientside)
                return;

            string url = arg.GetString(0, null);
            if (url == null)
            {
                Debug.Log(Config["UploadUrl"]);
            }
            else
            {
                try
                {
                    var uri = new Uri(url);
                    Debug.Log(uri);
                    Config["UploadUrl"] = url;
                }
                catch (UriFormatException ex)
                {
                    Debug.Log("Invalid url.");
                }
            }
        }

        [ConsoleCommand("calcrust.uploadpass")]
        void ConsoleCmd_UploadPassword(ConsoleSystem.Arg arg)
        {
            if (arg.IsClientside)
                return;

            string password = arg.GetString(0, null);
            if (password == null)
            {
                Debug.Log(Config["UploadPassword"]);
            }
            else
            {
                Config["UploadPassword"] = password;
            }
        }

        private RustData ParseData()
        {
            var startTime = Time.realtimeSinceStartup;
            var data = new RustData();

            // Parse damage data
            {
                var prefabs = new List<string>();

                string[] endsWithBlacklist =
                {
                    ".twig.prefab",
                    ".wood.prefab",
                    ".stone.prefab",
                    ".metal.prefab",
                    ".toptier.prefab",
                    ".item.prefab",
                    ".close-end.prefab",
                    "open-end.prefab",
                    "close-start.prefab",
                    "open-start.prefab",
                    "close-end.asset",
                    "open-end.asset",
                    "close-start.asset",
                    "open-start.asset",
                    "impact.prefab",
                    "knock.prefab",
                    "ladder_prop.prefab",
                    "-deploy.asset",
                    ".skinnable.asset"
                };

                foreach (var str in GameManifest.Get().pooledStrings)
                {
                    if (!str.str.StartsWith("assets/")) continue;
                    if (!str.str.StartsWith("assets/prefabs/building")) continue;
                    if (endsWithBlacklist.Any(prefab => str.str.EndsWith(prefab)))
                        continue;
                    
                    prefabs.Add(str.str);
                }
                
                destroyablePrefabObjects = prefabs.Select(name => GameManager.server.FindPrefab(name)).ToList();
                destroyableItemDefinitions = new Dictionary<GameObject, ItemDefinition>();
                ammoDefinitions = new List<ItemDefinition>();

                // Add deployables to prefabObjects and ammo to ammoDefinitions.foreach (var item in ItemManager.itemList)
                {
                    if (excludeList.Contains(item.shortname))
                        continue;

                    if (item.GetComponent<ItemModProjectile>() != null)
                    {
                        ammoDefinitions.Add(item);
                    }

                    if (item.GetComponent<ItemModDeployable>() != null)
                    {
                        var gameObject = item.GetComponent<ItemModDeployable>().entityPrefab.Get();
                        var combatEntity = gameObject.GetComponent<BaseCombatEntity>();

                        if (combatEntity == null)
                            continue;

                        if (destroyablePrefabObjects.Contains(gameObject))
                            continue;

                        destroyablePrefabObjects.Add(gameObject);
                        destroyableItemDefinitions.Add(gameObject, item);
                    }
                }

                foreach (var prefab in destroyablePrefabObjects)
                {
                    if (prefab == null)
                    {
                        Debug.LogError("Prefab null");
                        continue;
                    }

                    var baseCombatEntity = prefab.GetComponent<BaseCombatEntity>();

                    if (baseCombatEntity != null)
                    {
                        string objectName = destroyableItemDefinitions.ContainsKey(prefab) ? destroyableItemDefinitions[prefab].shortname : prefab.name;
                        Destructible damageInfo = GetDamageInfo(baseCombatEntity);

                        data.DamageInfo.Add(objectName, damageInfo);
                    }
                }
            }

            Debug.Log("Damage data parsed");

            ovenTemperatures.Clear();

            // Find ovens and populate oven info
            foreach (ItemDefinition item in ItemManager.itemList)
            {
                var deployableMod = item.GetComponent<ItemModDeployable>();

                if (deployableMod != null)
                {
                    var deployObject = deployableMod.entityPrefab.Get();
                    var oven = deployObject.GetComponent<BaseOven>();

                    if (oven != null)
                    {
                        ovenTemperatures.Add(item.shortname, GetProperty<float, BaseOven>(oven, "cookingTemperature"));
                        //Debug.Log(item.shortname + ": " + oven.temperature + " - " + ovenTemperatures[item.shortname]);
                    }
                }
            }

            Debug.Log("Got oven information...");

            // Add cooking and smelting data
            foreach (ItemDefinition item in ItemManager.itemList)
            {
                var cookableMod = item.GetComponent<ItemModCookable>();

                if (cookableMod != null)
                {
                    var exportCookable = new ExportCookable();
                    data.CookableInfo.Add(item.shortname, exportCookable);

                    exportCookable.Output = new ExportRecipeItem
                    {
                        Count = cookableMod.amountOfBecome,
                        ItemId = cookableMod.becomeOnCooked.shortname
                    };

                    exportCookable.TTC = cookableMod.cookTime;
                    // burnable.fuel -= (float)(0.5 * ((double)this.cookingTemperature / 200.0));

                    foreach (var keyval in ovenTemperatures)
                    {
                        string shortname = keyval.Key;
                        float ovenTemp = keyval.Value;

                        if (ovenTemp >= cookableMod.lowTemp && ovenTemp <= cookableMod.highTemp)
                        {
                            var ovenDef = ItemManager.FindItemDefinition(shortname).GetComponent<ItemModDeployable>().entityPrefab.Get().GetComponent<BaseOven>();
                            var ovenFuel = ovenDef.fuelType.GetComponent<ItemModBurnable>();
                            float fuelConsumed = (float) (cookableMod.cookTime * (ovenTemp / 200.0) / ovenFuel.fuelAmount);
                            
                            exportCookable.UsableOvens.Add(new ExportCookable.Oven
                            {
                                Shortname = shortname,
                                FuelConsumed = fuelConsumed,
                                Fuel = ovenDef.fuelType.shortname
                            });
                        }
                    }
                }
            }

            Debug.Log("Cooking and smelting data parsed");

            foreach (ItemDefinition item in ItemManager.itemList)
            {
                if (excludeList.Contains(item.shortname))
                    continue;
                
                var newItem = new ExportItem();
                newItem.Name = item.displayName.english;
                newItem.Description = item.displayDescription.english;
                newItem.MaxStack = item.stackable;
                newItem.Category = item.category.ToString();
                newItem.Category = newItem.Category.Substring(0, 1).ToLower() + newItem.Category.Substring(1);
                
                // Set meta depending on item type
                var consumable = item.GetComponent<ItemModConsumable>();
                var consume = item.GetComponent<ItemModConsume>();
                var deployable = item.GetComponent<ItemModDeployable>();
                var wearable = item.GetComponent<ItemModWearable>();
                var cookable = item.GetComponent<ItemModCookable>();
                var entity = item.GetComponent<ItemModEntity>();
                var burnable = item.GetComponent<ItemModBurnable>();

                if (consumable != null)
                {
                    newItem.Meta.Add(MetaType.Consumable.ToCamelCaseString(), new MetaConsumable(item)
                    {
                        Effects = consumable.effects,
                        ItemsGivenOnConsume = consume?.product
                    });
                }

                if (deployable != null)
                {
                    var deployPrefab = deployable.entityPrefab.Get();
                    var oven = deployPrefab.GetComponent<BaseOven>();
                    var bed = deployPrefab.GetComponent<SleepingBag>();

                    if (oven != null)
                    {
                        newItem.Meta.Add(MetaType.Oven.ToCamelCaseString(), new MetaOven(item)
                        {
                            Oven = oven,
                            FuelType = oven.fuelType,
                            Slots = oven.inventorySlots,
                            AllowByproductCreation = oven.allowByproductCreation,
                            Temperature = GetProperty<float, BaseOven>(oven, "cookingTemperature")
                        });
                    }

                    if (bed != null)
                    {
                        newItem.Meta.Add(MetaType.Bed.ToCamelCaseString(), new MetaBed(item)
                        {
                            Bed = bed
                        });
                    }
                }

                if (wearable != null)
                {
                    if (wearable.HasProtections())
                    {
                        var protections = wearable.protectionProperties;

                        newItem.Meta.Add(MetaType.Wearable.ToCamelCaseString(), new MetaWearable(item)
                        {
                            Protections = protections
                        });
                    }
                }

                if (cookable != null)
                {
                    newItem.Meta.Add(MetaType.Cookable.ToCamelCaseString(), new MetaCookable(item)
                    {
                        Cookable = cookable
                    });
                }

                if (entity != null)
                {
                    var prefab = entity.entityPrefab.Get();

                    if (prefab == null)
                    {
                        Debug.LogWarning("ItemModEntity prefab null, ignoring: " + item.shortname);
                    }
                    else
                    {
                        var thrownWeapon = prefab.GetComponent<ThrownWeapon>();
                        var baseProjectile = prefab.GetComponent<global::BaseProjectile>();
                        var meleeWeapon = prefab.GetComponent<BaseMelee>();

                        if (thrownWeapon != null)
                        {
                            var throwable = thrownWeapon.prefabToThrow.Get();
                            var explosive = throwable.GetComponent<TimedExplosive>();

                            if (explosive != null)
                            {
                                newItem.Meta.Add(MetaType.Weapon.ToCamelCaseString(), new MetaWeapon(item)
                                {
                                    TimedExplosive = explosive
                                });
                            }
                        }
                        else if (baseProjectile != null)
                        {
                            var primaryAmmo = baseProjectile.primaryMagazine.ammoType;
                            var projectileMod = primaryAmmo.GetComponent<ItemModProjectile>();

                            var projectilePrefab = projectileMod.projectileObject.Get();
                            var projectile = projectilePrefab.GetComponent<Projectile>();

                            newItem.Meta.Add(MetaType.Weapon.ToCamelCaseString(), new MetaWeapon(item)
                            {
                                ProjectileMod = projectileMod,
                                BaseProjectile = baseProjectile,
                                Projectile = projectile
                            });
                        }
                        else if (meleeWeapon != null)
                        {
                            newItem.Meta.Add(MetaType.Weapon.ToCamelCaseString(), new MetaWeapon(item)
                            {
                                Melee = meleeWeapon
                            });
                        }
                    }
                }

                if (burnable != null)
                {
                    newItem.Meta.Add(MetaType.Burnable.ToCamelCaseString(), new MetaBurnable(item)
                    {
                        ByproductItem = burnable.byproductItem,
                        ByproductAmount = burnable.byproductAmount,
                        ByproductChance = (float) (1d - burnable.byproductChance),
                        FuelAmount = burnable.fuelAmount
                    });
                }

                data.Items.Add(item.shortname, newItem);
            }

            Debug.Log("Items parsed");

            foreach (ItemBlueprint blueprint in ItemManager.bpList)
            {
                if (excludeList.Contains(blueprint.targetItem.shortname))
                    continue;

                var newRecipe = new ExportRecipe();

                newRecipe.TTC = (int) blueprint.time;
                newRecipe.Parent = blueprint.targetItem.Parent?.shortname;
                
                foreach (ItemAmount ingredient in blueprint.ingredients)
                {
                    newRecipe.Input.Add(new ExportRecipeItem
                    {
                        Count = (int) ingredient.amount,
                        ItemId = ingredient.itemDef.shortname
                    });
                }

                newRecipe.Output = new ExportRecipeItem
                {
                    Count = blueprint.amountToCreate,
                    ItemId = blueprint.targetItem.shortname
                };
                
                data.Recipes.Add(blueprint.targetItem.shortname, newRecipe);
            }
            
            Debug.Log("Blueprints parsed");

            // Add all meta descriptions to item descriptions.foreach (var item in data.Items.Values)
            {
                item.Descriptions.AddRange(item.Meta.Values.SelectMany(meta => meta.Descriptions));
            }

            var endTime = Time.realtimeSinceStartup;
            var totalTime = endTime - startTime;
            data.Meta.Time = totalTime;
            
            return data;
        }

        private Destructible GetDamageInfo(BaseCombatEntity entity)
        {
            var instance = GameObject.Instantiate(entity.gameObject);
            var baseCombatEntity = instance.GetComponent<BaseCombatEntity>();
            baseCombatEntity.Spawn();

            Destructible result;
            
            try
            {
                var attackEntities = new Dictionary<ItemDefinition, BaseEntity>();

                foreach (ItemDefinition item in ItemManager.itemList)
                {
                    if (excludeList.Contains(item.shortname))
                        continue;

                    var entityMod = item.GetComponent<ItemModEntity>();
                    
                    if (entityMod != null)
                    {
                        var entityPrefab = entityMod.entityPrefab.Get();

                        if (entityPrefab == null)
                        {
                            Debug.LogWarning("ItemModEntity prefab null, ignoring damage info: " + item.shortname);
                            continue;
                        }
                        
                        var thrownWeapon = entityPrefab.GetComponent<ThrownWeapon>();
                        var attackEntity = entityPrefab.GetComponent<AttackEntity>();
                        
                        if (thrownWeapon != null)
                        {
                            var toThrow = thrownWeapon.prefabToThrow.Get();
                            var explosive = toThrow.GetComponent<TimedExplosive>();
                            
                            if (explosive != null)
                            {
                                // Don't include harmless items
                                if (explosive.damageTypes.Sum(t => t.amount) <= 0)
                                    continue;

                                attackEntities.Add(item, explosive);
                            }
                            else
                            {
                                Debug.LogError("Unhandled prefabToThrow: " + toThrow.name);
                            }
                        }
                        else if (attackEntity != null)
                        {
                            // Don't include harmless items
                            if (attackEntity is Hammer || attackEntity is BaseMelee && ((BaseMelee) attackEntity).TotalDamage() <= 0)
                                continue;
                            
                            if (attackEntity is BaseMelee || attackEntity is BaseProjectile)
                                attackEntities.Add(item, attackEntity);
                        }
                    }
                }

                if (baseCombatEntity is BuildingBlock)
                {
                    var destructible = (BuildingBlockDestructible) (result = new BuildingBlockDestructible());
                    var buildingBlock = (BuildingBlock) baseCombatEntity;

                    foreach (BuildingGrade.Enum grade in Enum.GetValues(typeof (BuildingGrade.Enum)))
                    {
                        if (grade == BuildingGrade.Enum.None || grade == BuildingGrade.Enum.Count)
                            continue;

                        buildingBlock.SetGrade(grade);
                        buildingBlock.SetHealthToMax();

                        var attackInfos = GetDamagesForCombatEntity(buildingBlock, attackEntities);
                        destructible.Grades.Add(grade.ToCamelCaseString(), attackInfos);
                    }
                }
                else // BaseCombatEntity
                {
                    var destructible = (DeployableDestructible) (result = new DeployableDestructible());
                    destructible.Values = GetDamagesForCombatEntity(baseCombatEntity, attackEntities);
                }
            }
            finally
            {
                if (!baseCombatEntity.IsDestroyed)
                {
                    baseCombatEntity.DestroyShared();
                    baseCombatEntity.Kill();
                }
            }

            result.HasProtection = GetField<DirectionProperties[], BaseCombatEntity>(baseCombatEntity, "propDirection").Any(protection => protection.bounds.size != Vector3.zero);

            return result;
        }

        private Dictionary<string, AttackInfo> GetDamagesForCombatEntity(BaseCombatEntity baseCombatEntity, Dictionary<ItemDefinition, BaseEntity> attackEntities)
        {
            var attackInfos = new Dictionary<string, AttackInfo>();

            foreach (var keyval in attackEntities)
            {
                ItemDefinition item = keyval.Key;
                BaseEntity attackEntity = keyval.Value;
                AttackInfo attackInfo = null;

                if (attackEntity is AttackEntity)
                {
                    if (attackEntity is BaseMelee)
                    {
                        var meleeInfo = (MeleeAttackInfo) (attackInfo = new MeleeAttackInfo());
                        meleeInfo.Values = GetHitValues(baseCombatEntity, 1, item, null, null, (BaseMelee) attackEntity);
                    }
                    else if (attackEntity is BaseProjectile)
                    {
                        var weaponInfo = (WeaponAttackInfo) (attackInfo = new WeaponAttackInfo());
                        AmmoTypes ammoFlags = ((BaseProjectile) attackEntity).primaryMagazine.definition.ammoTypes;
                        ItemDefinition[] ammoTypes = GetAmmoDefinitions(ammoFlags);

                        foreach (var ammoType in ammoTypes)
                        {
                            weaponInfo.Ammunitions.Add(ammoType.shortname, GetHitValues(baseCombatEntity, ((BaseProjectile) attackEntity).damageScale, item, ammoType.GetComponent<ItemModProjectile>(), null, null));
                        }
                    }
                }
                else if (attackEntity is TimedExplosive)
                {
                    var explosiveInfo = (ExplosiveAttackInfo) (attackInfo = new ExplosiveAttackInfo());
                    explosiveInfo.Values = GetHitValues(baseCombatEntity, 1, item, null, (TimedExplosive) attackEntity, null);
                }

                if (attackInfo == null)
                {
                    Debug.LogError("Unexpected item: " + item.name);
                    continue;
                }

                attackInfos.Add(item.shortname, attackInfo);
            }
            return attackInfos;
        }

        /// <summary>NOTE: Only one of modProjectile, explosive, and baseMelee should be assigned!</summary>
        private HitValues GetHitValues(BaseCombatEntity entity, float damageScale, ItemDefinition itemDefinition, ItemModProjectile modProjectile, TimedExplosive explosive, BaseMelee baseMelee)
        {
            var hitValues = new HitValues();
            var propDirections = GetField<DirectionProperties[], BaseCombatEntity>(entity, "propDirection");
            List<DamageTypeEntry> damageTypes;
            bool usesPropProtection = false;

            if (modProjectile != null)
            {
                GameObject projectileObject = modProjectile.projectileObject.Get();
                Projectile projectile  = projectileObject.GetComponent<Projectile>();
                TimedExplosive rocket = projectileObject.GetComponent<TimedExplosive>();

                if (projectile != null)
                {
                    damageTypes = projectile.damageTypes;
                    usesPropProtection = true;

                    if (projectile.conditionLoss > 0)
                    {
                        Debug.Log(projectile.conditionLoss);
                    }
                }
                else
                    damageTypes = rocket.damageTypes;
            }
            else if (explosive != null)
            {
                damageTypes = explosive.damageTypes;
            }
            else if (baseMelee != null)
            {
                damageTypes = baseMelee.damageTypes;
                usesPropProtection = true;
            }
            else
            {
                throw new NotImplementedException();
            }
            
            var weakHit = new HitInfo();
            weakHit.damageTypes.Add(damageTypes);
            weakHit.damageTypes.ScaleAll(damageScale);

            var strongHit = new HitInfo();
            strongHit.damageTypes.Add(damageTypes);
            strongHit.damageTypes.ScaleAll(damageScale);

            if (modProjectile != null && modProjectile.numProjectiles > 1)
            {
                weakHit.damageTypes.ScaleAll(modProjectile.numProjectiles);
                strongHit.damageTypes.ScaleAll(modProjectile.numProjectiles);
            }

            if (entity.baseProtection != null)
            {
                entity.baseProtection.Scale(weakHit.damageTypes);
                entity.baseProtection.Scale(strongHit.damageTypes);
            }

            if (usesPropProtection)
            {
                if (propDirections.Length > 1)
                {
                    Debug.LogWarning(entity.name + ": propDirections.Length > 1, invalid strong hit scaling! " + propDirections.Length);
                }

                foreach (var propDirection in propDirections)
                {
                    propDirection.extraProtection.Scale(strongHit.damageTypes);

                    if (propDirection.bounds.size == Vector3.zero) // Item doesn't have a weakspot
                    {
                        propDirection.extraProtection.Scale(weakHit.damageTypes);
                    }
                }
            }

            hitValues.WeakDPS = weakHit.damageTypes.Total();
            hitValues.StrongDPS = strongHit.damageTypes.Total();
            hitValues.TotalWeakHits = hitValues.WeakDPS > 0 ? entity.health / hitValues.WeakDPS : -1;
            hitValues.TotalStrongHits = hitValues.StrongDPS > 0 ? entity.health / hitValues.StrongDPS : -1;

            float maxCondition = itemDefinition.condition.max;

            // Calculate condition loss
            if (baseMelee != null)
            {
                float conditionLoss = baseMelee.GetConditionLoss();
                float num = 0;

                foreach (var damageType in baseMelee.damageTypes)
                {
                    num += Mathf.Clamp(damageType.amount - strongHit.damageTypes.Get(damageType.type), 0, damageType.amount);
                }
                
                conditionLoss = conditionLoss + num * 0.2f;

                float hitsFromOne = maxCondition / conditionLoss;
                float numStrongItems = hitValues.TotalStrongHits / hitsFromOne;
                float numWeakItems = hitValues.TotalWeakHits / hitsFromOne;

                hitValues.TotalStrongItems = hitValues.TotalStrongHits >= 0 ? numStrongItems : -1;
                hitValues.TotalWeakItems = hitValues.TotalWeakHits >= 0 ? numWeakItems : -1;
            }
            else if (explosive != null)
            {
                hitValues.TotalStrongItems = Mathf.Ceil(hitValues.TotalStrongHits);
                hitValues.TotalWeakItems = Mathf.Ceil(hitValues.TotalWeakHits);
            }
            else if (modProjectile != null)
            {
                var projectileObject = modProjectile.projectileObject.Get();
                var projectile = projectileObject.GetComponent<Projectile>();
                float conditionLoss;

                if (projectile != null)
                {
                    // Source: BaseProjectile.UpdateItemCondition
                    conditionLoss = 0.5f * 0.3333333f; // As accurate as it gets.The actual code uses Random.Range(0, 3) == 0 to apply 0.5f condition loss.}
                else // Explosives/Rockets/etc, shot from weapon
                {
                    conditionLoss = 4.5f; // The actual code applies Random.Range(4f, 5f) condition loss.}

                float hitsFromOne = maxCondition / conditionLoss;
                float numStrongItems = hitValues.TotalStrongHits / hitsFromOne;
                float numWeakItems = hitValues.TotalWeakHits / hitsFromOne;

                hitValues.TotalStrongItems = hitValues.TotalStrongHits >= 0 ? numStrongItems : -1;
                hitValues.TotalWeakItems = hitValues.TotalWeakHits >= 0 ? numWeakItems : -1;
            }
            
            return hitValues;
        }

        private ItemDefinition[] GetAmmoDefinitions(AmmoTypes ammoTypes)
        {
            List<ItemDefinition> result = new List<ItemDefinition>();

            foreach (var ammoDefinition in ammoDefinitions)
            {
                var projectile = ammoDefinition.GetComponent<ItemModProjectile>();

                if ((projectile.ammoType & ammoTypes) > 0)
                {
                    result.Add(ammoDefinition);
                }
            }

            return result.ToArray();
        }

        void OnPlayerAttack(BasePlayer attacker, HitInfo info)
        {
            //Debug.Log("OnPlayerAttack: " + info.Weapon.LookupPrefabName());
        }

        void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            //if (entity.name.Contains("/animals/"))
            //    return;
            //
            //var total = info.damageTypes.Total();
            //
            //if (info.HitEntity != null)
            //{
            //    var buildingBlock = info.HitEntity.GetComponent<global::BuildingBlock>();
            //
            //    if (buildingBlock != null)
            //    {
            //
            //    }
            //}
        }
        
        void OnEntitySpawned(BaseNetworkable entity)
        {
            string entityString = entity.ToString();

            if (entityString.Contains("/autospawn/") || entityString.Contains("/building core/"))
                return;

            //Debug.Log(entityString);
        }

        private void WriteComponents(MonoBehaviour behaviour) { WriteComponents(behaviour?.gameObject); }
        private void WriteComponents(GameObject gameObject)
        {
            if (gameObject == null)
            {
                Debug.Log("null []");
                return;
            }

            Debug.Log(gameObject.name + " [" + String.Join(", ", gameObject.GetComponents<MonoBehaviour>().Select(c => c.GetType().Name).ToArray()) + "]");
        }

        private void WriteDamageTypes(DamageTypeList damageInfo)
        {
            Dictionary<DamageType, float> damages = new Dictionary<DamageType, float>();
            for (int i = 0; i < (int)DamageType.LAST; ++i)
            {
                damages.Add((DamageType) i, damageInfo.types[i]);
            }

            Debug.Log(String.Join("\n", damages.Select(d => d.Key.ToString() + ": " + d.Value).ToArray()));
        }

        private void WriteDamageTypes(ProtectionProperties properties)
        {
            var damages = new Dictionary<DamageType, float>();

            for (int i = 0; i < (int) DamageType.LAST; ++i)
            {
                damages.Add((DamageType) i, properties.amounts[i]);
            }

            Debug.Log(String.Join("\n", damages.Select(d => d.Key.ToString() + ": " + d.Value).ToArray()));
        }

        public static T GetField<T, TClassType>(object obj, string memberName)
        {
            if (obj == null)
                return default(T);

            var targetType = typeof(TClassType);
            var type = obj.GetType();

            while (type != targetType)
            {
                if (!type.IsSubclassOf(targetType) || type.BaseType == null)
                    throw new ArgumentException(obj.GetType().FullName + " does not equal or inherit type " + targetType.FullName + ".");

                type = type.BaseType;
            }

            var fieldInfo = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);

            if (fieldInfo == null)
                return default(T);

            return (T) fieldInfo.GetValue(obj);
        }

        public static T GetProperty<T, TClassType>(object obj, string propertyName)
        {
            if (obj == null)
                throw new ArgumentNullException(nameof(obj));

            var targetType = typeof (TClassType);
            var type = obj.GetType();
            
            while (type != targetType)
            {
                if (!type.IsSubclassOf(targetType) || type.BaseType == null)
                    throw new ArgumentException(obj.GetType().FullName + " does not equal or inherit type " + targetType.FullName + ".");

                type = type.BaseType;
            }

            var propInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);

            if (propInfo == null)
                throw new NullReferenceException("No property found with name " + propertyName + " in type " + type.FullName + ".");

            return (T)propInfo.GetValue(obj, new object[0]);
        }
    }
}

namespace RustExportData
{
    internal class RustData
    {
        [JsonProperty("items")]
        public Dictionary<string, ExportItem> Items = new Dictionary<string, ExportItem>();

        [JsonProperty("recipes")]
        public Dictionary<string, ExportRecipe> Recipes = new Dictionary<string, ExportRecipe>();
        
        [JsonProperty("damageInfo")]
        public Dictionary<string, Destructible> DamageInfo = new Dictionary<string, Destructible>();

        [JsonProperty("cookables")]
        public Dictionary<string, ExportCookable> CookableInfo = new Dictionary<string, ExportCookable>();

        [JsonProperty("meta")]
        public Meta Meta;

        public RustData()
        {
            Meta = new Meta(DateTime.UtcNow, Protocol.printable);
        }
    }

    internal class ExportCookable
    {
        public class Oven
        {
            [JsonProperty("shortname")]
            public string Shortname;

            [JsonProperty("fuelConsumed")]
            public float FuelConsumed;

            [JsonProperty("fuel")]
            public string Fuel { get; set; } // The fuel type item's shortname.}

        [JsonProperty("usableOvens")]
        public List<Oven> UsableOvens = new List<Oven>();

        [JsonProperty("ttc")]
        public float TTC;

        [JsonProperty("output")]
        public ExportRecipeItem Output;
    }

    internal class Meta
    {
        [JsonProperty("lastUpdate")]
        public DateTime LastUpdate;

        [JsonProperty("time")]
        public float Time;

        [JsonProperty("version")]
        public string Version;

        public Meta(DateTime lastUpdate, string version)
        {
            LastUpdate = lastUpdate;
            Version = version;
        }
    }

    internal class ExportRecipe
    {
        [JsonProperty("input")]
        public List<ExportRecipeItem> Input = new List<ExportRecipeItem>();

        [JsonProperty("output")]
        public ExportRecipeItem Output;

        [JsonProperty("ttc")]
        public int TTC;

        [JsonProperty("level")]
        public int Level;

        [JsonProperty("price")]
        public int Price;

        [JsonProperty("parent")]
        public string Parent { get; set; }
    }

    internal class ExportRecipeItem
    {
        [JsonProperty("item")]
        public string ItemId;

        [JsonProperty("count")]
        public int Count;
    }

    internal class ExportItem
    {
        [JsonProperty("name")]
        public string Name;

        [JsonProperty("description")]
        public string Description;

        [JsonProperty("maxStack")]
        public int MaxStack;

        [JsonProperty("category")]
        public string Category;

        [JsonProperty("numMeta")]
        public int NumMeta => Meta.Count;

        [JsonProperty("meta")]
        public Dictionary<string, ItemMeta> Meta { get; set; } = new Dictionary<string, ItemMeta>();

        [JsonProperty("descriptions")]
        public List<string> Descriptions { get; set; } = new List<string>();
    }

    internal enum MetaType
    {
        None,
        Consumable,
        Oven,
        Wearable,
        Bed,
        Cookable,
        Weapon,
        Burnable
    }

    [JsonObject(MemberSerialization.OptIn)]
    internal abstract class ItemMeta
    {
        public abstract string[] Descriptions { get; }
        
        public ItemDefinition Item { get; private set; }

        public MetaType Type { get; private set; }

        [JsonProperty("type")]
        private string strType => Type.ToCamelCaseString();

        protected ItemMeta(ItemDefinition itemDef, MetaType type)
        {
            if (itemDef == null)
                throw new ArgumentNullException(nameof(itemDef));

            Item = itemDef;
            Type = type;
        }
    }

    internal class MetaConsumable : ItemMeta
    {
        public ItemAmountRandom[] ItemsGivenOnConsume;
        public List<ItemModConsumable.ConsumableEffect> Effects;

        [JsonIgnore]
        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();

                if (ItemsGivenOnConsume != null)
                {
                    foreach (var randomAmount in ItemsGivenOnConsume)
                    {
                        descs.Add("50% chance to give " + randomAmount.itemDef.displayName.english + ".");
                    }
                }

                foreach (var effect in Effects)
                {
                    var desc = "";
                    var type = effect.type;

                    if (effect.amount > 0)
                        desc += "Adds ";
                    else
                        desc += "Removes ";

                    desc += Math.Abs(effect.amount).ToString("0") + " ";
                    desc += (type == MetabolismAttribute.Type.HealthOverTime ? MetabolismAttribute.Type.Health : type).ToString().ToLower();

                    if (effect.type == MetabolismAttribute.Type.HealthOverTime)
                        desc += " over " + effect.time.ToString("0") + " seconds";

                    descs.Add(desc);
                }

                return descs.ToArray();
            }
        }

        public MetaConsumable(ItemDefinition itemDef) : base(itemDef, MetaType.Consumable)
        {
        }
    }

    internal class MetaOven : ItemMeta
    {
        public BaseOven Oven;

        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();

                foreach (var item in Oven.startupContents)
                {
                    descs.Add("Spawns with " + item.amount + " " + item.itemDef.displayName.english);
                }

                descs.Add("Can be used for " + Oven.temperature.ToString().ToLower());

                if (Oven.fuelType != null)
                {
                    float seconds = 0;
                    float fuelAmount = Oven.fuelType.GetComponent<ItemModBurnable>().fuelAmount;
                    float temperature = Oxide.Plugins.RustExportData.GetProperty<float, BaseOven>(Oven, "cookingTemperature");
                    seconds = 1f / ((temperature / 200f) / fuelAmount);
                    
                    descs.Add("Uses 1 " + Oven.fuelType.displayName.english + " every " + seconds + " second" + (seconds != 1d ? "s" : "") + ".");
                }

                return descs.ToArray();
            }
        }

        public ItemDefinition FuelType;

        [JsonProperty("slots")]
        public int Slots;

        [JsonProperty("allowByproductCreation")]
        public bool AllowByproductCreation { get; set; }

        [JsonProperty("temperature")]
        public float Temperature { get; set; }

        [JsonProperty("fuelType")]
        private string strFuelType => FuelType?.shortname;

        public MetaOven(ItemDefinition itemDef) : base(itemDef, MetaType.Oven)
        {
        }
    }

    internal class MetaWearable : ItemMeta
    {
        public ProtectionProperties Protections;

        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();

                var protectionAmounts = Utility.MergeProtectionAmounts(Protections);

                foreach (var keyval in protectionAmounts)
                    descs.Add(keyval.Value * 2f * 10f + " protection from " + Utility.DamageTypeToString(keyval.Key));

                return descs.ToArray();
            }
        }

        public MetaWearable(ItemDefinition itemDef) : base(itemDef, MetaType.Wearable)
        {
        }
    }

    internal class MetaBed : ItemMeta
    {
        public SleepingBag Bed { get; set; }

        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();

                descs.Add(Bed.secondsBetweenReuses + " second cooldown between respawns.Triggers cooldown on all beds within " + ConVar.Server.respawnresetrange + "m.");

                return descs.ToArray();
            }
        }

        public MetaBed(ItemDefinition itemDef) : base(itemDef, MetaType.Bed)
        {
        }
    }

    internal class MetaCookable : ItemMeta
    {
        public ItemModCookable Cookable;

        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();

                descs.Add("Can be cooked for " + Cookable.cookTime + " seconds to get x" + Cookable.amountOfBecome + " " + Cookable.becomeOnCooked.displayName.english);

                return descs.ToArray();
            }
        }

        public MetaCookable(ItemDefinition itemDef) : base(itemDef, MetaType.Cookable)
        {
        }
    }

    internal class MetaWeapon : ItemMeta
    {
        public ItemModProjectile ProjectileMod;
        public global::BaseProjectile BaseProjectile;
        public Projectile Projectile;
        
        public TimedExplosive TimedExplosive;
        public BaseMelee Melee;

        [JsonProperty("fireDelay")]
        private float fireDelay => Melee?.repeatDelay
                                 ?? BaseProjectile?.ScaleRepeatDelay(BaseProjectile.repeatDelay)
                                 ?? 0;

        [JsonProperty("reloadTime")]
        private float? reloadTime => BaseProjectile?.reloadTime ?? 0;

        [JsonProperty("magazineSize")]
        private int magazineSize => BaseProjectile?.primaryMagazine.definition.builtInSize ?? 0;

        public override string[] Descriptions
        {
            get
            {
                var descs = new List<string>();
                
                if (Projectile != null && ProjectileMod != null)
                {
                    if (ProjectileMod.numProjectiles > 1)
                        descs.Add("Fires " + ProjectileMod.numProjectiles + " projectiles per shot");

                    if (Projectile.breakProbability > 0)
                        descs.Add(Math.Round(Projectile.breakProbability * 100f) + "% to break ammo on impact");
                }

                return descs.ToArray();
            }
        }

        public MetaWeapon(ItemDefinition itemDef) : base(itemDef, MetaType.Weapon)
        {
        }
    }

    internal class MetaBurnable : ItemMeta
    {
        [JsonProperty("fuelAmount")]
        public float FuelAmount;

        [JsonProperty("byproductAmount")]
        public int ByproductAmount;

        [JsonProperty("byproductChance")]
        public float ByproductChance;

        public ItemDefinition ByproductItem;

        [JsonProperty("byproductItem")]
        private string strByproductItem => ByproductItem?.shortname;

        public MetaBurnable(ItemDefinition itemDef) : base(itemDef, MetaType.Burnable)
        {
        }

        public override string[] Descriptions => new string[0];
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху