Exemple #1
0
    /// <summary>
    /// Server-side only. Performs the spawn and syncs it to all clients.
    /// </summary>
    /// <returns></returns>
    private static SpawnResult Server(SpawnInfo info)
    {
        if (info == null)
        {
            Logger.LogError("Cannot spawn, info is null", Category.ItemSpawn);
            return(SpawnResult.Fail(info));
        }

        EnsureInit();
        Logger.LogTraceFormat("Server spawning {0}", Category.ItemSpawn, info);

        List <GameObject> spawnedObjects = new List <GameObject>();

        for (int i = 0; i < info.Count; i++)
        {
            var result = info.SpawnableToSpawn.SpawnAt(info.SpawnDestination);

            if (result.Successful)
            {
                spawnedObjects.Add(result.GameObject);
                //apply scattering if it was specified
                if (info.ScatterRadius != null)
                {
                    foreach (var spawned in spawnedObjects)
                    {
                        var cnt           = spawned.GetComponent <CustomNetTransform>();
                        var scatterRadius = info.ScatterRadius.GetValueOrDefault(0);
                        if (cnt != null)
                        {
                            cnt.SetPosition(info.SpawnDestination.WorldPosition + new Vector3(Random.Range(-scatterRadius, scatterRadius), Random.Range(-scatterRadius, scatterRadius)));
                        }
                    }
                }
            }
            else
            {
                return(SpawnResult.Fail(info));
            }
        }

        //fire hooks for all spawned objects
        SpawnResult spawnResult = null;

        if (spawnedObjects.Count == 1)
        {
            spawnResult = SpawnResult.Single(info, spawnedObjects[0]);
        }
        else
        {
            spawnResult = SpawnResult.Multiple(info, spawnedObjects);
        }

        _ServerFireClientServerSpawnHooks(spawnResult);

        return(spawnResult);
    }
Exemple #2
0
    /// <summary>
    /// Spawns a ghost for the indicated mind's body and transfers the connection's control to it.
    /// </summary>
    /// <param name="conn"></param>
    /// <param name="oldBody"></param>
    /// <param name="characterSettings"></param>
    /// <param name="occupation"></param>
    /// <returns></returns>
    public static void ServerSpawnGhost(Mind forMind)
    {
        //determine where to spawn the ghost
        var body         = forMind.GetCurrentMob();
        var settings     = body.GetComponent <PlayerScript>().characterSettings;
        var connection   = body.GetComponent <NetworkIdentity>().connectionToClient;
        var registerTile = body.GetComponent <RegisterTile>();

        if (registerTile == null)
        {
            Logger.LogErrorFormat("Cannot spawn ghost for body {0} because it has no registerTile", Category.ItemSpawn,
                                  body.name);
            return;
        }

        Vector3Int spawnPosition = body.GetComponent <ObjectBehaviour>().AssumedWorldPositionServer().RoundToInt();

        if (spawnPosition == TransformState.HiddenPos)
        {
            //spawn ghost at occupation location if we can't determine where their body is
            Transform spawnTransform = GetSpawnForJob(forMind.occupation.JobType);
            if (spawnTransform == null)
            {
                Logger.LogErrorFormat("Unable to determine spawn position for occupation {1}. Cannot spawn ghost.", Category.ItemSpawn,
                                      forMind.occupation.DisplayName);
                return;
            }

            spawnPosition = spawnTransform.transform.position.CutToInt();
        }

        var matrixInfo      = MatrixManager.AtPoint(spawnPosition, true);
        var parentNetId     = matrixInfo.NetID;
        var parentTransform = matrixInfo.Objects;

        //using parentTransform.rotation rather than Quaternion.identity because objects should always
        //be upright w.r.t.  localRotation, NOT world rotation
        var ghost = Object.Instantiate(CustomNetworkManager.Instance.ghostPrefab, spawnPosition, parentTransform.rotation,
                                       parentTransform);

        ghost.GetComponent <PlayerScript>().registerTile.ServerSetNetworkedMatrixNetID(parentNetId);

        forMind.Ghosting(ghost);

        ServerTransferPlayer(connection, ghost, body, EVENT.GhostSpawned, settings);


        //fire all hooks
        var info = SpawnInfo.Ghost(forMind.occupation, settings, CustomNetworkManager.Instance.ghostPrefab,
                                   SpawnDestination.At(spawnPosition, parentTransform));

        Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, ghost));
    }
