Can Unity Editor enter PlayMode without reloading a script - unity3d

I am writing an Unity editor script that creates TCP server accepts requests from other application, but I found out that "clicking" play mode reloads my editor scripts which will interrupts the connection by re-initializing my server. Is there any way Unity Editor can stop reloading this particular script and makes it up running at all time?
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod()
{
if (m_Server == null)
{
EditorApplication.update += Update;
Debug.Log("starting");
IPAddress ip = IPAddress.Parse(ipAdress);
m_Server = new TcpListener(ip, port);
m_Server.Start();
Debug.Log("Sever started");
Debug.Log(ip);
Debug.Log(port);
//Wait for async client connection
m_Server.BeginAcceptTcpClient(ClientConnected, null);
OnServerStarted?.Invoke();
}
In other words, is there a way to keep all my static variables and my editor coroutines after PlayMode is invoked? I did some search and I think domain reloading has caused it

Haven't tried this and don't have Unity on this PC to test, but can you gate it by using the isPlaying check:
if (!Application.isPlaying)
{
// Do your server stuff here
}
https://docs.unity3d.com/ScriptReference/Application-isPlaying.html
In other words, don't run the code while the game is playing, which is true when you hit the Play button?

Related

Unity Stopping PlayMode After Yield Instruction

I have a system which can generate asset bundles + generate asset preview picture(.png) and packed to zip result.
GameObjects injected to Creator in Editor Mode and Creator initiated enabling\disabling PlayMode and do all logic in him.
But sometimes on my colleague machine it doesn't work... without any visible reasons. Log is clear and didn't have errors.
Last what I see everytime - it is log before "yield" instruction in coroutine. And after that "PlayMode Exit" log.
I re-checked all.
GameObject 100% is active when coroutine working.
Unity Editor Logs also doesn't contain any lines about errors.
But I don't have any idea whats wrong... is possible this is unique problem on PC?
Here is my code and last place what can write log before exiting from PlayMode
https://pastebin.com/w7VnjFFk
private IEnumerator DelayedCameraPositionAndSnapshot()
{
Debug.Log("AssetPreviewCreator.DelayedCameraPositionAndSnapshot()");
//Change object position for clear snapshot
_previousAssetPosition = _targetAssetObject.transform.position;
Vector3 assetPosition = _previousAssetPosition;
assetPosition.x -= 600f;
_targetAssetObject.transform.position = assetPosition;
Debug.Log("AssetPreviewCreator.DelayedCameraPositionAndSnapshot() before delay");
yield return new WaitForSeconds(0.5f);
Debug.Log("AssetPreviewCreator.DelayedCameraPositionAndSnapshot() after delay");

Unity not detecting F1 and F2 key presses

I am returning to unity after 6 months. I started my fps game yesterday. Today I was trying to make C4 bomb, which worked as follows: the c4 will already be placed, you just have to activate using a remote. In the start the remote will not be in your hand, you have to press F1 to set it active. To put the remote away again, we have to press F2. But the problem is that it won't detect my F1 key press. Here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class C4Script : MonoBehaviour
{
public GameObject remote;
private bool remoteHand;
// Start is called before the first frame update
void Start()
{
remote.SetActive(false);
remoteHand = false;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.F1) && !remoteHand)
{
remote.SetActive(true);
remoteHand = true;
}
if (Input.GetKeyUp(KeyCode.F2) && remoteHand)
{
remote.SetActive(false);
remoteHand = false;
}
}
}
The code may be wrongly formatted, I am sorry for that.
Also sorry if I didn't explain it properly.
Thanks!
The code works on my machine, do you maybe have the C4Script or the Gameobject on which it is attached disabled?
Looks like the script is never called rather then that it's not detecting the input. You could add an Debug log or debug breakpoint to the start method to check if it's ever called.
Soo, the problem was that i am dumb. i Put this script on the remote, and at the start it disables the remote thats why it wasn't detecting my key press. I put the script on my player object and now it works fine.

Roblox Studio - how do I run a script right before game starts?

I'm attempting to create a plugin that fetches additional code from a server before the user plays the game on roblox studio.
Basically, the user will use something like blockly to create luau code on a website and I want to sent that code to roblox studio. I've seen some plugins that fetch new data from a server from time to time and I've been able to do that, but I'd like to see if there's a way to only fetch the new code when the user clicks the play button because it could be expensive to request new data every 5 seconds or so.
Below is a simple plugin that attempts to send a request to the server when the game loads, but the script never goes beyond game.Loaded:Wait()
Main file:
local Request = require(script.Parent.Request)
local URL = "http://localhost:3333"
local toolbar = plugin:CreateToolbar("Test")
local button = toolbar:CreateButton("Test", "Test", "rbxassetid://4458901886")
local isListening = false
local request = Request.new()
local ok
local json
local function onClick ()
isListening = not isListening
if (isListening == false) then
return print("Not listening")
end
print("Listening")
if not game:IsLoaded() then
print(game.Loaded)
game.Loaded:Wait()
print("Game has started")
ok, json = request:Get(URL)
print(ok, json)
end
end
button.Click:Connect(onClick)
Request file:
local Request = {}
Request.__index = Request
function Request.new()
return setmetatable({}, Request)
end
function Request:Get(URL)
local ok, result = pcall(game.HttpService.GetAsync, game.HttpService, URL)
local json = game.HttpService:JSONDecode(result)
return ok, json
end
return Request
There isn't an explicit signal to detect when a game is about to start.
But, whenever you hit the Play button, the Edit session ends and the Play session begins. When a session ends, all of the plugins are unloaded. So you could use the plugin.Unloading signal to detect when the Edit session is ending, but it will also fire when the user closes the place, when you stop play testing, or when the plugin is disabled or uninstalled.
You could combine that signal with the RunService:IsEdit() function so that the behavior only triggers when exiting Edit mode, but this is still a really hazy signal.
So in a Script in your plugin, you could do something like this :
local RunService = game:GetService("RunService")
local Request = require(script.Parent.Request)
local URL = "<YOUR URL>"
-- listen for when sessions end
plugin.Unloading:Connect(function()
-- disregard sessions that aren't Edit Mode
if not RunService:IsEdit() end
return
end
print("Game about to start... maybe. The game might also be closing, or the plugin might be disabled from the PluginManager.")
local ok, json = request:Get(URL)
print(ok, json)
end)
Debugging this may be difficult as the Output console is cleared any time you start a Play session, so you won't see any of your print statements. But if you close the place, your logs will be preserved on the Welcome Screen. Just go View > Output to open the Output window.

