I am building a simulation that will be playable on multiple systems on a local network.
One of the main objects is a simulation clock.
I am instantiating the object and spawning it in OnServerStart with NetworkServer.Spawn.
The Network Identity has neither Server Only nor Local Authority checked.
The clock shows up on the server and all clients. It can be started from the local client on the server. It runs and keeps time on all clients. It can be stopped from the local client on the server.
My problem comes when I want to stop the clock from any one of the clients. I get an error message of:
Trying to send command for object without authority.
I feel like I am missing something basic.
Do I need to change something on the Network Identity?
Do I need to Spawn it differently?
Do I need to message the server in some other way then using the [Command] attribute?
Class Attached:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
/*
Clockwork is used to regulate the simulation time.
This class is derived from NetworkBehaviour and should
be spawned by the server on the network with:
NetworkServer.Spawn
It aasumes that the system clocks are in sync via NTP.
DateTime Structs can't be used as SyncVars. So, DateTime is
converted to formatted strings and passed to clients where Hook
methods convert them back to DateTime.
Four events are exposed:
DayTick; - clock face can subscribe to this event to update CurrDate
MonthTick;
CalendarYearTick;
FiscalYearTick;
*/
[NetworkSettings(sendInterval = 0)]
public class Clockwork : NetworkBehaviour {
//Last start in simulation time as string
[SyncVar(hook="PassLastSimulationStartDate")]
string LastSimulationStartDateString;
//Last start in system time as string
[SyncVar(hook="PassLastSystemStartTime")]
string LastSystemStartTimeString;
//Simulation time per System time
[SyncVar]
public int TimeScale; //days per minute
//Is the Clockwork Running
[SyncVar(hook="PassRunning")]
public bool Running;
public DateTime LastSimulationStartDate;
public DateTime CurrentSimulationDate;
public DateTime LastSystemStartTime;
// string version of the current clock date to use in the clock face
public string CurrDate;
//Hook for converting LastSimulationStartDateString to DateTime
void PassLastSimulationStartDate (string LastSimulationStartDateStr) {
LastSimulationStartDate = Convert.ToDateTime (LastSimulationStartDateStr);
}
//Hook for converting PassLastSystemStartTime to DateTime
void PassLastSystemStartTime (string LastSystemStartTimeStr) {
LastSystemStartTime = Convert.ToDateTime (LastSystemStartTimeStr);
}
//Hook for Running to start and stop Clockwork on client
void PassRunning (bool RunningBool) {
if (!isServer) {
if (RunningBool) {
Running = true;
StartCoroutine ("Escapement");
} else {
Running = false;
}
}
}
//Delegate for Clock Events
public delegate void PeriodTick () ;
//Clock Events to allow classes to conserve their Update Method
public static event PeriodTick DayTick;
public static event PeriodTick MonthTick;
public static event PeriodTick CalendarYearTick;
public static event PeriodTick FiscalYearTick;
//Stored values to test for period changes
int PreviousDay;
int PreviousMonth;
int PreviousCalendarYear;
int PreviousFiscalYear;
//coroutine run Clockwork
IEnumerator Escapement () {
while (Running) {
double ElapsedDays = (DateTime.Now - LastSystemStartTime).TotalSeconds * TimeScale / 60;
CurrentSimulationDate = LastSimulationStartDate.AddDays (ElapsedDays);
CurrDate = CurrentSimulationDate.ToString("MM/dd/yyyy");
if (CurrentSimulationDate.Day != PreviousDay) {
if (DayTick != null) {
DayTick ();
}
PreviousDay = CurrentSimulationDate.Day;
if (CurrentSimulationDate.Month != PreviousMonth) {
if (MonthTick != null) {
MonthTick ();
}
PreviousMonth = CurrentSimulationDate.Month;
if (CurrentSimulationDate.Year != PreviousCalendarYear) {
if (CalendarYearTick != null) {
CalendarYearTick ();
}
PreviousCalendarYear = CurrentSimulationDate.Year;
}
if (CurrentSimulationDate.AddDays(92).Year != PreviousFiscalYear) {
if (FiscalYearTick != null) {
FiscalYearTick ();
}
PreviousFiscalYear = CurrentSimulationDate.AddDays(92).Year;
}
}
}
yield return null;
}
StopCoroutine("Escapement");
}
// Use this for initialization
public override void OnStartServer () {
CurrentSimulationDate = DateTime.Today;
Running = false;
}
//Start the Server Clockwork
public void StartClock () {
LastSimulationStartDate = CurrentSimulationDate;
LastSimulationStartDateString = LastSimulationStartDate.ToShortDateString ();
LastSystemStartTime = DateTime.Now;
LastSystemStartTimeString = LastSystemStartTime.ToString ("yyyy-MM-ddTHH:mm:ss.ffff");
Running = true;
StartCoroutine ("Escapement");
}
//Stop the Clockwork
public void StopClock () {
if (hasAuthority) {
Running = false;
} else {
CmdOff ();
}
}
//When the new instance is created on a client the SyncVars will already be synced
//so the Hooks are rerun
public override void OnStartClient () {
if (Running) {
PassLastSimulationStartDate (LastSimulationStartDateString);
PassLastSystemStartTime (LastSystemStartTimeString);
PassRunning (Running);
}
}
[Command]
public void CmdOff () {
Running = false;
}
}