2020-12-18 12:12:45 +01:00
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
using UnityEditor ;
2021-01-19 10:46:07 +01:00
2020-12-18 12:12:45 +01:00
//Define the system managing the clients. (Singleton)
2021-01-17 17:56:17 +01:00
//TODO: Switch to a registering approach for clients
2020-12-18 12:12:45 +01:00
public sealed class ClientManager : MonoBehaviour
{
2021-01-19 10:46:07 +01:00
public static string ClientManager_path = "/GameSystem/ClientManager" ;
2021-01-13 15:05:09 +01:00
//Singleton
private static ClientManager _instance = null ;
public static ClientManager Instance { get
{
2021-01-19 10:46:07 +01:00
if ( _instance is null ) //Force Awakening if needed
GameObject . Find ( ClientManager_path ) . GetComponent < ClientManager > ( ) . Awake ( ) ;
2021-01-13 15:05:09 +01:00
return _instance ;
}
}
2021-01-13 13:32:24 +01:00
[HideInInspector]
public bool ready = false ; //Wether the ClientManager is initialized
2021-01-13 15:05:09 +01:00
[SerializeField]
int nbMaxClients = 1 ; //Maximum active clients
[SerializeField]
2021-01-17 13:39:56 +01:00
float clientSpawnChance = 100.0f ; //Chance of new client every request
2021-01-13 15:05:09 +01:00
[SerializeField]
2021-01-17 13:39:56 +01:00
float clientFrequency = 1.0f ; //Time (s) between clientRequest
// [SerializeField]
// float clientSpawnTimer = 0.5f; //Intial time before first spawn (pseudo-random after that)
// [SerializeField]
// float maxTimeNewClients = 2.0f; //Longest waiting time for new clients
// bool clientSpawnReady = false;
2020-12-18 12:12:45 +01:00
2021-01-17 10:57:00 +01:00
[SerializeField]
2020-12-18 12:12:45 +01:00
string ClientRessourceFolder = "Clients" ;
2021-01-22 17:34:44 +01:00
private Object [ ] clientsPrefab ;
2020-12-31 16:24:44 +01:00
GameObject ClientContainer = null ;
2021-01-22 17:34:44 +01:00
private List < GameObject > _clientList = new List < GameObject > ( ) ;
public List < GameObject > clientList
{
get { return _clientList ; }
private set { _clientList = value ; }
}
2020-12-18 12:12:45 +01:00
2020-12-31 12:53:02 +01:00
Vector2 spawnPoint ;
Dictionary < Vector2 , bool > targets_dict ; //Dict with target and wether they're taken by a client
2020-12-30 20:09:20 +01:00
2021-01-17 17:56:17 +01:00
private List < IEnumerator > coroutines = new List < IEnumerator > ( ) ; //List of ClientManager coroutines
2020-12-18 12:12:45 +01:00
//Request new client
//Return wether a new client was created
2021-01-17 13:39:56 +01:00
public bool clientRequest ( float SpawnChance = 100.0f )
2020-12-18 12:12:45 +01:00
{
2021-01-22 17:34:44 +01:00
if ( Random . Range ( 0.0f , 99.9f ) < SpawnChance & & clientList . Count < nbMaxClients & & targets_dict . ContainsValue ( false ) )
2020-12-18 12:12:45 +01:00
{
2021-01-22 17:34:44 +01:00
int prefabChoice = Random . Range ( 0 , clientsPrefab . Length ) ;
GameObject newClient = Instantiate ( ( GameObject ) clientsPrefab [ prefabChoice ] , spawnPoint , Quaternion . identity , ClientContainer . transform ) ; //Instantiate new client inside ClientManager
2020-12-31 16:24:44 +01:00
// Debug.Log(newClient.GetInstanceID());
2021-01-22 17:34:44 +01:00
newClient . name = newClient . name . Split ( '(' ) [ 0 ] + newClient . GetInstanceID ( ) ; //Rename new client
clientList . Add ( newClient ) ; //Save client ref
2020-12-31 16:24:44 +01:00
2021-01-17 13:39:56 +01:00
// clientSpawnTimer=Random.Range(1.0f, maxTimeNewClients); //Need more random ?
// clientSpawnReady=false;
2020-12-18 12:12:45 +01:00
2020-12-31 16:24:44 +01:00
// Debug.Log("Spawning "+clientPrefab.name+" at "+spawnPosition);
2020-12-18 12:12:45 +01:00
return true ; //New client instantiated
}
return false ; //No new client
}
2021-01-07 14:45:19 +01:00
//TODO: Reputation
public void clientReward ( int money )
{
2021-01-12 16:55:43 +01:00
GameSystem . Instance . Gold + = money ;
2021-01-07 14:45:19 +01:00
}
2020-12-31 16:24:44 +01:00
//Destroy a client
public void clientLeave ( GameObject client )
{
2021-01-22 17:34:44 +01:00
clientList . Remove ( client ) ;
2020-12-31 16:24:44 +01:00
// Debug.Log(client.name+" destroyed"+clientIDs.Count);
2021-01-13 13:32:24 +01:00
//Prevent immediate spawn of a new client after one leaving
2021-01-17 13:39:56 +01:00
// if(clientSpawnReady)
// {
// clientSpawnReady=false;
// clientSpawnTimer+=0.5f;
// }
2020-12-31 16:24:44 +01:00
}
2021-01-12 10:20:30 +01:00
//Return a random available target. Or the Exit if Exit=True.
//prevTarget : Previous target of the client which will be available for other clients.
public Vector2 assignTarget ( Vector2 ? prevTarget = null , bool exit = false )
2020-12-30 20:09:20 +01:00
{
2020-12-31 12:53:02 +01:00
if ( prevTarget ! = null )
{
targets_dict [ ( Vector2 ) prevTarget ] = false ; //Free prevTarget
2021-01-12 10:20:30 +01:00
}
if ( exit ) //Assign Exit target
2020-12-31 12:53:02 +01:00
return spawnPoint ;
2021-01-12 10:20:30 +01:00
else
{
List < Vector2 > avail_tgt = new List < Vector2 > ( ) ;
foreach ( KeyValuePair < Vector2 , bool > tgt in targets_dict )
if ( tgt . Value is false )
avail_tgt . Add ( tgt . Key ) ;
Vector2 target = avail_tgt [ Random . Range ( 0 , avail_tgt . Count ) ] ;
targets_dict [ target ] = true ;
return target ;
2020-12-31 12:53:02 +01:00
}
2021-01-12 10:20:30 +01:00
}
//Return a random order from available consummable
2021-01-12 16:55:43 +01:00
//TODO : Check stock before assignement ?
2021-01-12 10:20:30 +01:00
public string assignOrder ( )
{
2021-01-12 16:55:43 +01:00
List < string > available_types = new List < string > ( Consumable . allowed_types ) ;
2021-01-12 10:41:48 +01:00
string order_type = available_types [ Random . Range ( 0 , available_types . Count ) ] ;
return order_type ;
2020-12-30 20:09:20 +01:00
}
2021-01-17 17:56:17 +01:00
//InvokeRepeating() is another option
//Coroutine to be started in a parallel process. It'll repeatidly request new client.
private IEnumerator requestCoroutine ( )
{
while ( ClientManager . Instance ! = null ) {
if ( GameSystem . Instance . serviceOpen )
ClientManager . Instance . clientRequest ( clientSpawnChance ) ;
yield return new WaitForSeconds ( clientFrequency ) ;
}
}
2021-01-12 16:55:43 +01:00
//Awake is called when the script instance is being loaded.
void Awake ( )
2020-12-18 12:12:45 +01:00
{
2021-01-13 15:05:09 +01:00
//Singleton
if ( _instance ! = null & & _instance ! = this )
Destroy ( this . gameObject ) ;
else
_instance = this ;
2021-01-13 13:32:24 +01:00
if ( ! ready )
{
2021-01-19 10:46:07 +01:00
ClientContainer = GameObject . Find ( ClientManager_path ) ;
2021-01-13 13:32:24 +01:00
if ( ClientContainer is null )
throw new System . Exception ( "No ClientManager found under GameSystem" ) ;
2020-12-31 16:24:44 +01:00
2021-01-13 13:32:24 +01:00
// Load clients prefabs //
2020-12-30 20:09:20 +01:00
2021-01-13 13:32:24 +01:00
// Find all assets labelled with 'usable' :
// string[] guids = AssetDatabase.FindAssets("", new string[] {"Assets/Prefabs/Characters/Clients"});
2020-12-18 12:12:45 +01:00
2021-01-13 13:32:24 +01:00
// foreach (string guid in guids)
// {
// Debug.Log(AssetDatabase.GUIDToAssetPath(guid));
// Instantiate(guid, spawnPosition, Quaternion.identity);
// }
2020-12-18 12:12:45 +01:00
2021-01-22 17:34:44 +01:00
clientsPrefab = Resources . LoadAll ( ClientRessourceFolder ) ;
2020-12-18 12:12:45 +01:00
2021-01-13 13:32:24 +01:00
// foreach (var c in clients)
// {
// Debug.Log(gameObject.name+" : "+c.name + " loaded");
// }
2021-01-22 17:34:44 +01:00
if ( clientsPrefab . Length < nbMaxClients )
2021-01-13 13:32:24 +01:00
{
2021-01-22 17:34:44 +01:00
Debug . LogWarning ( "ClientManager doesn't have enough client prefab to manage unique MaxClients : " + clientsPrefab . Length + "/" + nbMaxClients ) ;
2021-01-13 13:32:24 +01:00
}
2020-12-30 20:09:20 +01:00
2021-01-13 13:32:24 +01:00
// Load Client spawn point //
GameObject spawnObj = GameObject . Find ( "/GameSystem/ClientSpawn" ) ;
if ( spawnObj is null )
throw new System . Exception ( "No ClientSpawn GameObject found under GameSystem" ) ;
spawnPoint = spawnObj . transform . position ;
2020-12-30 20:09:20 +01:00
2021-01-13 13:32:24 +01:00
// Load Client targets //
targets_dict = new Dictionary < Vector2 , bool > ( ) ;
GameObject targetsObj = GameObject . Find ( "/GameSystem/Targets" ) ;
if ( targetsObj is null )
throw new System . Exception ( "No Targets GameObject found under GameSystem" ) ;
2020-12-30 20:09:20 +01:00
2021-01-13 13:32:24 +01:00
Component [ ] targets = targetsObj . GetComponentsInChildren < Transform > ( ) ;
if ( targets ! = null )
2020-12-30 20:09:20 +01:00
{
2021-01-13 13:32:24 +01:00
foreach ( Transform target in targets )
2020-12-30 20:09:20 +01:00
{
2021-01-13 13:32:24 +01:00
if ( target . gameObject . name ! = "Targets" )
{
targets_dict . Add ( target . position , false ) ;
// Debug.Log("Client target : "+ target.gameObject.name + target.position);
}
2020-12-30 20:09:20 +01:00
}
}
2021-01-13 13:32:24 +01:00
if ( targets_dict . Count < nbMaxClients )
{
Debug . LogWarning ( "ClientManager doesn't have enough target to manage MaxClients : " + targets_dict . Count + "/" + nbMaxClients ) ;
}
ready = true ;
2020-12-31 16:24:44 +01:00
}
2020-12-18 12:12:45 +01:00
}
2021-01-17 13:39:56 +01:00
void Start ( )
{
2021-01-17 17:56:17 +01:00
//Start coroutines in parallel
coroutines . Add ( requestCoroutine ( ) ) ;
foreach ( IEnumerator c in coroutines )
StartCoroutine ( c ) ;
2021-01-17 13:39:56 +01:00
}
2020-12-18 12:12:45 +01:00
// Update is called once per frame
void Update ( )
{
2021-01-17 13:39:56 +01:00
// if(!clientSpawnReady)
// {
// clientSpawnTimer-= Time.deltaTime;
// if(clientSpawnTimer<=0)
// clientSpawnReady=true;
// }
2020-12-31 16:24:44 +01:00
// Debug.Log("Client Spawn : "+clientSpawnTimer+" / Seat available: "+targets_dict.ContainsValue(false));
2020-12-18 12:12:45 +01:00
}
2021-01-17 17:56:17 +01:00
void OnDisable ( )
{
StopAllCoroutines ( ) ;
}
void OnDestroy ( )
{
StopAllCoroutines ( ) ;
}
2020-12-18 12:12:45 +01:00
//// Singleton Implementation (https://jlambert.developpez.com/tutoriels/dotnet/implementation-pattern-singleton-csharp/#LIII) ////
2021-01-13 15:05:09 +01:00
// private ClientManager()
// {
// }
2020-12-18 12:12:45 +01:00
2021-01-13 15:05:09 +01:00
// public static ClientManager Instance { get { return Nested.instance; } }
2020-12-18 12:12:45 +01:00
2021-01-13 15:05:09 +01:00
// private class Nested
// {
// // Explicit static constructor to tell C# compiler
// // not to mark type as beforefieldinit
// static Nested()
// {
// }
// internal static readonly ClientManager instance = new GameObject("ClientManager").AddComponent<ClientManager>();
// }
2020-12-18 12:12:45 +01:00
////
}