Exemple #3
0
    /// <summary>
    /// Performs the specified spawn locally, for this client only.
    /// </summary>
    /// <returns></returns>
    public static SpawnResult Client(SpawnInfo info)
    {
        if (info == null)
        {
            Logger.LogError("Cannot spawn, info is null", Category.ItemSpawn);
            return(SpawnResult.Fail(info));
        }

        if (info.SpawnableToSpawn is IClientSpawnable clientSpawnable)
        {
            List <GameObject> spawnedObjects = new List <GameObject>();
            for (var i = 0; i < info.Count; i++)
            {
                var result = clientSpawnable.ClientSpawnAt(info.SpawnDestination);
                if (result.Successful)
                {
                    spawnedObjects.Add(result.GameObject);
                }
            }

            //fire client side lifecycle hooks
            foreach (var spawnedObject in spawnedObjects)
            {
                var hooks = spawnedObject.GetComponents <IClientSpawn>();
                if (hooks != null)
                {
                    foreach (var hook in hooks)
                    {
                        hook.OnSpawnClient(ClientSpawnInfo.Default());
                    }
                }
            }

            if (spawnedObjects.Count == 1)
            {
                return(SpawnResult.Single(info, spawnedObjects[0]));
            }

            return(SpawnResult.Multiple(info, spawnedObjects));
        }
        else
        {
            Logger.LogErrorFormat("Cannot spawn {0} client side, spawnable does not" +
                                  " implement IClientSpawnable", Category.ItemSpawn, info);
            return(SpawnResult.Fail(info));
        }
    }
Exemple #4
0
    /// <summary>
    /// Spawns an assistant dummy
    /// </summary>
    public static void ServerSpawnDummy()
    {
        Transform spawnTransform = GetSpawnForJob(JobType.ASSISTANT);

        if (spawnTransform != null)
        {
            var dummy = ServerCreatePlayer(spawnTransform.position.RoundToInt());

            ServerTransferPlayer(null, dummy, null, EVENT.PlayerSpawned, new CharacterSettings());


            //fire all hooks
            var info = SpawnInfo.Player(OccupationList.Instance.Get(JobType.ASSISTANT), new CharacterSettings(), CustomNetworkManager.Instance.humanPlayerPrefab,
                                        SpawnDestination.At(spawnTransform.gameObject));
            Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, dummy));
        }
    }
    /// <summary>
    /// Performs the specified spawn locally, for this client only.
    /// </summary>
    /// <returns></returns>
    public static SpawnResult Client(SpawnInfo info)
    {
        if (info == null)
        {
            Logger.LogError("Cannot spawn, info is null", Category.ItemSpawn);
            return(SpawnResult.Fail(info));
        }
        List <GameObject> spawnedObjects = new List <GameObject>();

        for (var i = 0; i < info.Count; i++)
        {
            if (info.SpawnableType == SpawnableType.Cloth)
            {
                Logger.LogErrorFormat("Spawning cloths on client side is not currently supported. {0}", Category.ItemSpawn, info);
                return(SpawnResult.Fail(info));
            }

            bool isPooled;             // not used for Client-only instantiation
            var  go = PoolInstantiate(info.PrefabUsed, info.WorldPosition, info.Rotation, info.Parent, out isPooled);

            spawnedObjects.Add(go);
        }

        //fire client side lifecycle hooks
        foreach (var spawnedObject in spawnedObjects)
        {
            var hooks = spawnedObject.GetComponents <IClientSpawn>();
            if (hooks != null)
            {
                foreach (var hook in hooks)
                {
                    hook.OnSpawnClient(ClientSpawnInfo.Default());
                }
            }
        }

        if (spawnedObjects.Count == 1)
        {
            return(SpawnResult.Single(info, spawnedObjects[0]));
        }

        return(SpawnResult.Multiple(info, spawnedObjects));
    }
    /// <summary>
    /// Spawns an assistant dummy
    /// </summary>
    public static void ServerSpawnDummy(Transform spawnTransform = null)
    {
        if (spawnTransform == null)
        {
            spawnTransform = SpawnPoint.GetRandomPointForJob(JobType.ASSISTANT);
        }
        if (spawnTransform != null)
        {
            var dummy = ServerCreatePlayer(spawnTransform.position.RoundToInt());

            CharacterSettings randomSettings = CharacterSettings.RandomizeCharacterSettings();

            ServerTransferPlayer(null, dummy, null, Event.PlayerSpawned, randomSettings);


            //fire all hooks
            var info = SpawnInfo.Player(OccupationList.Instance.Get(JobType.ASSISTANT), randomSettings, CustomNetworkManager.Instance.humanPlayerPrefab,
                                        SpawnDestination.At(spawnTransform.gameObject));
            Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, dummy));
        }
    }
