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

FREE GetState : 0.1 0.1

Нет прав для скачивания
C#:
// File: GetState.cs
// Drop into: <your_server>/oxide/plugins/
// Helper functions for building game state snapshots (players and ore nodes)

using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("GetState", "You", "0.1")]
    [Description("Helper functions for building game state snapshots")]
    public class GetState : CovalencePlugin
    {
        // Limit nodes to avoid enormous payloads on dense maps
        private const int MAX_NODES_RETURNED = 1000;

        /// <summary>
        /// Build the structured snapshot containing players and ore nodes.
        /// This method MUST be called on the main thread.
        /// </summary>
        /// <returns>Snapshot object containing players and nodes data</returns>
        public object BuildSnapshot()
        {
            var playersList = new List<object>();
            try
            {
                // Copy to list to avoid collection-modified exceptions
                var active = BasePlayer.activePlayerList?.ToList() ?? new List<BasePlayer>();
                foreach (var p in active)
                {
                    if (p == null) continue;
                    try
                    {
                        // Basic spatial & identity
                        var pos = p.transform?.position ?? Vector3.zero;
                        var rot = p.transform?.eulerAngles ?? Vector3.zero;

                        // Health & metabolism (defensive)
                        float? health = null;
                        try { health = p.Health(); } catch { }

                        float? maxHealth = null;
                        try
                        {
                            // MaxHealth is not guaranteed across versions; call defensively
                            var mi = p.GetType().GetMethod("MaxHealth");
                            if (mi != null) maxHealth = Convert.ToSingle(mi.Invoke(p, null));
                        }
                        catch { }

                        float? calories = null;
                        float? hydration = null;
                        bool isSwimming = false;
                        try
                        {
                            var meta = p.metabolism;
                            if (meta != null)
                            {
                                try { calories = (float?)meta.calories?.value; } catch { }
                                try { hydration = (float?)meta.hydration?.value; } catch { }
                            }
                        }
                        catch { }
                        
                        // Check if player is swimming using WaterFactor
                        try
                        {
                            float waterFactor = p.WaterFactor();
                            // Player is swimming if water factor is above 0.65 (standard swimming threshold)
                            isSwimming = waterFactor > 0.30f;
                        }
                        catch { }

                        // Inventory aggregation (main, belt, wear)
                        var items = new List<object>();
                        try
                        {
                            var main = p.inventory?.containerMain?.itemList;
                            if (main != null)
                            {
                                foreach (var it in main)
                                {
                                    var serial = SerializeItem(it, "main");
                                    if (serial != null) items.Add(serial);
                                }
                            }
                        }
                        catch { /* ignore inventory exceptions per-player */ }

                        try
                        {
                            var belt = p.inventory?.containerBelt?.itemList;
                            if (belt != null)
                            {
                                foreach (var it in belt)
                                {
                                    var serial = SerializeItem(it, "belt");
                                    if (serial != null) items.Add(serial);
                                }
                            }
                        }
                        catch { }

                        try
                        {
                            var wear = p.inventory?.containerWear?.itemList;
                            if (wear != null)
                            {
                                foreach (var it in wear)
                                {
                                    var serial = SerializeItem(it, "wear");
                                    if (serial != null) items.Add(serial);
                                }
                            }
                        }
                        catch { }

                        playersList.Add(new
                        {
                            steamId = p.userID.ToString(),
                            name = p.displayName,
                            position = new { x = pos.x, y = pos.y, z = pos.z },
                            rotation = new { x = rot.x, y = rot.y, z = rot.z },
                            health = health,
                            maxHealth = maxHealth,
                            calories = calories,
                            hydration = hydration,
                            isSleeping = p.IsSleeping(),
                            isConnected = p.IsConnected,
                            isSwimming = isSwimming,
                            items = items
                        });
                    }
                    catch (Exception ex)
                    {
                        PrintWarning($"GetState: error building player snapshot for a player: {ex}");
                        // continue with other players
                    }
                }
            }
            catch (Exception ex)
            {
                PrintWarning($"GetState: players collection error: {ex}");
            }

            // Nodes: search server entities and pick OreResourceEntity instances (stone/metal/sulfur)
            var nodesList = new List<object>();
            var nodePositions = new List<Vector3>(); // Store node positions for NodeInView calculation
            var playerObjects = new Dictionary<string, BasePlayer>(); // Store player references for NodeInView
            
            // Extract player objects for later use
            foreach (var p in BasePlayer.activePlayerList?.ToList() ?? new List<BasePlayer>())
            {
                if (p != null)
                {
                    playerObjects[p.userID.ToString()] = p;
                }
            }
            
            try
            {
                var entities = BaseNetworkable.serverEntities?.ToList() ?? new List<BaseNetworkable>();
                int count = 0;
                foreach (var net in entities)
                {
                    if (count >= MAX_NODES_RETURNED) break;
                    try
                    {
                        var be = net as BaseEntity;
                        if (be == null) continue;

                        // Check for the OreResourceEntity component (defensive)
                        var ore = be.GetComponent<global::OreResourceEntity>(); // fully qualified to avoid ambiguity
                        if (ore == null) continue;

                        // Determine prefab name (ShortPrefabName is common)
                        string prefab = null;
                        try { prefab = be.ShortPrefabName; } catch { }
                        if (string.IsNullOrEmpty(prefab))
                        {
                            try { prefab = be.name; } catch { }
                        }
                        if (string.IsNullOrEmpty(prefab)) prefab = "unknown";

                        // Filter: only include typical ore node prefabs (stone, metal, sulfur)
                        var lower = prefab.ToLowerInvariant();
                        if (!(lower.Contains("stone") || lower.Contains("metal") || lower.Contains("sulfur") || lower.Contains("ore"))) continue;

                        var pos = be.transform?.position ?? Vector3.zero;
                        float? nodeHealth = TryGetEntityHealth(be); // defensive health read

                        nodesList.Add(new
                        {
                            prefab = prefab,
                            position = new { x = pos.x, y = pos.y, z = pos.z },
                            health = nodeHealth
                        });
                        
                        nodePositions.Add(pos); // Store for NodeInView calculation

                        count++;
                    }
                    catch
                    {
                        // skip problematic entities
                    }
                }
            }
            catch (Exception ex)
            {
                PrintWarning($"GetState: nodes collection error: {ex}");
            }

            // Calculate NodeInView for each player and rebuild player list
            var finalPlayersList = new List<object>();
            foreach (var playerData in playersList)
            {
                int nodeInView = 0;
                string steamId = null;
                string name = null;
                object position = null;
                object rotation = null;
                float? health = null;
                float? maxHealth = null;
                float? calories = null;
                float? hydration = null;
                bool isSleeping = false;
                bool isConnected = false;
                bool isSwimming = false;
                List<object> items = null;
                
                try
                {
                    // Extract data using reflection to avoid dynamic
                    var type = playerData.GetType();
                    steamId = type.GetProperty("steamId")?.GetValue(playerData) as string;
                    name = type.GetProperty("name")?.GetValue(playerData) as string;
                    position = type.GetProperty("position")?.GetValue(playerData);
                    rotation = type.GetProperty("rotation")?.GetValue(playerData);
                    health = type.GetProperty("health")?.GetValue(playerData) as float?;
                    maxHealth = type.GetProperty("maxHealth")?.GetValue(playerData) as float?;
                    calories = type.GetProperty("calories")?.GetValue(playerData) as float?;
                    hydration = type.GetProperty("hydration")?.GetValue(playerData) as float?;
                    
                    var isSleepingObj = type.GetProperty("isSleeping")?.GetValue(playerData);
                    if (isSleepingObj != null) isSleeping = (bool)isSleepingObj;
                    
                    var isConnectedObj = type.GetProperty("isConnected")?.GetValue(playerData);
                    if (isConnectedObj != null) isConnected = (bool)isConnectedObj;
                    
                    var isSwimmingObj = type.GetProperty("isSwimming")?.GetValue(playerData);
                    if (isSwimmingObj != null) isSwimming = (bool)isSwimmingObj;

                    items = type.GetProperty("items")?.GetValue(playerData) as List<object>;
                    
                    // Calculate NodeInView
                    if (!string.IsNullOrEmpty(steamId) && playerObjects.ContainsKey(steamId))
                    {
                        var player = playerObjects[steamId];
                        if (player != null && !player.IsSleeping())
                        {
                            nodeInView = CalculateNodeInView(player, nodePositions);
                        }
                    }
                }
                catch (Exception ex)
                {
                    PrintWarning($"GetState: error calculating NodeInView: {ex}");
                }
                
                finalPlayersList.Add(new
                {
                    steamId = steamId,
                    name = name,
                    position = position,
                    rotation = rotation,
                    health = health,
                    maxHealth = maxHealth,
                    calories = calories,
                    hydration = hydration,
                    isSleeping = isSleeping,
                    isConnected = isConnected,
                    items = items,
                    nodeInView = nodeInView,
                    isSwimming = isSwimming
                });
            }

            var snapshot = new
            {
                serverTimeUtc = DateTime.UtcNow,
                players = finalPlayersList,
                nodes = nodesList,
                playersCount = finalPlayersList.Count,
                nodesCount = nodesList.Count
            };

            return snapshot;
        }

        /// <summary>
        /// Serialize an Item to a compact object; runs on main thread.
        /// </summary>
        private object SerializeItem(Item item, string container)
        {
            if (item == null) return null;
            try
            {
                string shortname = null;
                try { shortname = item.info?.shortname; } catch { }
                string displayName = null;
                try { displayName = item.info?.displayName?.english; } catch { }
                int amount = 0;
                try { amount = item.amount; } catch { }
                ulong skin = 0;
                try { skin = item.skin; } catch { }
                float? condition = null;
                try { condition = item.condition; } catch { }

                int? itemId = null;
                try { itemId = item.info?.itemid; } catch { }

                return new
                {
                    container = container,
                    itemId = itemId,
                    shortName = shortname,
                    displayName = displayName,
                    amount = amount,
                    skin = skin,
                    condition = condition
                };
            }
            catch
            {
                return new { container = container, shortName = "unknown" };
            }
        }

        /// <summary>
        /// Calculate if any node is visible to the player (within view cone and line of sight).
        /// Returns 1 if at least one node is visible, 0 otherwise.
        /// </summary>
        private int CalculateNodeInView(BasePlayer player, List<Vector3> nodePositions)
        {
            if (player == null || nodePositions == null || nodePositions.Count == 0)
                return 0;
            
            try
            {
                // Get player's eye position (head) and view direction
                Vector3 eyePos = player.transform.position;
                
                // Field of view parameters
                float fovAngle = 0.7f; // Typical FoV in degrees (half angle, so 90 total cone)
                float maxViewDistance = 30f; // Maximum distance to check for nodes

                int layer_mask = LayerMask.GetMask("Construction", "Default", "Deployed", "Resource", "Terrain", "World");                
                foreach (var nodePos in nodePositions)
                {
                    // Calculate direction from player to node
                    Vector3 toNode = nodePos - eyePos;
                    float distance = toNode.magnitude;
                        
                    // Skip if too far
                    if (distance > maxViewDistance)
                        continue;
                        
                        // Check if node is within view cone                    
                    Vector3 directionToNode = (nodePos - player.eyes.position).normalized;
                    float dot = Vector3.Dot(player.eyes.HeadForward(), directionToNode);

                    if (dot >= fovAngle)
                    {
                            // Node is in view cone, now check line of sight
                        RaycastHit hit;
                        if (Physics.Raycast(player.eyes.position, directionToNode, out hit, distance, layer_mask))
                        {
                            var entity = hit.GetEntity();
                            if (entity != null && Vector3.Distance(hit.point, nodePos) < 3f) {
                                // Node is actually visible and not blocked
                                return 1;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                PrintWarning($"GetState: CalculateNodeInView error: {ex}");
                return 2;
            }
            
            return 0; // No visible nodes found
        }
        
        /// <summary>
        /// Try to read an entity's health in a defensive manner.
        /// </summary>
        private float? TryGetEntityHealth(BaseEntity be)
        {
            if (be == null) return null;
            try
            {
                // Most BaseEntity-derived types expose a health field or property:
                try
                {
                    // direct property access (most common)
                    var h = be.Health();
                    return h;
                }
                catch { }

                // Fallback: reflect for "health" or "GetHealth"/"Health" methods/properties
                try
                {
                    var t = be.GetType();
                    var prop = t.GetProperty("health");
                    if (prop != null)
                    {
                        var val = prop.GetValue(be);
                        if (val is float fv) return fv;
                        if (val is double dv) return (float)dv;
                        if (val is int iv) return iv;
                    }
                }
                catch { }

                try
                {
                    var mi = be.GetType().GetMethod("GetHealth") ?? be.GetType().GetMethod("Health") ?? be.GetType().GetMethod("health");
                    if (mi != null)
                    {
                        var val = mi.Invoke(be, null);
                        if (val is float vf) return vf;
                        if (val is double vd) return (float)vd;
                        if (val is int vi) return vi;
                    }
                }
                catch { }
            }
            catch { }
            return null;
        }
    }
}

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