Decompiled source of ShoppingList v0.2.0

BepInEx/plugins/ShoppingList.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using KaimiraGames;
using Microsoft.CodeAnalysis;
using StbRectPackSharp;
using Unity.Netcode;
using Unity.VisualScripting;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ShoppingList")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("Shopping List")]
[assembly: AssemblyTitle("ShoppingList")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace KaimiraGames
{
	public class WeightedList<T> : IEnumerable<T>, IEnumerable
	{
		private readonly List<T> _list = new List<T>();

		private readonly List<int> _weights = new List<int>();

		private readonly List<int> _probabilities = new List<int>();

		private readonly List<int> _alias = new List<int>();

		private readonly Random _rand;

		private int _totalWeight;

		private bool _areAllProbabilitiesIdentical = false;

		private int _minWeight;

		private int _maxWeight;

		public WeightErrorHandlingType BadWeightErrorHandling { get; set; } = WeightErrorHandlingType.SetWeightToOne;


		public int TotalWeight => _totalWeight;

		public int MinWeight => _minWeight;

		public int MaxWeight => _maxWeight;

		public IReadOnlyList<T> Items => _list.AsReadOnly();

		public T this[int index] => _list[index];

		public int Count => _list.Count;

		public WeightedList(Random rand = null)
		{
			_rand = rand ?? new Random();
		}

		public WeightedList(ICollection<WeightedListItem<T>> listItems, Random rand = null)
		{
			_rand = rand ?? new Random();
			foreach (WeightedListItem<T> listItem in listItems)
			{
				_list.Add(listItem._item);
				_weights.Add(listItem._weight);
			}
			Recalculate();
		}

		public T Next()
		{
			if (Count == 0)
			{
				return default(T);
			}
			int index = _rand.Next(Count);
			if (_areAllProbabilitiesIdentical)
			{
				return _list[index];
			}
			int num = _rand.Next(_totalWeight);
			return (num < _probabilities[index]) ? _list[index] : _list[_alias[index]];
		}

		public void AddWeightToAll(int weight)
		{
			if (weight + _minWeight <= 0 && BadWeightErrorHandling == WeightErrorHandlingType.ThrowExceptionOnAdd)
			{
				throw new ArgumentException($"Subtracting {-1 * weight} from all items would set weight to non-positive for at least one element.");
			}
			for (int i = 0; i < Count; i++)
			{
				_weights[i] = FixWeight(_weights[i] + weight);
			}
			Recalculate();
		}

		public void SubtractWeightFromAll(int weight)
		{
			AddWeightToAll(weight * -1);
		}

		public void SetWeightOfAll(int weight)
		{
			if (weight <= 0 && BadWeightErrorHandling == WeightErrorHandlingType.ThrowExceptionOnAdd)
			{
				throw new ArgumentException("Weight cannot be non-positive.");
			}
			for (int i = 0; i < Count; i++)
			{
				_weights[i] = FixWeight(weight);
			}
			Recalculate();
		}

		public IEnumerator<T> GetEnumerator()
		{
			return _list.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return _list.GetEnumerator();
		}

		public void Add(T item, int weight)
		{
			_list.Add(item);
			_weights.Add(FixWeight(weight));
			Recalculate();
		}

		public void Add(ICollection<WeightedListItem<T>> listItems)
		{
			foreach (WeightedListItem<T> listItem in listItems)
			{
				_list.Add(listItem._item);
				_weights.Add(FixWeight(listItem._weight));
			}
			Recalculate();
		}

		public void Clear()
		{
			_list.Clear();
			_weights.Clear();
			Recalculate();
		}

		public bool Contains(T item)
		{
			return _list.Contains(item);
		}

		public int IndexOf(T item)
		{
			return _list.IndexOf(item);
		}

		public void Insert(int index, T item, int weight)
		{
			_list.Insert(index, item);
			_weights.Insert(index, FixWeight(weight));
			Recalculate();
		}

		public void Remove(T item)
		{
			int index = IndexOf(item);
			RemoveAt(index);
			Recalculate();
		}

		public void RemoveAt(int index)
		{
			_list.RemoveAt(index);
			_weights.RemoveAt(index);
			Recalculate();
		}

		public void SetWeight(T item, int newWeight)
		{
			SetWeightAtIndex(IndexOf(item), FixWeight(newWeight));
		}

		public int GetWeightOf(T item)
		{
			return GetWeightAtIndex(IndexOf(item));
		}

		public void SetWeightAtIndex(int index, int newWeight)
		{
			_weights[index] = FixWeight(newWeight);
			Recalculate();
		}

		public int GetWeightAtIndex(int index)
		{
			return _weights[index];
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("WeightedList<");
			stringBuilder.Append(typeof(T).Name);
			stringBuilder.Append(">: TotalWeight:");
			stringBuilder.Append(TotalWeight);
			stringBuilder.Append(", Min:");
			stringBuilder.Append(_minWeight);
			stringBuilder.Append(", Max:");
			stringBuilder.Append(_maxWeight);
			stringBuilder.Append(", Count:");
			stringBuilder.Append(Count);
			stringBuilder.Append(", {");
			for (int i = 0; i < _list.Count; i++)
			{
				stringBuilder.Append(_list[i].ToString());
				stringBuilder.Append(":");
				stringBuilder.Append(_weights[i].ToString());
				if (i < _list.Count - 1)
				{
					stringBuilder.Append(", ");
				}
			}
			stringBuilder.Append("}");
			return stringBuilder.ToString();
		}

		private void Recalculate()
		{
			_totalWeight = 0;
			_areAllProbabilitiesIdentical = false;
			_minWeight = 0;
			_maxWeight = 0;
			bool flag = true;
			_alias.Clear();
			_probabilities.Clear();
			List<int> list = new List<int>(Count);
			List<int> list2 = new List<int>(Count);
			List<int> list3 = new List<int>(Count);
			foreach (int weight in _weights)
			{
				if (flag)
				{
					_minWeight = (_maxWeight = weight);
					flag = false;
				}
				_minWeight = ((weight < _minWeight) ? weight : _minWeight);
				_maxWeight = ((_maxWeight < weight) ? weight : _maxWeight);
				_totalWeight += weight;
				list.Add(weight * Count);
				_alias.Add(0);
				_probabilities.Add(0);
			}
			if (_minWeight == _maxWeight)
			{
				_areAllProbabilitiesIdentical = true;
				return;
			}
			for (int i = 0; i < Count; i++)
			{
				if (list[i] < _totalWeight)
				{
					list2.Add(i);
				}
				else
				{
					list3.Add(i);
				}
			}
			while (list2.Count > 0 && list3.Count > 0)
			{
				int index = list2[list2.Count - 1];
				list2.RemoveAt(list2.Count - 1);
				int num = list3[list3.Count - 1];
				list3.RemoveAt(list3.Count - 1);
				_probabilities[index] = list[index];
				_alias[index] = num;
				int num3 = (list[num] = list[num] + list[index] - _totalWeight);
				if (num3 < _totalWeight)
				{
					list2.Add(num);
				}
				else
				{
					list3.Add(num);
				}
			}
			while (list3.Count > 0)
			{
				int index2 = list3[list3.Count - 1];
				list3.RemoveAt(list3.Count - 1);
				_probabilities[index2] = _totalWeight;
			}
		}

		internal static int FixWeightSetToOne(int weight)
		{
			return (weight <= 0) ? 1 : weight;
		}

		internal static int FixWeightExceptionOnAdd(int weight)
		{
			if (weight > 0)
			{
				return weight;
			}
			throw new ArgumentException("Weight cannot be non-positive");
		}

		private int FixWeight(int weight)
		{
			return (BadWeightErrorHandling == WeightErrorHandlingType.ThrowExceptionOnAdd) ? FixWeightExceptionOnAdd(weight) : FixWeightSetToOne(weight);
		}
	}
	public readonly struct WeightedListItem<T>
	{
		internal readonly T _item;

		internal readonly int _weight;

		public WeightedListItem(T item, int weight)
		{
			_item = item;
			_weight = weight;
		}
	}
	public enum WeightErrorHandlingType
	{
		SetWeightToOne,
		ThrowExceptionOnAdd
	}
}
namespace System.Runtime.CompilerServices
{
	public class ExtensionAttribute : Attribute
	{
	}
}
namespace ShoppingList
{
	[BepInPlugin("yasenfire.shoppinglist", "ShoppingList", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(CustomerController), "SetupShoppingList")]
		private class SetupShoppingListPatch
		{
			private static bool Prefix(CustomerController __instance)
			{
				__instance.shoppingList.Clear();
				List<ProductSO> list = GameManager.Instance.itemDatabase.Where((ItemSO x) => x is ProductSO).Cast<ProductSO>().ToList();
				List<WeightedListItem<ProductSO>> list2 = new List<WeightedListItem<ProductSO>>();
				SeasonSO currentSeason = GameManager.Instance.GetCurrentSeason();
				EventSO currentEvent = GameManager.Instance.GetCurrentEvent();
				foreach (ProductSO item2 in list)
				{
					float num = 100f;
					num = ((!((Object)(object)currentSeason == (Object)(object)item2.season)) ? (num * 0.9f) : (num * 1.2f));
					float num2 = GameManager.Instance.GetSellingPriceServer(item2);
					float num3 = GameManager.Instance.GetRecommendedPrice(item2);
					float num4 = num3 / num2;
					num = ((!(num4 > 1f)) ? (num * Mathf.Lerp(0.1f, 1f, (Mathf.Clamp(num4, 0.8f, 1f) - 0.8f) * 10f)) : (num * Mathf.Lerp(1f, 8f, Mathf.Clamp(num4, 1f, 2f) - 1f)));
					num *= Random.Range(0.8f, 1.2f);
					if (currentEvent != null)
					{
						if (currentEvent.forbiddenProducts.Contains(item2))
						{
							num *= 0.1f;
						}
						if (currentEvent.products.Contains(item2))
						{
							num *= Random.Range(2f, 4f);
						}
					}
					list2.Add(new WeightedListItem<ProductSO>(item2, Mathf.RoundToInt(num)));
				}
				WeightedList<ProductSO> weightedList = new WeightedList<ProductSO>(list2);
				List<ProductSO> list3 = (from x in LinqUtility.DistinctBy<Item, long>(from x in Object.FindObjectsOfType<Item>()
						where x.itemSO is ProductSO && x.onStand.Value && x.amount.Value > 0
						select x, (Func<Item, long>)((Item x) => x.itemSO.id))
					select x.itemSO).Cast<ProductSO>().ToList();
				float num5 = (float)list3.Count / (float)list.Count;
				string text = weightedBuyerList.Next();
				if (text == "obsessive")
				{
					ProductSO val = weightedList.Next();
					int num6 = Random.Range(4, Mathf.Min(((ItemSO)val).amount, 24));
					for (int i = 0; i < num6; i++)
					{
						__instance.shoppingList.Add(val);
					}
					return false;
				}
				if (text == "loyal")
				{
					int num7 = Mathf.RoundToInt(Mathf.Lerp(0f, 18f, num5)) + 6;
					int num8 = Random.Range(1, num7);
					for (int j = 0; j < num8; j++)
					{
						ProductSO item;
						do
						{
							item = weightedList.Next();
						}
						while (!list3.Contains(item));
						__instance.shoppingList.Add(item);
					}
					return false;
				}
				int num9 = Random.Range(1, 24);
				int num10 = 0;
				List<ProductSO> list4 = new List<ProductSO>();
				for (int k = 0; k < num9; k++)
				{
					ProductSO val2 = weightedList.Next();
					list4.Add(val2);
					int num11 = 1;
					for (; k < num9; k++)
					{
						if (!(Random.Range(0f, 1f) < (float)(((ItemSO)val2).amount / 100 / num11)))
						{
							break;
						}
						list4.Add(val2);
						num11++;
					}
					if (list3.Contains(val2))
					{
						num10 += num11;
					}
				}
				if ((float)(num10 / num9) >= 0.5f)
				{
					for (int l = 0; l < list4.Count; l++)
					{
						if (list3.Contains(list4[l]))
						{
							__instance.shoppingList.Add(list4[l]);
						}
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Checkout), "SpawnProducts")]
		private class CheckoutSpawnProductsPatch
		{
			private static bool Prefix(Checkout __instance)
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_010a: Expected O, but got Unknown
				//IL_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0162: Unknown result type (might be due to invalid IL or missing references)
				//IL_0167: Unknown result type (might be due to invalid IL or missing references)
				//IL_016b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0170: Unknown result type (might be due to invalid IL or missing references)
				//IL_0174: Unknown result type (might be due to invalid IL or missing references)
				//IL_018d: Unknown result type (might be due to invalid IL or missing references)
				//IL_019d: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0271: Unknown result type (might be due to invalid IL or missing references)
				//IL_02af: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
				if (__instance.spawnedProducts)
				{
					return false;
				}
				object value = Traverse.Create((object)__instance).Field("checkoutEmployee").GetValue();
				CheckoutEmployee val = (CheckoutEmployee)((value is CheckoutEmployee) ? value : null);
				List<CustomerController> list = Traverse.Create((object)__instance).Field("customers").GetValue() as List<CustomerController>;
				Transform child = __instance.productSlots.GetChild(0);
				Transform child2 = __instance.productSlots.GetChild(8);
				float num = Mathf.Abs(child2.localPosition.x * 1000f - child.localPosition.x * 1000f);
				float num2 = Mathf.Abs(child2.localPosition.z * 1000f - child.localPosition.z * 1000f) * 2f;
				List<ProductSO> shoppingCart = list[0].shoppingCart;
				shoppingCart.Sort((ProductSO x, ProductSO y) => ((ItemSO)x).id.CompareTo(((ItemSO)y).id));
				Packer val2 = new Packer(Mathf.RoundToInt(num), Mathf.RoundToInt(num2));
				for (int i = 0; i < shoppingCart.Count; i++)
				{
					Transform child3 = __instance.productSlots.GetChild(0);
					ProductSO val3 = shoppingCart[i];
					GameObject item = Object.Instantiate<GameObject>(GameManager.Instance.checkoutItem, child3.position, child3.rotation);
					Mesh sharedMesh = val3.pickupPrefab.GetComponentsInChildren<MeshFilter>()[0].sharedMesh;
					Bounds bounds = sharedMesh.bounds;
					Vector3 size = ((Bounds)(ref bounds)).size;
					val2.PackRect(Mathf.RoundToInt(size.z * 1000f * val3.pickupPrefab.transform.localScale.z), Mathf.RoundToInt(size.x * 1000f * val3.pickupPrefab.transform.localScale.x), (object)(item, ((ItemSO)val3).id));
				}
				foreach (PackerRectangle packRectangle in val2.PackRectangles)
				{
					(GameObject, long) obj = ((GameObject, long))packRectangle.Data;
					GameObject item2 = obj.Item1;
					long item3 = obj.Item2;
					NetworkObject component = item2.GetComponent<NetworkObject>();
					component.Spawn(false);
					((Component)component).GetComponent<CheckoutItem>().ServerSetupItem(item3, __instance);
					component.TrySetParent(((Component)__instance).gameObject.transform, true);
					Transform transform = item2.transform;
					transform.localPosition += new Vector3((float)packRectangle.Rectangle.Y / 1000f, 0f, (float)packRectangle.Rectangle.X / 1000f * -1f);
				}
				__instance.spawnedProducts = true;
				if ((Object)(object)val != (Object)null)
				{
					val.Work();
				}
				return false;
			}
		}

		internal static ManualLogSource Logger;

		private Harmony m_harmony = new Harmony("yasenfire.shoppinglist");

		public static WeightedList<string> weightedBuyerList;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin ShoppingList is loaded!");
			m_harmony.PatchAll();
			List<WeightedListItem<string>> listItems = new List<WeightedListItem<string>>
			{
				new WeightedListItem<string>("obsessive", 1),
				new WeightedListItem<string>("loyal", 20),
				new WeightedListItem<string>("standard", 79)
			};
			weightedBuyerList = new WeightedList<string>(listItems);
		}
	}
}

