using Sandbox.Network; using System; using System.Collections.Generic; namespace Sandbox; internal class ReplicatedConvars { public StringTable StringTable { get; init; } public ReplicatedConvars( string name ) { StringTable = new( name, true ); StringTable.OnChangeOrAdd += OnTableEntryUpdated; StringTable.OnRemoved += OnTableEntryRemoved; StringTable.OnSnapshot += OnTableSnapshot; ConVarSystem.ConVarChanged += OnConVarChanged; } /// /// Should be called after the assemblies are loaded. We'll update all the replicated convars now. /// public void OnAssembliesLoaded() { if ( !Networking.IsHost ) return; foreach ( var convar in ConVarSystem.Members.Values ) { if ( !convar.IsReplicated ) continue; StringTable.SetString( convar.Name, convar.Value ); } } public void Reset() { StringTable.Reset(); } /// /// Called any time a ConVar changes. /// void OnConVarChanged( Command convar, string oldValue ) { if ( !Networking.IsHost ) return; if ( !convar.IsReplicated ) return; StringTable.SetString( convar.Name, convar.Value ); } void OnTableEntryUpdated( StringTable.Entry entry ) { if ( Networking.IsHost ) return; // host table shouldn't update host table! var newValue = entry.ReadAsString(); // no change if ( _values.GetValueOrDefault( entry.Name ) == newValue ) return; _values[entry.Name] = newValue; Log.Info( $"Replicated Var Changed: {entry.Name} = {newValue}" ); // TODO - if we have a notice flag, broadcast to the game somehow } void OnTableEntryRemoved( StringTable.Entry entry ) { } void OnTableSnapshot() { _values.Clear(); foreach ( var (_, entry) in StringTable.Entries ) { OnTableEntryUpdated( entry ); } } private readonly Dictionary _values = new( StringComparer.OrdinalIgnoreCase ); /// /// Get the value of a replicated ConVar. /// public bool TryGetValue( string name, out string value ) { return _values.TryGetValue( name, out value ); } }