Exemple #7
0
    /// <summary>
    /// Spawns a new player character and transfers the connection's control into the new body.
    /// If existingMind is null, creates the new mind and assigns it to the new body.
    ///
    /// Fires server and client side player spawn hooks.
    /// </summary>
    /// <param name="connection">connection to give control to the new player character</param>
    /// <param name="occupation">occupation of the new player character</param>
    /// <param name="characterSettings">settings of the new player character</param>
    /// <param name="existingMind">existing mind to transfer to the new player, if null new mind will be created
    /// and assigned to the new player character</param>
    /// <param name="spawnPos">world position to spawn at</param>
    /// <param name="spawnItems">If spawning a player, should the player spawn without the defined initial equipment for their occupation?</param>
    /// <param name="willDestroyOldBody">if true, indicates the old body is going to be destroyed rather than pooled,
    /// thus we shouldn't send any network message which reference's the old body's ID since it won't exist.</param>
    ///
    /// <returns>the spawned object</returns>
    private static GameObject ServerSpawnInternal(NetworkConnection connection, Occupation occupation, CharacterSettings characterSettings,
                                                  Mind existingMind, Vector3Int?spawnPos = null, bool spawnItems = true, bool willDestroyOldBody = false)
    {
        //determine where to spawn them
        if (spawnPos == null)
        {
            Transform spawnTransform;
            //Spawn normal location for special jobs or if less than 2 minutes passed
            if (GameManager.Instance.stationTime < ARRIVALS_SPAWN_TIME || occupation.LateSpawnIsArrivals == false)
            {
                spawnTransform = GetSpawnForJob(occupation.JobType);
            }
            else
            {
                spawnTransform = GetSpawnForLateJoin(occupation.JobType);
                //Fallback to assistant spawn location if none found for late join
                if (spawnTransform == null && occupation.JobType != JobType.NULL)
                {
                    spawnTransform = GetSpawnForJob(JobType.ASSISTANT);
                }
            }

            if (spawnTransform == null)
            {
                Logger.LogErrorFormat(
                    "Unable to determine spawn position for connection {0} occupation {1}. Cannot spawn player.",
                    Category.ItemSpawn,
                    connection.address, occupation.DisplayName);
                return(null);
            }

            spawnPos = spawnTransform.transform.position.CutToInt();
        }

        //create the player object
        var newPlayer       = ServerCreatePlayer(spawnPos.GetValueOrDefault());
        var newPlayerScript = newPlayer.GetComponent <PlayerScript>();

        //get the old body if they have one.
        var oldBody = existingMind?.GetCurrentMob();

        //transfer control to the player object
        ServerTransferPlayer(connection, newPlayer, oldBody, EVENT.PlayerSpawned, characterSettings, willDestroyOldBody);


        if (existingMind == null)
        {
            //create the mind of the player
            Mind.Create(newPlayer, occupation);
        }
        else
        {
            //transfer the mind to the new body
            existingMind.SetNewBody(newPlayerScript);
        }


        var ps = newPlayer.GetComponent <PlayerScript>();
        var connectedPlayer = PlayerList.Instance.Get(connection);

        connectedPlayer.Name = ps.playerName;
        connectedPlayer.Job  = ps.mind.occupation.JobType;
        UpdateConnectedPlayersMessage.Send();

        //fire all hooks
        var info = SpawnInfo.Player(occupation, characterSettings, CustomNetworkManager.Instance.humanPlayerPrefab,
                                    SpawnDestination.At(spawnPos), spawnItems: spawnItems);

        Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, newPlayer));

        return(newPlayer);
    }
    /// <summary>
    /// Spawns a ghost for the indicated mind's body and transfers the connection's control to it.
    /// </summary>
    /// <param name="conn"></param>
    /// <param name="oldBody"></param>
    /// <param name="characterSettings"></param>
    /// <param name="occupation"></param>
    /// <returns></returns>
    public static void ServerSpawnGhost(Mind forMind)
    {
        if (forMind == null)
        {
            Logger.LogError("Mind was null for ServerSpawnGhost", Category.Ghosts);
            return;
        }
        //determine where to spawn the ghost
        var body = forMind.GetCurrentMob();

        if (body == null)
        {
            Logger.LogError("Body was null for ServerSpawnGhost", Category.Ghosts);
            return;
        }

        var settings     = body.GetComponent <PlayerScript>().characterSettings;
        var connection   = body.GetComponent <NetworkIdentity>().connectionToClient;
        var registerTile = body.GetComponent <RegisterTile>();

        if (registerTile == null)
        {
            Logger.LogErrorFormat("Cannot spawn ghost for body {0} because it has no registerTile", Category.Ghosts,
                                  body.name);
            return;
        }

        Vector3Int spawnPosition = TransformState.HiddenPos;
        var        objBeh        = body.GetComponent <ObjectBehaviour>();

        if (objBeh != null)
        {
            spawnPosition = objBeh.AssumedWorldPositionServer();
        }

        if (spawnPosition == TransformState.HiddenPos)
        {
            //spawn ghost at occupation location if we can't determine where their body is
            Transform spawnTransform = SpawnPoint.GetRandomPointForJob(forMind.occupation.JobType, true);
            if (spawnTransform == null)
            {
                Logger.LogErrorFormat("Unable to determine spawn position for occupation {1}. Cannot spawn ghost.", Category.Ghosts,
                                      forMind.occupation.DisplayName);
                return;
            }

            spawnPosition = spawnTransform.transform.position.CutToInt();
        }

        var matrixInfo      = MatrixManager.AtPoint(spawnPosition, true);
        var parentTransform = matrixInfo.Objects;

        //using parentTransform.rotation rather than Quaternion.identity because objects should always
        //be upright w.r.t.  localRotation, NOT world rotation
        var ghost = UnityEngine.Object.Instantiate(CustomNetworkManager.Instance.ghostPrefab, spawnPosition, parentTransform.rotation,
                                                   parentTransform);

        forMind.Ghosting(ghost);

        ServerTransferPlayer(connection, ghost, body, Event.GhostSpawned, settings);


        //fire all hooks
        var info = SpawnInfo.Ghost(forMind.occupation, settings, CustomNetworkManager.Instance.ghostPrefab,
                                   SpawnDestination.At(spawnPosition, parentTransform));

        Spawn._ServerFireClientServerSpawnHooks(SpawnResult.Single(info, ghost));

        if (PlayerList.Instance.IsAdmin(forMind.ghost.connectedPlayer))
        {
            var adminItemStorage = AdminManager.Instance.GetItemSlotStorage(forMind.ghost.connectedPlayer);
            adminItemStorage.ServerAddObserverPlayer(ghost);
            ghost.GetComponent <GhostSprites>().SetAdminGhost();
        }
    }