BepInEx/plugins/StbRectPackSharp.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("StbRectPackSharpTeam")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("C# port of the stb_rect_pack.h")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.00.4")]
[assembly: AssemblyProduct("StbRectPackSharp")]
[assembly: AssemblyTitle("StbRectPackSharp")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
namespace StbRectPackSharp;

internal static class CRuntime
{
	public unsafe delegate int QSortComparer(void* a, void* b);

	public unsafe static void* malloc(ulong size)
	{
		return malloc((long)size);
	}

	public unsafe static void* malloc(long size)
	{
		return Marshal.AllocHGlobal((int)size).ToPointer();
	}

	public unsafe static void free(void* a)
	{
		Marshal.FreeHGlobal(new IntPtr(a));
	}

	private unsafe static void qsortSwap(byte* data, long size, long pos1, long pos2)
	{
		byte* ptr = data + size * pos1;
		byte* ptr2 = data + size * pos2;
		for (long num = 0L; num < size; num++)
		{
			byte b = *ptr;
			*ptr = *ptr2;
			*ptr2 = b;
			ptr++;
			ptr2++;
		}
	}

	private unsafe static long qsortPartition(byte* data, long size, QSortComparer comparer, long left, long right)
	{
		void* b = data + size * left;
		long num = left - 1;
		long num2 = right + 1;
		while (true)
		{
			num++;
			if (comparer(data + size * num, b) >= 0)
			{
				do
				{
					num2--;
				}
				while (comparer(data + size * num2, b) > 0);
				if (num >= num2)
				{
					break;
				}
				qsortSwap(data, size, num, num2);
			}
		}
		return num2;
	}

	private unsafe static void qsortInternal(byte* data, long size, QSortComparer comparer, long left, long right)
	{
		if (left < right)
		{
			long num = qsortPartition(data, size, comparer, left, right);
			qsortInternal(data, size, comparer, left, num);
			qsortInternal(data, size, comparer, num + 1, right);
		}
	}

	public unsafe static void qsort(void* data, ulong count, ulong size, QSortComparer comparer)
	{
		qsortInternal((byte*)data, (long)size, comparer, 0L, (long)(count - 1));
	}
}
public class PackerRectangle
{
	public Rectangle Rectangle { get; private set; }

	public int X => Rectangle.X;

	public int Y => Rectangle.Y;

	public int Width => Rectangle.Width;

	public int Height => Rectangle.Height;

	public object Data { get; private set; }

	public PackerRectangle(Rectangle rect, object data)
	{
		Rectangle = rect;
		Data = data;
	}
}
public class Packer : IDisposable
{
	private StbRectPack.stbrp_context _context;

	private List<PackerRectangle> _rectangles = new List<PackerRectangle>();

	public int Width => _context.width;

	public int Height => _context.height;

	public List<PackerRectangle> PackRectangles => _rectangles;

	public Packer(int initialWidth = 256, int initialHeight = 256)
	{
		InitContext(initialWidth, initialHeight);
	}

	public void Dispose()
	{
		_context.Dispose();
	}

	private unsafe void InitContext(int width, int height)
	{
		if (width <= 0)
		{
			throw new ArgumentOutOfRangeException("width");
		}
		if (height <= 0)
		{
			throw new ArgumentOutOfRangeException("height");
		}
		_context.Dispose();
		StbRectPack.stbrp_context context = new StbRectPack.stbrp_context(width);
		StbRectPack.stbrp_init_target(&context, width, height, context.all_nodes, width);
		_context = context;
		_rectangles = new List<PackerRectangle>();
	}

	public unsafe PackerRectangle PackRect(int width, int height, object userData)
	{
		StbRectPack.stbrp_rect stbrp_rect = default(StbRectPack.stbrp_rect);
		stbrp_rect.id = _rectangles.Count;
		stbrp_rect.w = width;
		stbrp_rect.h = height;
		StbRectPack.stbrp_rect stbrp_rect2 = stbrp_rect;
		int num;
		fixed (StbRectPack.stbrp_context* context = &_context)
		{
			num = StbRectPack.stbrp_pack_rects(context, &stbrp_rect2, 1);
		}
		if (num == 0)
		{
			return null;
		}
		PackerRectangle packerRectangle = new PackerRectangle(new Rectangle(stbrp_rect2.x, stbrp_rect2.y, stbrp_rect2.w, stbrp_rect2.h), userData);
		_rectangles.Add(packerRectangle);
		return packerRectangle;
	}
}
public static class StbRectPack
{
	public struct stbrp_context : IDisposable
	{
		public int width;

		public int height;

		public int align;

		public int init_mode;

		public int heuristic;

		public int num_nodes;

		public unsafe stbrp_node* active_head;

		public unsafe stbrp_node* free_head;

		public unsafe stbrp_node* extra;

		public unsafe stbrp_node* all_nodes;

		public unsafe stbrp_context(int nodesCount)
		{
			if (nodesCount <= 0)
			{
				throw new ArgumentOutOfRangeException("nodesCount");
			}
			width = (height = (align = (init_mode = (heuristic = (num_nodes = 0)))));
			active_head = (free_head = null);
			all_nodes = (stbrp_node*)CRuntime.malloc(sizeof(stbrp_node) * nodesCount);
			extra = (stbrp_node*)CRuntime.malloc(sizeof(stbrp_node) * 2);
		}

		public unsafe void Dispose()
		{
			if (all_nodes != null)
			{
				CRuntime.free(all_nodes);
				all_nodes = null;
			}
			if (extra != null)
			{
				CRuntime.free(extra);
				extra = null;
			}
		}
	}

	public struct stbrp_rect
	{
		public int id;

		public int w;

		public int h;

		public int x;

		public int y;

		public int was_packed;
	}

	public struct stbrp_node
	{
		public int x;

		public int y;

		public unsafe stbrp_node* next;
	}

	public struct stbrp__findresult
	{
		public int x;

		public int y;

		public unsafe stbrp_node** prev_link;
	}

	public const int STBRP_HEURISTIC_Skyline_default = 0;

	public const int STBRP_HEURISTIC_Skyline_BL_sortHeight = 0;

	public const int STBRP_HEURISTIC_Skyline_BF_sortHeight = 2;

	public const int STBRP__INIT_skyline = 1;

	public unsafe static void stbrp_setup_heuristic(stbrp_context* context, int heuristic)
	{
		if (context->init_mode == 1)
		{
			context->heuristic = heuristic;
			return;
		}
		throw new Exception("Mode " + context->init_mode + " is not supported.");
	}

	public unsafe static void stbrp_setup_allow_out_of_mem(stbrp_context* context, int allow_out_of_mem)
	{
		if (allow_out_of_mem != 0)
		{
			context->align = 1;
		}
		else
		{
			context->align = (context->width + context->num_nodes - 1) / context->num_nodes;
		}
	}

	public unsafe static void stbrp_init_target(stbrp_context* context, int width, int height, stbrp_node* nodes, int num_nodes)
	{
		int num = 0;
		for (num = 0; num < num_nodes - 1; num++)
		{
			nodes[num].next = nodes + (num + 1);
		}
		nodes[num].next = null;
		context->init_mode = 1;
		context->heuristic = 0;
		context->free_head = nodes;
		context->active_head = context->extra;
		context->width = width;
		context->height = height;
		context->num_nodes = num_nodes;
		stbrp_setup_allow_out_of_mem(context, 0);
		context->extra->x = 0;
		context->extra->y = 0;
		context->extra->next = context->extra + 1;
		context->extra[1].x = width;
		context->extra[1].y = 65535;
		context->extra[1].next = null;
	}

	public unsafe static int stbrp__skyline_find_min_y(stbrp_context* c, stbrp_node* first, int x0, int width, int* pwaste)
	{
		stbrp_node* ptr = first;
		int num = x0 + width;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		num2 = 0;
		num4 = 0;
		num3 = 0;
		while (ptr->x < num)
		{
			if (ptr->y > num2)
			{
				num4 += num3 * (ptr->y - num2);
				num2 = ptr->y;
				num3 = ((ptr->x >= x0) ? (num3 + (ptr->next->x - ptr->x)) : (num3 + (ptr->next->x - x0)));
			}
			else
			{
				int num5 = ptr->next->x - ptr->x;
				if (num5 + num3 > width)
				{
					num5 = width - num3;
				}
				num4 += num5 * (num2 - ptr->y);
				num3 += num5;
			}
			ptr = ptr->next;
		}
		*pwaste = num4;
		return num2;
	}

	public unsafe static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context* c, int width, int height)
	{
		int num = 1073741824;
		int num2 = 0;
		int num3 = 1073741824;
		stbrp__findresult result = default(stbrp__findresult);
		stbrp_node** ptr = null;
		width = width + c->align - 1;
		width -= width % c->align;
		if (width > c->width || height > c->height)
		{
			result.prev_link = null;
			result.x = (result.y = 0);
			return result;
		}
		stbrp_node* ptr2 = c->active_head;
		stbrp_node** ptr3 = &c->active_head;
		while (ptr2->x + width <= c->width)
		{
			int num4 = 0;
			int num5 = 0;
			num4 = stbrp__skyline_find_min_y(c, ptr2, ptr2->x, width, &num5);
			if (c->heuristic == 0)
			{
				if (num4 < num3)
				{
					num3 = num4;
					ptr = ptr3;
				}
			}
			else if (num4 + height <= c->height && (num4 < num3 || (num4 == num3 && num5 < num)))
			{
				num3 = num4;
				num = num5;
				ptr = ptr3;
			}
			ptr3 = &ptr2->next;
			ptr2 = ptr2->next;
		}
		num2 = ((ptr != null) ? (*ptr)->x : 0);
		if (c->heuristic == 2)
		{
			stbrp_node* ptr4 = c->active_head;
			ptr2 = c->active_head;
			ptr3 = &c->active_head;
			while (ptr4->x < width)
			{
				ptr4 = ptr4->next;
			}
			while (ptr4 != null)
			{
				int num6 = ptr4->x - width;
				int num7 = 0;
				int num8 = 0;
				while (ptr2->next->x <= num6)
				{
					ptr3 = &ptr2->next;
					ptr2 = ptr2->next;
				}
				num7 = stbrp__skyline_find_min_y(c, ptr2, num6, width, &num8);
				if (num7 + height <= c->height && num7 <= num3 && (num7 < num3 || num8 < num || (num8 == num && num6 < num2)))
				{
					num2 = num6;
					num3 = num7;
					num = num8;
					ptr = ptr3;
				}
				ptr4 = ptr4->next;
			}
		}
		result.prev_link = ptr;
		result.x = num2;
		result.y = num3;
		return result;
	}

	public unsafe static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context* context, int width, int height)
	{
		stbrp__findresult result = stbrp__skyline_find_best_pos(context, width, height);
		if (result.prev_link == null || result.y + height > context->height || context->free_head == null)
		{
			result.prev_link = null;
			return result;
		}
		stbrp_node* free_head = context->free_head;
		free_head->x = result.x;
		free_head->y = result.y + height;
		context->free_head = free_head->next;
		stbrp_node* ptr = *result.prev_link;
		if (ptr->x < result.x)
		{
			stbrp_node* next = ptr->next;
			ptr->next = free_head;
			ptr = next;
		}
		else
		{
			*result.prev_link = free_head;
		}
		while (ptr->next != null && ptr->next->x <= result.x + width)
		{
			stbrp_node* next2 = ptr->next;
			ptr->next = context->free_head;
			context->free_head = ptr;
			ptr = next2;
		}
		free_head->next = ptr;
		if (ptr->x < result.x + width)
		{
			ptr->x = result.x + width;
		}
		return result;
	}

	public unsafe static int rect_height_compare(void* a, void* b)
	{
		if (((stbrp_rect*)a)->h > ((stbrp_rect*)b)->h)
		{
			return -1;
		}
		if (((stbrp_rect*)a)->h < ((stbrp_rect*)b)->h)
		{
			return 1;
		}
		if (((stbrp_rect*)a)->w <= ((stbrp_rect*)b)->w)
		{
			if (((stbrp_rect*)a)->w >= ((stbrp_rect*)b)->w)
			{
				return 0;
			}
			return 1;
		}
		return -1;
	}

	public unsafe static int rect_original_order(void* a, void* b)
	{
		if (((stbrp_rect*)a)->was_packed >= ((stbrp_rect*)b)->was_packed)
		{
			if (((stbrp_rect*)a)->was_packed <= ((stbrp_rect*)b)->was_packed)
			{
				return 0;
			}
			return 1;
		}
		return -1;
	}

	public unsafe static int stbrp_pack_rects(stbrp_context* context, stbrp_rect* rects, int num_rects)
	{
		int num = 0;
		int result = 1;
		for (num = 0; num < num_rects; num++)
		{
			rects[num].was_packed = num;
		}
		CRuntime.qsort(rects, (ulong)num_rects, (ulong)sizeof(stbrp_rect), rect_height_compare);
		for (num = 0; num < num_rects; num++)
		{
			if (rects[num].w == 0 || rects[num].h == 0)
			{
				rects[num].x = (rects[num].y = 0);
				continue;
			}
			stbrp__findresult stbrp__findresult = stbrp__skyline_pack_rectangle(context, rects[num].w, rects[num].h);
			if (stbrp__findresult.prev_link != null)
			{
				rects[num].x = stbrp__findresult.x;
				rects[num].y = stbrp__findresult.y;
			}
			else
			{
				rects[num].x = (rects[num].y = 65535);
			}
		}
		CRuntime.qsort(rects, (ulong)num_rects, (ulong)sizeof(stbrp_rect), rect_original_order);
		for (num = 0; num < num_rects; num++)
		{
			rects[num].was_packed = ((rects[num].x != 65535 || rects[num].y != 65535) ? 1 : 0);
			if (rects[num].was_packed == 0)
			{
				result = 0;
			}
		}
		return result;
	}
}