No compile for last update, fix please.
ZoneManagerTime - Failed to compile: 'ZoneManagerTime.DateController.OnDestroy()': cannot change access modifiers when overriding 'public' inherited member 'SingletonComponent.OnDestroy()' | Line: 113, Pos: 37
No compile
Try this
using System;
using System.Collections.Generic;
using Network;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Zone Manager Time", "misticos", "1.0.1")]
[Description("Set specific time for your zones")]
class ZoneManagerTime : CovalencePlugin
{
#region Variables
[PluginReference]
// ReSharper disable once InconsistentNaming
private Plugin ZoneManager = null;
private Dictionary<string, string> _playerZones = new Dictionary<string, string>();
#endregion
#region Configuration
private Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Zone ID Time", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, TimeSpan> ZoneTime = new Dictionary<string, TimeSpan>
{{"Zone ID", new TimeSpan(10, 5, 37)}};
[JsonProperty(PropertyName = "Update Frequency")]
public float UpdateFrequency = 5f;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() => Config.WriteObject(_config);
protected override void LoadDefaultConfig() => _config = new Configuration();
#endregion
#region Hooks
private void OnServerInitialized()
{
new GameObject().AddComponent<DateController>().PluginInstance = this;
if (ZoneManager != null && ZoneManager.IsLoaded)
{
foreach (var player in BasePlayer.activePlayerList)
{
var zones = ZoneManager.Call<string[]>("GetPlayerZoneIDs", player);
if (zones == null || zones.Length == 0)
continue;
_playerZones[player.UserIDString] = zones[zones.Length - 1];
}
}
}
private void Unload()
{
UnityEngine.Object.DestroyImmediate(DateController.Instance.gameObject);
}
private void OnEnterZone(string zoneId, BasePlayer player)
{
_playerZones[player.UserIDString] = zoneId;
}
private void OnExitZone(string zoneId, BasePlayer player)
{
_playerZones.Remove(player.UserIDString);
}
#endregion
#region Controller
private class DateController : SingletonComponent<DateController>
{
public ZoneManagerTime PluginInstance = null;
private EnvSync _timeEntity;
private void Start()
{
_timeEntity = FindObjectOfType<EnvSync>();
_timeEntity.limitNetworking = true;
InvokeRepeating(DoUpdate, PluginInstance._config.UpdateFrequency, PluginInstance._config.UpdateFrequency);
}
public override void OnDestroy()
{
base.OnDestroy();
_timeEntity.limitNetworking = false;
}
private void DoUpdate()
{
var saveInfo = new BaseNetworkable.SaveInfo
{
forDisk = false
};
using (saveInfo.msg = Facepunch.Pool.Get<ProtoBuf.Entity>())
{
_timeEntity.Save(saveInfo);
var initialDateTime = DateTime.FromBinary(saveInfo.msg.environment.dateTime);
for (var i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var connection = BasePlayer.activePlayerList[i].net?.connection;
if (connection == null)
continue;
var write = Net.sv.StartWrite();
saveInfo.forConnection = connection;
connection.validate.entityUpdates += 1u;
write.PacketID(Message.Type.Entities);
write.UInt32(connection.validate.entityUpdates);
string zoneId;
TimeSpan offset;
if (PluginInstance._playerZones.TryGetValue(BasePlayer.activePlayerList[i].UserIDString,
out zoneId) && PluginInstance._config.ZoneTime.TryGetValue(zoneId, out offset))
{
saveInfo.msg.environment.dateTime = (initialDateTime.Date + offset).ToBinary();
}
else
{
saveInfo.msg.environment.dateTime = initialDateTime.ToBinary();
}
saveInfo.msg.ToProto(write);
write.Send(new SendInfo(connection));
}
}
}
}
#endregion
}
} Thank you so much.
Is there another plugin you all found since this one doesnt work.
WarZombie
Is there another plugin you all found since this one doesnt work.
I was looking for one, too, since there was a different compile error now when using the code BadKop provided. The downside to all the cool server updates recently, I guess! This is what ChatGPT gave me as far as what to correct to work with the latest server build, along with the explanation of why it changed what it did. It's working on my server currently.
using System;
using System.Collections.Generic;
using System.Reflection; // <-- added
using Network;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Zone Manager Time", "misticos", "1.0.1")]
[Description("Set specific time for your zones")]
class ZoneManagerTime : CovalencePlugin
{
#region Variables
[PluginReference]
// ReSharper disable once InconsistentNaming
private Plugin ZoneManager = null;
private Dictionary<string, string> _playerZones = new Dictionary<string, string>();
#endregion
#region Configuration
private Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Zone ID Time", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, TimeSpan> ZoneTime = new Dictionary<string, TimeSpan>
{ { "Zone ID", new TimeSpan(10, 5, 37) } };
[JsonProperty(PropertyName = "Update Frequency")]
public float UpdateFrequency = 5f;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch
{
PrintError("Your configuration file contains an error. Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() => Config.WriteObject(_config);
protected override void LoadDefaultConfig() => _config = new Configuration();
#endregion
#region Hooks
private void OnServerInitialized()
{
new GameObject().AddComponent<DateController>().PluginInstance = this;
if (ZoneManager != null && ZoneManager.IsLoaded)
{
foreach (var player in BasePlayer.activePlayerList)
{
var zones = ZoneManager.Call<string[]>("GetPlayerZoneIDs", player);
if (zones == null || zones.Length == 0)
continue;
_playerZones[player.UserIDString] = zones[zones.Length - 1];
}
}
}
private void Unload()
{
UnityEngine.Object.DestroyImmediate(DateController.Instance.gameObject);
}
private void OnEnterZone(string zoneId, BasePlayer player)
{
_playerZones[player.UserIDString] = zoneId;
}
private void OnExitZone(string zoneId, BasePlayer player)
{
_playerZones.Remove(player.UserIDString);
}
#endregion
#region Controller
private class DateController : SingletonComponent<DateController>
{
public ZoneManagerTime PluginInstance = null;
private EnvSync _timeEntity;
// --- Reflection cache for ToProto fallbacks
private static readonly string[] BufferFieldCandidates = { "write", "_write", "stream", "_stream", "buffer", "_buffer" };
private void Start()
{
_timeEntity = FindObjectOfType<EnvSync>();
_timeEntity.limitNetworking = true;
InvokeRepeating(DoUpdate, PluginInstance._config.UpdateFrequency, PluginInstance._config.UpdateFrequency);
}
public override void OnDestroy() // must be public to match base signature
{
base.OnDestroy();
_timeEntity.limitNetworking = false;
}
private bool TryWriteEntityProto(object entityMsg, NetWrite nw)
{
if (entityMsg == null || nw == null) return false;
var msgType = entityMsg.GetType();
// 1) Try ToProto(NetWrite)
var toProtoNetWrite = msgType.GetMethod(
"ToProto",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[] { nw.GetType() },
null);
if (toProtoNetWrite != null)
{
try
{
toProtoNetWrite.Invoke(entityMsg, new object[] { nw });
return true;
}
catch { /* fall through */ }
}
// 2) Try common internal BufferStream-like fields on NetWrite
var nwt = nw.GetType();
foreach (var fname in BufferFieldCandidates)
{
var f = nwt.GetField(fname, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (f == null) continue;
var buf = f.GetValue(nw);
if (buf == null) continue;
var toProtoBuf = msgType.GetMethod(
"ToProto",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[] { buf.GetType() },
null);
if (toProtoBuf != null)
{
try
{
toProtoBuf.Invoke(entityMsg, new object[] { buf });
return true;
}
catch { /* keep searching */ }
}
}
// If we got here, we couldn't find a compatible overload
if (PluginInstance != null)
PluginInstance.PrintError("Unable to locate ProtoBuf.Entity.ToProto(...) overload for this server build.");
return false;
}
private void DoUpdate()
{
var saveInfo = new BaseNetworkable.SaveInfo
{
forDisk = false
};
using (saveInfo.msg = Facepunch.Pool.Get<ProtoBuf.Entity>())
{
_timeEntity.Save(saveInfo);
var initialDateTime = DateTime.FromBinary(saveInfo.msg.environment.dateTime);
for (var i = 0; i < BasePlayer.activePlayerList.Count; i++)
{
var connection = BasePlayer.activePlayerList[i].net?.connection;
if (connection == null)
continue;
var write = Net.sv.StartWrite();
saveInfo.forConnection = connection;
connection.validate.entityUpdates += 1u;
write.PacketID(Message.Type.Entities);
write.UInt32(connection.validate.entityUpdates);
string zoneId;
TimeSpan offset;
if (PluginInstance._playerZones.TryGetValue(BasePlayer.activePlayerList[i].UserIDString,
out zoneId) && PluginInstance._config.ZoneTime.TryGetValue(zoneId, out offset))
{
saveInfo.msg.environment.dateTime = (initialDateTime.Date + offset).ToBinary();
}
else
{
saveInfo.msg.environment.dateTime = initialDateTime.ToBinary();
}
// CHANGED: version-agnostic ToProto
if (!TryWriteEntityProto(saveInfo.msg, write))
{
// Don't send a malformed packet if serialization failed
continue;
}
write.Send(new SendInfo(connection));
}
}
}
}
#endregion
}
}
"
Here’s what changed—and why it matters:
What’s different
Added reflection-based serializer
New version: adds
using System.Reflection;, aBufferFieldCandidatesarray, and a helper:private bool TryWriteEntityProto(object entityMsg, NetWrite nw) { ... }In
DoUpdate()it now does:if (!TryWriteEntityProto(saveInfo.msg, write)) continue;Old version: directly calls
saveInfo.msg.ToProto(write);(which assumes
ToProto(NetWrite)exists, or thatNetWriteis implicitly convertible).
Overload selection logic
New: Tries
ToProto(NetWrite)first. If that overload isn’t present, it reflects common internal fields onNetWrite(write,_write,stream,_stream,buffer,_buffer) and callsToProto(BufferStreamType)instead.Old: No fallback; it will fail on builds where
ToProtoexpects aBufferStream(or whereNetWrite.writeisn’t exposed).
Safer failure behavior
New: On a mismatch, it logs a clear error and skips sending that packet (avoids malformed frames).
Old: Compilation fails (
cannot convert from 'Network.NetWrite' to 'BufferStream') or crashes at runtime if the signature doesn’t match.
Access modifier on
OnDestroy
New:
public override void OnDestroy()(matches baseSingletonComponent).Old:
protected override void OnDestroy()(can cause: “cannot change access modifiers when overriding ‘public’ inherited member”).
Why it matters
Cross-version Rust compatibility. Facepunch has changed the
ProtoBuf.Entity.ToProto(...)signature across builds. The reflection path lets your plugin work whether the server expectsToProto(NetWrite)orToProto(BufferStream), so you don’t have to keep chasing breaking changes.Fixes your compile error. The old call
ToProto(write)produced:Argument 1: cannot convert from 'Network.NetWrite' to 'BufferStream'.
The new code passes the correct thing for your DLLs at runtime.Prevents hard crashes/bad packets. If serialization can’t be resolved, the new code logs and skips one send instead of pushing a malformed Entities packet (which can kick players).
Builds cleanly. Making
OnDestroypublic avoids the access-modifier override error on newer Oxide/Rust.
Everything else (timers, limitNetworking, connection.validate.entityUpdates counter bump, etc.) is unchanged between your two snippets. The big win is the version-agnosticToProto call and the compile-proof OnDestroy override."
Hope this helps!!