Exemple #9
0
    /// <summary>
    /// FOR DEV / TESTING ONLY! Simulates destroying and recreating an item by putting it in the pool and taking it back
    /// out again. If item is not pooled, simply destroys and recreates it as if calling Despawn and then Spawn
    /// Can use this to validate that the object correctly re-initializes itself after spawning -
    /// no state should be left over from its previous incarnation.
    /// </summary>
    /// <returns>the re-created object</returns>
    public static GameObject ServerPoolTestRespawn(GameObject target)
    {
        var poolPrefabTracker = target.GetComponent <PoolPrefabTracker>();

        if (poolPrefabTracker == null)
        {
            //destroy / create using normal approach with no pooling
            Logger.LogWarningFormat("Object {0} has no pool prefab tracker, thus cannot be pooled. It will be destroyed / created" +
                                    " without going through the pool.", Category.ItemSpawn, target.name);

            //determine prefab
            var position = target.TileWorldPosition();
            var prefab   = DeterminePrefab(target);
            if (prefab == null)
            {
                Logger.LogErrorFormat("Object {0} at {1} cannot be respawned because it has no PoolPrefabTracker and its name" +
                                      " does not match a prefab name, so we cannot" +
                                      " determine the prefab to instantiate. Please fix this object so that it" +
                                      " has an attached PoolPrefabTracker or so its name matches the prefab it was created from.", Category.ItemSpawn, target.name, position);
                return(null);
            }

            Despawn.ServerSingle(target);
            return(ServerPrefab(prefab, position.To3Int()).GameObject);
        }
        else
        {
            //destroy / create with pooling
            //save previous position
            var destination = SpawnDestination.At(target);
            var worldPos    = target.TileWorldPosition();
            var transform   = target.GetComponent <IPushable>();
            var prevParent  = target.transform.parent;

            //this simulates going into the pool
            Despawn._ServerFireDespawnHooks(DespawnResult.Single(DespawnInfo.Single(target)));

            if (transform != null)
            {
                transform.VisibleState = false;
            }

            //this simulates coming back out of the pool
            target.SetActive(true);

            target.transform.parent   = prevParent;
            target.transform.position = worldPos.To3Int();

            var cnt = target.GetComponent <CustomNetTransform>();
            if (cnt)
            {
                cnt.ReInitServerState();
                cnt.NotifyPlayers();                 //Sending out clientState for already spawned items
            }
            var       prefab    = DeterminePrefab(target);
            SpawnInfo spawnInfo = SpawnInfo.Spawnable(
                SpawnablePrefab.For(prefab),
                destination);


            _ServerFireClientServerSpawnHooks(SpawnResult.Single(spawnInfo, target));
            return(target);
        }
    }
