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;
}
}
}