using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace SynapticPro.GOAP { /// /// World State - Manages the state of the world for GOAP planning /// [Serializable] public class WorldState { private Dictionary states = new Dictionary(); /// /// Set a state value /// public void SetState(string key, object value) { if (string.IsNullOrEmpty(key)) return; if (states.ContainsKey(key)) { states[key] = value; } else { states.Add(key, value); } } /// /// Get a state value /// public T GetState(string key) { if (states.TryGetValue(key, out var value)) { if (value is T typedValue) { return typedValue; } // Try conversion try { return (T)Convert.ChangeType(value, typeof(T)); } catch { return default(T); } } return default(T); } /// /// Check if state exists /// public bool HasState(string key) { return states.ContainsKey(key); } /// /// Remove a state /// public void RemoveState(string key) { if (states.ContainsKey(key)) { states.Remove(key); } } /// /// Clear all states /// public void Clear() { states.Clear(); } /// /// Get all states as dictionary /// public Dictionary GetAllStates() { return new Dictionary(states); } /// /// Clone this world state /// public WorldState Clone() { var clone = new WorldState(); foreach (var kvp in states) { clone.states[kvp.Key] = kvp.Value; } return clone; } /// /// Apply another state on top of this one /// public void ApplyState(WorldState other) { if (other == null) return; foreach (var kvp in other.states) { states[kvp.Key] = kvp.Value; } } /// /// Check if this state satisfies the conditions /// public bool Satisfies(Dictionary conditions) { if (conditions == null || conditions.Count == 0) { return true; } foreach (var condition in conditions) { if (!HasState(condition.Key)) { return false; } var currentValue = states[condition.Key]; if (!ValuesEqual(currentValue, condition.Value)) { return false; } } return true; } /// /// Compare two values for equality /// private bool ValuesEqual(object a, object b) { if (a == null && b == null) return true; if (a == null || b == null) return false; // Handle numeric comparisons if (IsNumeric(a) && IsNumeric(b)) { return Convert.ToDouble(a) == Convert.ToDouble(b); } return a.Equals(b); } private bool IsNumeric(object obj) { return obj is int || obj is float || obj is double || obj is long || obj is short || obj is byte; } /// /// Get hash code for state comparison /// public override int GetHashCode() { int hash = 17; foreach (var kvp in states.OrderBy(x => x.Key)) { hash = hash * 31 + kvp.Key.GetHashCode(); hash = hash * 31 + (kvp.Value?.GetHashCode() ?? 0); } return hash; } /// /// String representation for debugging /// public override string ToString() { var sb = new System.Text.StringBuilder(); sb.AppendLine("WorldState:"); foreach (var kvp in states) { sb.AppendLine($" {kvp.Key}: {kvp.Value}"); } return sb.ToString(); } /// /// Initialize from dictionary /// public static WorldState FromDictionary(Dictionary dict) { var state = new WorldState(); if (dict != null) { foreach (var kvp in dict) { state.SetState(kvp.Key, kvp.Value); } } return state; } } }