Exemple #10
0
    /// <summary>
    /// Server-side only. Performs the spawn and syncs it to all clients.
    /// </summary>
    /// <returns></returns>
    private static SpawnResult Server(SpawnInfo info, bool AutoOnSpawnServerHook = true)
    {
        if (info == null)
        {
            Logger.LogError("Cannot spawn, info is null", Category.ItemSpawn);
            return(SpawnResult.Fail(info));
        }

        EnsureInit();
        Logger.LogTraceFormat("Server spawning {0}", Category.ItemSpawn, info);

        List <GameObject> spawnedObjects = new List <GameObject>();

        for (int i = 0; i < info.Count; i++)
        {
            var result = info.SpawnableToSpawn.SpawnAt(info.SpawnDestination);

            if (result.Successful)
            {
                if (info.Mapspawn == false)
                {
                    result.GameObject.AddComponent <RuntimeSpawned>();
                }
                spawnedObjects.Add(result.GameObject);
                //apply scattering if it was specified
                if (info.ScatterRadius != null)
                {
                    var cnt           = result.GameObject.GetComponent <CustomNetTransform>();
                    var scatterRadius = info.ScatterRadius.GetValueOrDefault(0);
                    if (cnt != null)
                    {
                        cnt.SetPosition(info.SpawnDestination.WorldPosition + new Vector3(
                                            Random.Range(-scatterRadius, scatterRadius), Random.Range(-scatterRadius, scatterRadius)));
                    }
                }

                if (info.SpawnDestination.SharePosition != null &&
                    info.SpawnDestination.SharePosition.parentContainer != null)
                {
                    if (result.GameObject.TryGetComponent <ObjectBehaviour>(out var objectBehaviour))
                    {
                        var closetControl = info.SpawnDestination.SharePosition.parentContainer
                                            .GetComponent <ClosetControl>();
                        closetControl.ServerAddInternalItem(objectBehaviour);
                    }
                }
            }
            else
            {
                return(SpawnResult.Fail(info));
            }
        }

        //fire hooks for all spawned objects
        SpawnResult spawnResult = null;

        if (spawnedObjects.Count == 1)
        {
            spawnResult = SpawnResult.Single(info, spawnedObjects[0]);
        }
        else
        {
            spawnResult = SpawnResult.Multiple(info, spawnedObjects);
        }

        if (AutoOnSpawnServerHook)
        {
            _ServerFireClientServerSpawnHooks(spawnResult);
        }


        return(spawnResult);
    }