Missing something important with ClientRpc (Unity Mirror)

I'm having an issue with ClientRpc never being called any client objects. I've trolled the internet for hours, but I can't find any clues as to why my implementation isn't working.
I'm following an order of events like so:
Add players in a lobby
Switch scene to the gameplay scene
Generate random tiles on the server
Send tile data to the clients using Rpc for rendering
However, the rendering function never gets called.
NetworkManager.cs
public override void OnServerReady(NetworkConnection conn)
{
base.OnServerReady(conn);
//Make sure they're all ready
for (int i = RoomPlayers.Count - 1; i >= 0; i--)
{
if (!RoomPlayers[i].IsReady)
{
return;
}
}
//Previously add SpawnTiles to OnServerReadied
OnServerReadied?.Invoke(conn);
}
GameManager.cs
private void SpawnTiles(NetworkConnection conn)
{
//Generate rawTiles beforehand
Debug.Log(conn.isReady);
Debug.Log("Entered spawn tiles");
RpcSpawnTiles(rawTiles);
}
[ClientRpc]
public void RpcSpawnTiles(short[] rawTiles)
{
Debug.Log("Client spawning tiles");
}
And this is my output when run on a host:
True
Entered spawn tiles
It appears to never enter the Rpc function :(
Is there something super obvious that I'm missing? My GameManager does have a NetworkID attached to it
There seemed to be a combination of things that I had to do to get it to work- I'm not entirely sure which one worked, but if you are having these problems, these are some of the things I had to check-
Just basic code. Make sure that the appropriate things are being created on the client, host, or server
Make sure that there aren't any race conditions, especially when working with changing scenes. You can call stuff from OnClientSceneChanged and OnServerSceneChanged
As derHugo pointed out, I was not checking to see if my package could even be sent. It turns out that the maximum size that can be sent is 1200 bytes, while I was trying to send 100x100x4 bytes. This error didn't occur when I was testing on the host, only when there was an external client

Unet, how to sync a counter to check if all players are ready

I'm making a multiplayer bomberman game using Unet. I'm trying to create a ready check to start the game when everyone else is ready.
I tried using a sync var,Command and Rpc calls, but nothing seems to work properly.
When using a Cmd call this way (called when a player pushes the ready button)
[Command]
private void CmdIncreaseReady()
{
IncreaseReady();
RpcIncreaseReady();
}
[ClientRpc]
private void RpcIncreaseReady()
{
IncreaseReady();
}
private void IncreaseReady() {
playersReady++;
//ChechAllReady();
}
When pressed on the client, everyone's counter is 0 (it should be one), and when pressed on the server, the server's counter is 2 and the client 1.
I've tried to call Cmd when !isServer and Rpc when it is, and the result is that stills doesn't update when pressed on the client, but it is updated correctly (the counter is 1 on both), when pressed on the server.
if (!isServer)
{
CmdIncreaseReady();
}
else
{
RpcIncreaseReady();
}
If I delete the IncreaseReady() call on the Cmd, the result is the same than above.
I've tried too to use a [SyncVar] to the counter, with and without a hook, passing 1 on the hook (to increment the counter that amount) and passing the already counter incremented and set variable to that number, nothing seems to work.
I really don't know how to make it work anymore. Could someone help me? I'm really desperate with this. I've searched everywhere.
The script is the game manager, when every client has his version, it has a Netework Identity and has Local player Authority.
I've tried another approach, passing the increased number on the Cmd and Rpc, and inside the functions, just set the playersReady = i. Even that doesn't work.
[UPDATE]:
So, I've found the specific problem that I want to solve, and it's to Sync non-player objects properties.
I've tried to spawn the Game Manager with Client Authority, and now it seems to sync correctly only on the server, the client stills doesn't call the Cmd propety.
Looking at the Debug mode in the inspector, I've been able to see that on the server, hasAutority is true, but is false on the client.
This is a fragment of the code on the player script where I spawn the game manager:
void Update()
{
if (!sceneLoaded)
{
if(isServer & SceneManager.GetActiveScene().name == "Main Scene")
//if (SceneManager.GetActiveScene().name == "Main Scene")
{
if (connectionToClient.isReady)
{
var go = (GameObject)Instantiate(gameManager);
NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
go.transform.SetParent(null);
//go.GetComponent<NetworkIdentity>().AssignClientAuthority(connectionToClient);
globalManager = go.GetComponent<FSM>();
//SetFSM();
sceneLoaded = true;
}
}
}
UNET has a Lobby system which does exactly what I think you want. It has a per-player ready state, so that the game starts when all players are ready.
I would recommend using that, as it saves you having to reimplement things like dropping out, rejoining etc...