using System.Collections.Generic;
using System;
using UnityEngine;
using Cyber.Networking.Serverside;
using Cyber.Entities.SyncBases;
using Cyber.Console;
namespace Cyber.Entities {
///
/// A database of the game's all syncable components. Syncable components are
/// the instances of the subclasses of .
///
public class SyncDB : MonoBehaviour {
private static readonly Type[] SyncableClasses = new Type[] {
typeof(Character),
typeof(Inventory),
typeof(Button),
typeof(Door),
typeof(Computer)
};
private int IDCounter = 0;
private Dictionary Database = new Dictionary();
private Dictionary> CategorizedDatabase = new Dictionary>();
private Dictionary SyncHandletypes = new Dictionary();
private List StaticSyncBaseIDList = new List();
///
/// Add an entity to the database with the given IDs.
///
/// Game object.
/// The IDs. Should be from or
/// , since the order is important.
public void AddEntity(GameObject gameObject, int[] ids) {
int Index = 0;
for (int i = 0; i < SyncableClasses.Length; i++) {
SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]);
if (Syncable != null) {
Syncable.ID = ids[Index++];
AddSyncBaseToDatabase(Syncable);
}
}
}
///
/// Clears the given gameobject's s from the Database.
///
/// The GameObject to remove.
public void RemoveEntity(GameObject gameObject) {
for (int i = 0; i < SyncableClasses.Length; i++) {
SyncBase Syncable = (SyncBase) gameObject.GetComponent(SyncableClasses[i]);
if (Syncable != null) {
Database.Remove(Syncable.ID);
if (Server.IsRunning()) {
CategorizedDatabase[Syncable.GetType()].RemoveAll(x => x == Syncable.ID);
}
}
}
}
///
/// Makes an ordered list of the given gameobject's syncable components'
/// IDs.
///
/// The IDs.
/// Game object.
/// Whether or not new IDs are created.
/// is a shorthand for this function with
/// this parameter set to true.
public int[] GetEntityIDs(GameObject gameObject, bool newIDs = false) {
List IDs = new List();
for (int i = 0; i < SyncableClasses.Length; i++) {
SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]);
if (Syncable != null) {
if (newIDs) {
Syncable.ID = CreateID();
}
IDs.Add(Syncable.ID);
}
}
int[] IDArray = new int[IDs.Count];
for (int i = 0; i < IDs.Count; i++) {
IDArray[i] = IDs[i];
}
return IDArray;
}
///
/// Creates an ordered list of the given gameobject's syncable components'
/// IDs. See for more information.
///
/// The new IDs.
/// Game object.
public int[] GetNewEntityIDs(GameObject gameObject) {
return GetEntityIDs(gameObject, true);
}
///
/// Get a synced component by its ID.
///
/// The ID.
public SyncBase Get(int id) {
if (!Database.ContainsKey(id)) {
return null;
}
return Database[id];
}
///
/// Gives the database categorized into lists of their types.
///
/// A dictionary of categorized SyncBases.
public Dictionary> GetCategorizedDatabase() {
return CategorizedDatabase;
}
///
/// Gets the Sync Handletypes currently known by the SyncDB.
///
/// The Sync Handletypes by Type.
public Dictionary GetSyncHandletypes() {
return SyncHandletypes;
}
///
/// Creates a new ID which isn't in use yet.
///
/// A new, free ID.
public int CreateID() {
int ID;
try {
ID = IDCounter++;
} catch (OverflowException) {
ID = 0;
IDCounter = 1;
}
while (Database.ContainsKey(ID) && ID < int.MaxValue) {
ID++;
if (ID < int.MaxValue - 1)
IDCounter = ID + 1;
}
if (Database.ContainsKey(ID)) {
// Somehow we've managed to fill up the whole database.
// I can't even imagine why or how.
Debug.LogError("!!!WARNING!!! The SyncDB is full. Update the game to use longs instead of uints. !!!WARNING!!!");
}
return ID;
}
///
/// Sets static objects for all objects in the world. This method should be called once per game launch ever.
///
/// The list of id's to be set. If null, will create new ids.
public void SetStaticObjectsIDs(int[] idList = null) {
SyncBase[] SyncBases = GameObject.Find("/StaticWorld").GetComponentsInChildren();
Array.Sort(SyncBases, (a, b) => {
Vector3 APos = a.gameObject.transform.position;
float AComparison = APos.x * 677 + APos.y * 881 + APos.z * 313 + Array.IndexOf(SyncableClasses, a) * 463;
Vector3 BPos = b.gameObject.transform.position;
float BComparison = BPos.x * 677 + BPos.y * 881 + BPos.z * 313 + Array.IndexOf(SyncableClasses, b) * 463;
return AComparison.CompareTo(BComparison);
});
if (idList == null) {
foreach (SyncBase SyncBase in SyncBases) {
SyncBase.ID = CreateID();
AddSyncBaseToDatabase(SyncBase);
StaticSyncBaseIDList.Add(SyncBase.ID);
}
} else {
for (int i = 0; i < Math.Min(SyncBases.Length, idList.Length); i++) {
SyncBases[i].ID = idList[i];
AddSyncBaseToDatabase(SyncBases[i]);
}
}
}
///
/// Returns the list of id's on the static objects that exist on the world by default.
///
///
public int[] GetStaticSyncBaseIDList() {
return StaticSyncBaseIDList.ToArray();
}
private void AddSyncBaseToDatabase(SyncBase syncBase) {
Database[syncBase.ID] = syncBase;
if (Server.IsRunning()) {
Type Type = syncBase.GetType();
if (!CategorizedDatabase.ContainsKey(Type)) {
CategorizedDatabase.Add(Type, new List());
SyncHandletypes.Add(Type, syncBase.GetSyncHandletype());
}
CategorizedDatabase[Type].Add(syncBase.ID);
}
}
}
}