Exemple #11
0
    /// <summary>
    /// Server-side only. Performs the spawn and syncs it to all clients.
    /// </summary>
    /// <returns></returns>
    private static SpawnResult Server(SpawnInfo info)
    {
        if (info == null)
        {
            Logger.LogError("Cannot spawn, info is null", Category.ItemSpawn);
            return(SpawnResult.Fail(info));
        }
        EnsureInit();
        Logger.LogTraceFormat("Server spawning {0}", Category.ItemSpawn, info);

        List <GameObject> spawnedObjects = new List <GameObject>();

        for (int i = 0; i < info.Count; i++)
        {
            if (info.SpawnableType == SpawnableType.Prefab)
            {
                if (info.PrefabUsed == null)
                {
                    Logger.LogError("Cannot spawn, prefab to use is null", Category.ItemSpawn);
                    return(SpawnResult.Fail(info));
                }

                if (info.CancelIfImpassable)
                {
                    if (IsTotallyImpassable(info.WorldPosition.CutToInt()))
                    {
                        Logger.LogTraceFormat("Cancelling spawn of {0} because" +
                                              " the position being spawned to {1} is impassable",
                                              Category.ItemSpawn, info.PrefabUsed, info.WorldPosition.CutToInt());
                        return(SpawnResult.Fail(info));
                    }
                }

                bool isPooled;

                GameObject tempObject = PoolInstantiate(info.PrefabUsed, info.WorldPosition, info.Rotation,
                                                        info.Parent,
                                                        out isPooled);

                if (!isPooled)
                {
                    Logger.LogTrace("Prefab to spawn was not pooled, spawning new instance.", Category.ItemSpawn);
                    NetworkServer.Spawn(tempObject);
                    tempObject.GetComponent <CustomNetTransform>()
                    ?.NotifyPlayers();                             //Sending clientState for newly spawned items
                }
                else
                {
                    Logger.LogTrace("Prefab to spawn was pooled, reusing it...", Category.ItemSpawn);
                }

                spawnedObjects.Add(tempObject);
            }
            else if (info.SpawnableType == SpawnableType.Cloth)
            {
                var result = ServerCloth(info);
                if (result == null)
                {
                    return(SpawnResult.Fail(info));
                }

                spawnedObjects.Add(result);
            }
            else if (info.SpawnableType == SpawnableType.Clone)
            {
                var prefab = DeterminePrefab(info.ClonedFrom);
                if (prefab == null)
                {
                    Logger.LogErrorFormat(
                        "Object {0} cannot be cloned because it has no PoolPrefabTracker and its name" +
                        " does not match a prefab name, so we cannot" +
                        " determine the prefab to instantiate. Please fix this object so that it" +
                        " has an attached PoolPrefabTracker or so its name matches the prefab it was created from.",
                        Category.ItemSpawn, info.ClonedFrom);
                }

                GameObject tempObject = PoolInstantiate(prefab, info.WorldPosition, info.Rotation, info.Parent,
                                                        out var isPooled);

                if (!isPooled)
                {
                    NetworkServer.Spawn(tempObject);
                    tempObject.GetComponent <CustomNetTransform>()
                    ?.NotifyPlayers();                             //Sending clientState for newly spawned items
                }

                spawnedObjects.Add(tempObject);
            }

            //apply scattering if it was specified
            if (info.ScatterRadius != null)
            {
                foreach (var spawned in spawnedObjects)
                {
                    var cnt           = spawned.GetComponent <CustomNetTransform>();
                    var scatterRadius = info.ScatterRadius.GetValueOrDefault(0);
                    if (cnt != null)
                    {
                        cnt.SetPosition(info.WorldPosition + new Vector3(Random.Range(-scatterRadius, scatterRadius), Random.Range(-scatterRadius, scatterRadius)));
                    }
                }
            }

            //fire hooks for all spawned objects
            if (spawnedObjects.Count == 1)
            {
                _ServerFireClientServerSpawnHooks(SpawnResult.Single(info, spawnedObjects[0]));
            }
            else
            {
                _ServerFireClientServerSpawnHooks(SpawnResult.Multiple(info, spawnedObjects));
            }
        }

        return(SpawnResult.Multiple(info, spawnedObjects));
    }