Client LuaCsForBarotrauma
ServerSettingsUI.cs
2 using Microsoft.Xna.Framework;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 namespace Barotrauma.Networking
8 {
9  partial class ServerSettings : ISerializableEntity
10  {
11  //GUI stuff
12  private GUIFrame settingsFrame;
13  private readonly Dictionary<SettingsTab, GUIComponent> settingsTabs = new Dictionary<SettingsTab, GUIComponent>();
14  private readonly Dictionary<SettingsTab, GUIButton> tabButtons = new Dictionary<SettingsTab, GUIButton>();
15  private SettingsTab selectedTab;
16 
17  //UI elements relating to karma, hidden when karma is disabled
18  private readonly List<GUIComponent> karmaElements = new List<GUIComponent>();
19  private GUIDropDown karmaPresetDD;
20  private GUIListBox karmaSettingsList;
21 
22  private GUIComponent extraCargoPanel, monstersEnabledPanel;
23  private GUIButton extraCargoButton, monstersEnabledButton;
24 
25  enum SettingsTab
26  {
27  ServerIdentity,
28  General,
29  Antigriefing,
30  Banlist
31  }
32 
33  public void AssignGUIComponent(string propertyName, GUIComponent component)
34  {
35  GetPropertyData(propertyName).AssignGUIComponent(component);
36  }
37 
38  public void AddToGUIUpdateList()
39  {
40  if (GUI.DisableHUD) { return; }
41 
42  settingsFrame?.AddToGUIUpdateList();
43  }
44 
45  private void CreateSettingsFrame()
46  {
47  foreach (NetPropertyData prop in netProperties.Values)
48  {
49  prop.TempValue = prop.Value;
50  }
51 
52  //background frame
53  settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), style: null);
54  new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, settingsFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
55 
56  new GUIButton(new RectTransform(Vector2.One, settingsFrame.RectTransform), "", style: null).OnClicked += (btn, userData) =>
57  {
58  if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) { ToggleSettingsFrame(btn, userData); }
59  return true;
60  };
61 
62  new GUIButton(new RectTransform(Vector2.One, settingsFrame.RectTransform), "", style: null)
63  {
64  OnClicked = ToggleSettingsFrame
65  };
66 
67  //center frames
68  GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.85f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
69  GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(innerFrame.Rect.Size - new Point(GUI.IntScale(20)), innerFrame.RectTransform, Anchor.Center),
70  childAnchor: Anchor.TopCenter)
71  {
72  Stretch = true,
73  RelativeSpacing = 0.02f
74  };
75 
76  new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), TextManager.Get("serversettingsbutton"), font: GUIStyle.LargeFont);
77 
78  var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), paddedFrame.RectTransform), isHorizontal: true)
79  {
80  Stretch = true,
81  RelativeSpacing = 0.01f
82  };
83 
84  var tabContent = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.85f), paddedFrame.RectTransform), style: "InnerFrame");
85 
86  //tabs
87  var settingsTabTypes = Enum.GetValues(typeof(SettingsTab)).Cast<SettingsTab>();
88  foreach (var settingsTab in settingsTabTypes)
89  {
90  settingsTabs[settingsTab] = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabContent.RectTransform, Anchor.Center));
91  tabButtons[settingsTab] = new GUIButton(new RectTransform(new Vector2(0.2f, 1.2f), buttonArea.RectTransform), TextManager.Get($"ServerSettings{settingsTab}Tab"), style: "GUITabButton")
92  {
93  UserData = settingsTab,
94  OnClicked = SelectSettingsTab
95  };
96  }
97  GUITextBlock.AutoScaleAndNormalize(tabButtons.Values.Select(b => b.TextBlock));
98  SelectSettingsTab(tabButtons[0], 0);
99  tabButtons[SettingsTab.Banlist].Enabled =
100  GameMain.Client.HasPermission(Networking.ClientPermissions.Ban) ||
101  GameMain.Client.HasPermission(Networking.ClientPermissions.Unban);
102 
103  //"Close"
104  var buttonContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.05f), paddedFrame.RectTransform), style: null);
105  var closeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("Close"))
106  {
107  OnClicked = ToggleSettingsFrame
108  };
109 
110  CreateServerIdentityTab(settingsTabs[SettingsTab.ServerIdentity]);
111  CreateGeneralTab(settingsTabs[SettingsTab.General]);
112  CreateAntigriefingTab(settingsTabs[SettingsTab.Antigriefing]);
113  CreateBanlistTab(settingsTabs[SettingsTab.Banlist]);
114 
115  if (GameMain.Client == null ||
116  !GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings))
117  {
118  //block all settings if the client doesn't have permission to edit them
119  foreach (var settingsTab in settingsTabs)
120  {
121  SetElementInteractability(settingsTab.Value, false);
122  }
123  }
124  //keep these enabled, so clients can open the panels and see what's enabled even if they can't edit them
125  extraCargoButton.Enabled = monstersEnabledButton.Enabled = true;
126  }
127 
128  private void SetElementInteractability(GUIComponent parent, bool interactable)
129  {
130  foreach (var child in parent.GetAllChildren<GUIComponent>())
131  {
132  child.Enabled = interactable;
133  //make the disabled color slightly less dim (these should be readable, despite being non-interactable)
134  child.DisabledColor = new Color(child.Color, child.Color.A / 255.0f * 0.8f);
135  if (child is GUITextBlock textBlock)
136  {
137  textBlock.DisabledTextColor = new Color(textBlock.TextColor, textBlock.TextColor.A / 255.0f * 0.8f);
138  }
139  }
140  }
141 
142  private void CreateServerIdentityTab(GUIComponent parent)
143  {
144  //changing server visibility on the fly is not supported in dedicated servers
145  if (GameMain.Client?.ClientPeer is not LidgrenClientPeer)
146  {
147  var isPublic = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform),
148  TextManager.Get("publicserver"))
149  {
150  ToolTip = TextManager.Get("publicservertooltip")
151  };
152  AssignGUIComponent(nameof(IsPublic), isPublic);
153  }
154 
155  var serverNameLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform), TextManager.Get("ServerName"));
156  var serverNameBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), serverNameLabel.RectTransform, Anchor.CenterRight),
157  GameMain.Client.ServerSettings.ServerName)
158  {
159  OverflowClip = true,
160  MaxTextLength = NetConfig.ServerNameMaxLength
161  };
162  serverNameBox.OnDeselected += (textBox, key) =>
163  {
164  if (textBox.Text.IsNullOrWhiteSpace())
165  {
166  textBox.Flash(GUIStyle.Red);
167  if (GameMain.Client != null)
168  {
169  textBox.Text = GameMain.Client.ServerSettings.ServerName;
170  }
171  }
172  GameMain.Client?.ServerSettings.ClientAdminWrite(NetFlags.Properties);
173  };
174  AssignGUIComponent(nameof(ServerName), serverNameBox);
175 
176  // server message *************************************************************************
177 
178  var motdHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform), TextManager.Get("ServerMOTD"));
179  var motdCharacterCount = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), motdHeader.RectTransform, Anchor.CenterRight), string.Empty, textAlignment: Alignment.CenterRight);
180  var serverMessageContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), parent.RectTransform))
181  {
182  Visible = true
183  };
184  var serverMessageBox = new GUITextBox(new RectTransform(Vector2.One, serverMessageContainer.Content.RectTransform),
185  style: "GUITextBoxNoBorder", wrap: true, textAlignment: Alignment.TopLeft)
186  {
187  MaxTextLength = NetConfig.ServerMessageMaxLength
188  };
189  var serverMessageHint = new GUITextBlock(new RectTransform(Vector2.One, serverMessageBox.RectTransform),
190  textColor: Color.DarkGray * 0.6f, textAlignment: Alignment.TopLeft, font: GUIStyle.Font, text: TextManager.Get("ClickToWriteServerMessage"));
191  AssignGUIComponent(nameof(ServerMessageText), serverMessageBox);
192 
193  void updateServerMessageScrollBasedOnCaret()
194  {
195  float caretY = serverMessageBox.CaretScreenPos.Y;
196  float bottomCaretExtent = serverMessageBox.Font.LineHeight * 1.5f;
197  float topCaretExtent = -serverMessageBox.Font.LineHeight * 0.5f;
198  if (caretY + bottomCaretExtent > serverMessageContainer.Rect.Bottom)
199  {
200  serverMessageContainer.ScrollBar.BarScroll
201  = (caretY - serverMessageBox.Rect.Top - serverMessageContainer.Rect.Height + bottomCaretExtent)
202  / (serverMessageBox.Rect.Height - serverMessageContainer.Rect.Height);
203  }
204  else if (caretY + topCaretExtent < serverMessageContainer.Rect.Top)
205  {
206  serverMessageContainer.ScrollBar.BarScroll
207  = (caretY - serverMessageBox.Rect.Top + topCaretExtent)
208  / (serverMessageBox.Rect.Height - serverMessageContainer.Rect.Height);
209  }
210  }
211  serverMessageBox.OnSelected += (textBox, key) =>
212  {
213  serverMessageHint.Visible = false;
214  updateServerMessageScrollBasedOnCaret();
215  };
216  serverMessageBox.OnTextChanged += (textBox, text) =>
217  {
218  serverMessageHint.Visible = !textBox.Selected && !textBox.Readonly && string.IsNullOrWhiteSpace(textBox.Text);
219  RefreshServerInfoSize();
220  return true;
221  };
222  serverMessageBox.RectTransform.SizeChanged += RefreshServerInfoSize;
223  motdCharacterCount.TextGetter += () => { return serverMessageBox.Text.Length + " / " + NetConfig.ServerMessageMaxLength; };
224 
225  void RefreshServerInfoSize()
226  {
227  serverMessageHint.Visible = !serverMessageBox.Selected && !serverMessageBox.Readonly && string.IsNullOrWhiteSpace(serverMessageBox.Text);
228  Vector2 textSize = serverMessageBox.Font.MeasureString(serverMessageBox.WrappedText);
229  serverMessageBox.RectTransform.NonScaledSize = new Point(serverMessageBox.RectTransform.NonScaledSize.X, Math.Max(serverMessageContainer.Content.Rect.Height, (int)textSize.Y + 10));
230  serverMessageContainer.UpdateScrollBarSize();
231  }
232 
233  serverMessageBox.OnEnterPressed += (textBox, text) =>
234  {
235  string str = textBox.Text;
236  int caretIndex = textBox.CaretIndex;
237  textBox.Text = $"{str[..caretIndex]}\n{str[caretIndex..]}";
238  textBox.CaretIndex = caretIndex + 1;
239 
240  return true;
241  };
242  serverMessageBox.OnDeselected += (textBox, key) =>
243  {
244  if (!textBox.Readonly)
245  {
246  GameMain.Client?.ServerSettings?.ClientAdminWrite(NetFlags.Properties);
247  }
248  serverMessageHint.Visible = !textBox.Readonly && string.IsNullOrWhiteSpace(textBox.Text);
249  };
250  serverMessageBox.OnKeyHit += (sender, key) => updateServerMessageScrollBasedOnCaret();
251 
252  // *************************************************************************
253 
254  var playStyleLayoutLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform),
255  TextManager.Get("ServerSettingsPlayStyle"));
256  var playStyleSelection = new GUISelectionCarousel<PlayStyle>(new RectTransform(new Vector2(0.5f, 1.0f), playStyleLayoutLabel.RectTransform, Anchor.CenterRight));
257  foreach (PlayStyle playStyle in Enum.GetValues(typeof(PlayStyle)))
258  {
259  playStyleSelection.AddElement(playStyle, TextManager.Get("servertag." + playStyle), TextManager.Get("servertagdescription." + playStyle));
260  }
261  AssignGUIComponent(nameof(PlayStyle), playStyleSelection);
262 
263  var passwordLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform), TextManager.Get("Password"));
264  new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), passwordLabel.RectTransform, Anchor.CenterRight),
265  TextManager.Get("ServerSettingsSetPassword"), style: "GUIButtonSmall")
266  {
267  OnClicked = (btn, userdata) => { CreateChangePasswordPrompt(); return true; }
268  };
269 
270  var wrongPasswordBanBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform), TextManager.Get("ServerSettingsBanAfterWrongPassword"));
271  AssignGUIComponent(nameof(BanAfterWrongPassword), wrongPasswordBanBox);
272  var allowedPasswordRetries = NetLobbyScreen.CreateLabeledNumberInput(parent, "ServerSettingsPasswordRetriesBeforeBan", 0, 10);
273  AssignGUIComponent(nameof(MaxPasswordRetriesBeforeBan), allowedPasswordRetries);
274 
275  var maxPlayers = NetLobbyScreen.CreateLabeledNumberInput(parent, "MaxPlayers", 0, NetConfig.MaxPlayers);
276  AssignGUIComponent(nameof(MaxPlayers), maxPlayers);
277 
278  // Language
279  var languageLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), parent.RectTransform), TextManager.Get("Language"));
280  var languageDD = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1.0f), languageLabel.RectTransform, Anchor.CenterRight));
281  foreach (var language in ServerLanguageOptions.Options)
282  {
283  languageDD.AddItem(language.Label, language.Identifier);
284  }
285  languageLabel.InheritTotalChildrenMinHeight();
286  AssignGUIComponent(nameof(Language), languageDD);
287 
288  }
289 
290  private static void CreateChangePasswordPrompt()
291  {
292  var passwordMsgBox = new GUIMessageBox(
293  TextManager.Get("ServerSettingsSetPassword"),
294  "", new LocalizedString[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
295  relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, GUI.IntScale(170)));
296  var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), passwordMsgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
297  var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform))
298  {
299  Censor = true
300  };
301 
302  passwordMsgBox.Content.Recalculate();
303  passwordMsgBox.Content.InheritTotalChildrenHeight();
304  passwordMsgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(passwordMsgBox.Content.RectTransform.MinSize.Y / passwordMsgBox.Content.RectTransform.RelativeSize.Y));
305 
306  var okButton = passwordMsgBox.Buttons[0];
307  okButton.OnClicked += (_, __) =>
308  {
309  DebugConsole.ExecuteCommand($"setpassword \"{passwordBox.Text}\"");
310  return true;
311  };
312  okButton.OnClicked += passwordMsgBox.Close;
313 
314  var cancelButton = passwordMsgBox.Buttons[1];
315  cancelButton.OnClicked = (_, __) =>
316  {
317  passwordMsgBox?.Close();
318  passwordMsgBox = null;
319  return true;
320  };
321  passwordBox.OnEnterPressed += (_, __) =>
322  {
323  okButton.OnClicked.Invoke(okButton, okButton.UserData);
324  return true;
325  };
326 
327  passwordBox.Select();
328  }
329 
330  private void CreateGeneralTab(GUIComponent parent)
331  {
332  var listBox = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform), style: "GUIListBoxNoBorder")
333  {
334  AutoHideScrollBar = true,
335  CurrentSelectMode = GUIListBox.SelectMode.None
336  };
337 
338  NetLobbyScreen.CreateSubHeader("serversettingscategory.roundmanagement", listBox.Content);
339 
340  var endVoteBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
341  TextManager.Get("ServerSettingsEndRoundVoting"));
342  AssignGUIComponent(nameof(AllowEndVoting), endVoteBox);
343 
344  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: "ServerSettingsEndRoundVotesRequired", tooltipTag: string.Empty, out var slider, out var sliderLabel);
345 
346  LocalizedString endRoundLabel = sliderLabel.Text;
347  slider.Step = 0.2f;
348  slider.Range = new Vector2(0.5f, 1.0f);
349  AssignGUIComponent(nameof(EndVoteRequiredRatio), slider);
350  slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
351  {
352  ((GUITextBlock)scrollBar.UserData).Text = endRoundLabel + " " + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
353  return true;
354  };
355  slider.OnMoved(slider, slider.BarScroll);
356 
357  //***********************************************
358 
359  // Sub Selection
360 
361  var subSelectionLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
362  TextManager.Get("ServerSettingsSubSelection"));
363  var subSelection = new GUISelectionCarousel<SelectionMode>(new RectTransform(new Vector2(0.5f, 1.0f), subSelectionLabel.RectTransform, Anchor.CenterRight));
364  foreach (SelectionMode selectionMode in Enum.GetValues(typeof(SelectionMode)))
365  {
366  subSelection.AddElement(selectionMode, TextManager.Get(selectionMode.ToString()));
367  }
368  AssignGUIComponent(nameof(SubSelectionMode), subSelection);
369 
370  // Mode Selection
371  var gameModeSelectionLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
372  TextManager.Get("ServerSettingsModeSelection"));
373  var gameModeSelection = new GUISelectionCarousel<SelectionMode>(new RectTransform(new Vector2(0.5f, 1.0f), gameModeSelectionLabel.RectTransform, Anchor.CenterRight));
374  foreach (SelectionMode selectionMode in Enum.GetValues(typeof(SelectionMode)))
375  {
376  gameModeSelection.AddElement(selectionMode, TextManager.Get(selectionMode.ToString()));
377  }
378  AssignGUIComponent(nameof(ModeSelectionMode), gameModeSelection);
379 
380  //***********************************************
381 
382  LocalizedString autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay") + " ";
383 
384  var autorestartBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
385  TextManager.Get("AutoRestart"));
386  AssignGUIComponent(nameof(AutoRestart), autorestartBox);
387  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: string.Empty, tooltipTag: string.Empty,
388  out var startIntervalSlider, out var startIntervalSliderLabel, range: new Vector2(10.0f, 300.0f));
389  startIntervalSlider.StepValue = 10.0f;
390  startIntervalSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
391  {
392  GUITextBlock text = scrollBar.UserData as GUITextBlock;
393  text.Text = autoRestartDelayLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
394  return true;
395  };
396  AssignGUIComponent(nameof(AutoRestartInterval), startIntervalSlider);
397  startIntervalSlider.OnMoved(startIntervalSlider, startIntervalSlider.BarScroll);
398 
399  //***********************************************
400 
401  var startWhenClientsReady = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
402  TextManager.Get("ServerSettingsStartWhenClientsReady"));
403  AssignGUIComponent(nameof(StartWhenClientsReady), startWhenClientsReady);
404 
405  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: "ServerSettingsStartWhenClientsReadyRatio", tooltipTag: string.Empty,
406  out slider, out sliderLabel);
407  LocalizedString clientsReadyRequiredLabel = sliderLabel.Text;
408  slider.Step = 0.2f;
409  slider.Range = new Vector2(0.5f, 1.0f);
410  slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
411  {
412  ((GUITextBlock)scrollBar.UserData).Text = clientsReadyRequiredLabel.Replace("[percentage]", ((int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f)).ToString());
413  return true;
414  };
416  slider.OnMoved(slider, slider.BarScroll);
417 
418  var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
419  AssignGUIComponent(nameof(RandomizeSeed), randomizeLevelBox);
420 
421  // ******* PVP ********************************
422  NetLobbyScreen.CreateSubHeader("gamemode.pvp", listBox.Content);
423 
424  var teamSelectModeLabel = new GUITextBlock(
425  new RectTransform(new Vector2(1.0f, 0.05f),
426  listBox.Content.RectTransform),
427  TextManager.Get("TeamSelectionMode"));
428  teamSelectModeLabel.ToolTip = TextManager.Get("TeamSelectionMode.tooltip");
429  var teamSelectionMode = new GUISelectionCarousel<PvpTeamSelectionMode>(
430  new RectTransform(new Vector2(0.5f, 0.6f),
431  teamSelectModeLabel.RectTransform,
432  Anchor.CenterRight));
433  foreach (PvpTeamSelectionMode teamSelectionModeOption in Enum.GetValues(typeof(PvpTeamSelectionMode)))
434  {
435  var optionName = teamSelectionModeOption.ToString();
436  teamSelectionMode.AddElement(teamSelectionModeOption,
437  TextManager.Get($"TeamSelectionMode.{optionName}"),
438  TextManager.Get($"TeamSelectionMode.{optionName}.tooltip"));
439  }
440  AssignGUIComponent(nameof(PvpTeamSelectionMode), teamSelectionMode);
441 
442  var autoBalanceThresholdLabel = new GUITextBlock(
443  new RectTransform(new Vector2(1.0f, 0.05f),
444  listBox.Content.RectTransform),
445  TextManager.Get("AutoBalanceThreshold"));
446  var autoBalanceThresholdTooltip = TextManager.Get("AutoBalanceThreshold.tooltip");
447  autoBalanceThresholdLabel.ToolTip = autoBalanceThresholdTooltip;
448  var autoBalanceThreshold = new GUISelectionCarousel<int>(
449  new RectTransform(new Vector2(0.5f, 0.6f),
450  autoBalanceThresholdLabel.RectTransform,
451  Anchor.CenterRight));
452  autoBalanceThreshold.AddElement(0, TextManager.Get($"AutoBalanceThreshold.Off"), autoBalanceThresholdTooltip);
453  autoBalanceThreshold.AddElement(1, "1", autoBalanceThresholdTooltip);
454  autoBalanceThreshold.AddElement(2, "2", autoBalanceThresholdTooltip);
455  autoBalanceThreshold.AddElement(3, "3", autoBalanceThresholdTooltip);
456  AssignGUIComponent(nameof(PvpAutoBalanceThreshold), autoBalanceThreshold);
457 
458  // ******* GAMEPLAY ***************************
459  NetLobbyScreen.CreateSubHeader("serversettingsroundstab", listBox.Content);
460 
461  var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
462  TextManager.Get("ServerSettingsVoiceChatEnabled"));
463  AssignGUIComponent(nameof(VoiceChatEnabled), voiceChatEnabled);
464 
465  var allowSpecBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsAllowSpectating"));
466  AssignGUIComponent(nameof(AllowSpectating), allowSpecBox);
467 
468  var losModeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
469  TextManager.Get("LosEffect"));
470  var losModeSelection = new GUISelectionCarousel<LosMode>(new RectTransform(new Vector2(0.5f, 0.6f), losModeLabel.RectTransform, Anchor.CenterRight));
471  foreach (var losMode in Enum.GetValues(typeof(LosMode)).Cast<LosMode>())
472  {
473  losModeSelection.AddElement(losMode, TextManager.Get($"LosMode{losMode}"), TextManager.Get($"LosMode{losMode}.tooltip"));
474  }
475  AssignGUIComponent(nameof(LosMode), losModeSelection);
476 
477  var healthBarModeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
478  TextManager.Get("ShowEnemyHealthBars"));
479  var healthBarModeSelection = new GUISelectionCarousel<EnemyHealthBarMode>(new RectTransform(new Vector2(0.5f, 0.6f), healthBarModeLabel.RectTransform, Anchor.CenterRight));
480  foreach (var healthBarMode in Enum.GetValues(typeof(EnemyHealthBarMode)).Cast<EnemyHealthBarMode>())
481  {
482  healthBarModeSelection.AddElement(healthBarMode, TextManager.Get($"ShowEnemyHealthBars.{healthBarMode}"));
483  }
484  AssignGUIComponent(nameof(ShowEnemyHealthBars), healthBarModeSelection);
485 
486  var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
487  AssignGUIComponent(nameof(DisableBotConversations), disableBotConversationsBox);
488 
489  //***********************************************
490 
491  NetLobbyScreen.CreateSubHeader("serversettingscategory.misc", listBox.Content);
492 
493  var shareSubsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsShareSubFiles"));
494  AssignGUIComponent(nameof(AllowFileTransfers), shareSubsBox);
495 
496  var saveLogsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsSaveLogs"))
497  {
498  OnSelected = (GUITickBox) =>
499  {
500  //TODO: fix?
501  //showLogButton.Visible = SaveServerLogs;
502  return true;
503  }
504  };
505  AssignGUIComponent(nameof(SaveServerLogs), saveLogsBox);
506 
507  LocalizedString newCampaignDefaultSalaryLabel = TextManager.Get("ServerSettingsNewCampaignDefaultSalary");
508  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: "ServerSettingsNewCampaignDefaultSalary", valueLabelTag: "ServerSettingsKickVotesRequired", tooltipTag: "ServerSettingsNewCampaignDefaultSalaryToolTip",
509  out var defaultSalarySlider, out var defaultSalarySliderLabel);
510  defaultSalarySlider.Range = new Vector2(0, 100);
511  defaultSalarySlider.StepValue = 1;
512  defaultSalarySlider.OnMoved = (scrollBar, _) =>
513  {
514  if (scrollBar.UserData is not GUITextBlock text) { return false; }
515  text.Text = TextManager.AddPunctuation(
516  ':',
517  newCampaignDefaultSalaryLabel,
518  TextManager.GetWithVariable("percentageformat", "[value]", ((int)Math.Round(scrollBar.BarScrollValue, digits: 0)).ToString()));
519  return true;
520  };
521  AssignGUIComponent(nameof(NewCampaignDefaultSalary), defaultSalarySlider);
522  defaultSalarySlider.OnMoved(defaultSalarySlider, defaultSalarySlider.BarScroll);
523 
524  var pvpDisembarkPoints = NetLobbyScreen.CreateLabeledNumberInput(listBox.Content, "serversettingsdisembarkpoints", 0, 100, "serversettingsdisembarkpointstooltip");
525  AssignGUIComponent(nameof(DisembarkPointAllowance), pvpDisembarkPoints);
526 
527  //--------------------------------------------------------------------------------
528  // game settings
529  //--------------------------------------------------------------------------------
530 
531  GUILayoutGroup buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), listBox.Content.RectTransform), isHorizontal: true, childAnchor: Anchor.BottomLeft)
532  {
533  Stretch = true,
534  RelativeSpacing = 0.05f
535  };
536 
537  const string MonstersEnabledUserdata = "monstersenabled";
538  const string ExtraCargoUserdata = "extracargo";
539 
540  monstersEnabledButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonHolder.RectTransform),
541  TextManager.Get("ServerSettingsMonsterSpawns"), style: "GUIButtonSmall")
542  {
543  Enabled = !GameMain.NetworkMember.GameStarted
544  };
545  monstersEnabledPanel = CreateMonstersEnabledPanel();
546  monstersEnabledButton.UserData = MonstersEnabledUserdata;
547  monstersEnabledButton.OnClicked = ExtraSettingsButtonClicked;
548 
549  extraCargoButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonHolder.RectTransform),
550  TextManager.Get("ServerSettingsAdditionalCargo"), style: "GUIButtonSmall")
551  {
552  Enabled = !GameMain.NetworkMember.GameStarted
553  };
554 
555  extraCargoPanel = CreateExtraCargoPanel();
556  extraCargoButton.UserData = ExtraCargoUserdata;
557  extraCargoButton.OnClicked = ExtraSettingsButtonClicked;
558 
559  GUITextBlock.AutoScaleAndNormalize(buttonHolder.Children.Select(c => ((GUIButton)c).TextBlock));
560 
561  bool ExtraSettingsButtonClicked(GUIButton button, object obj)
562  {
563  //the extra settings buttons (monsters enabled, cargo) hold a reference to the panel they're supposed to toggle
564  GUIComponent panel;
565  switch (obj as string)
566  {
567  case MonstersEnabledUserdata:
568  panel = monstersEnabledPanel;
569  break;
570  case ExtraCargoUserdata:
571  panel = extraCargoPanel;
572  break;
573  default:
574  throw new Exception("Unrecognized extra settings button");
575  }
576  if (GameMain.NetworkMember.GameStarted)
577  {
578  panel.Visible = false;
579  button.Enabled = false;
580  return true;
581  }
582  panel.Visible = !panel.Visible;
583  return true;
584  }
585  }
586 
587  private GUIComponent CreateMonstersEnabledPanel()
588  {
589  var monsterFrame = new GUIListBox(new RectTransform(new Vector2(0.5f, 0.7f), settingsTabs[SettingsTab.General].RectTransform, Anchor.BottomLeft, Pivot.BottomRight))
590  {
591  Visible = false,
592  IgnoreLayoutGroups = true
593  };
594 
595  InitMonstersEnabled();
596  List<Identifier> monsterNames = MonsterEnabled.Keys.ToList();
597  tempMonsterEnabled = new Dictionary<Identifier, bool>(MonsterEnabled);
598  foreach (Identifier s in monsterNames)
599  {
600  LocalizedString translatedLabel = TextManager.Get($"Character.{s}").Fallback(s.Value);
601  var monsterEnabledBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), monsterFrame.Content.RectTransform) { MinSize = new Point(0, 25) },
602  label: translatedLabel)
603  {
604  Selected = tempMonsterEnabled[s],
605  OnSelected = (GUITickBox tb) =>
606  {
607  tempMonsterEnabled[s] = tb.Selected;
608  return true;
609  }
610  };
611  }
612  monsterFrame.Content.RectTransform.SortChildren((c1, c2) =>
613  {
614  var name1 = (c1.GUIComponent as GUITickBox)?.Text ?? string.Empty;
615  var name2 = (c2.GUIComponent as GUITickBox)?.Text ?? string.Empty;
616  return name1.CompareTo(name2);
617  });
618 
619  if (GameMain.Client == null ||
620  !GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings))
621  {
622  SetElementInteractability(monsterFrame.Content, false);
623  }
624 
625  return monsterFrame;
626  }
627 
628  private GUIComponent CreateExtraCargoPanel()
629  {
630  var cargoFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.7f), settingsTabs[SettingsTab.General].RectTransform, Anchor.BottomRight, Pivot.BottomLeft))
631  {
632  Visible = false,
633  IgnoreLayoutGroups = true
634  };
635  var cargoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), cargoFrame.RectTransform, Anchor.Center))
636  {
637  Stretch = true
638  };
639 
640  var filterText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), cargoContent.RectTransform), TextManager.Get("serverlog.filter"), font: GUIStyle.SubHeadingFont);
641  var entityFilterBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), filterText.RectTransform, Anchor.CenterRight), font: GUIStyle.Font, createClearButton: true);
642  filterText.RectTransform.MinSize = new Point(0, entityFilterBox.RectTransform.MinSize.Y);
643  var cargoList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), cargoContent.RectTransform));
644  entityFilterBox.OnTextChanged += (textBox, text) =>
645  {
646  foreach (var child in cargoList.Content.Children)
647  {
648  if (child.UserData is not ItemPrefab itemPrefab) { continue; }
649  child.Visible = string.IsNullOrEmpty(text) || itemPrefab.Name.Contains(text, StringComparison.OrdinalIgnoreCase);
650  }
651  return true;
652  };
653 
654  foreach (ItemPrefab ip in ItemPrefab.Prefabs.OrderBy(ip => ip.Name))
655  {
656  if (ip.AllowAsExtraCargo.HasValue)
657  {
658  if (!ip.AllowAsExtraCargo.Value) { continue; }
659  }
660  else
661  {
662  if (!ip.CanBeBought) { continue; }
663  }
664 
665  var itemFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), cargoList.Content.RectTransform) { MinSize = new Point(0, 30) }, isHorizontal: true)
666  {
667  Stretch = true,
668  UserData = ip,
669  RelativeSpacing = 0.05f
670  };
671 
672  if (ip.InventoryIcon != null || ip.Sprite != null)
673  {
674  GUIImage img = new GUIImage(new RectTransform(new Point(itemFrame.Rect.Height), itemFrame.RectTransform),
675  ip.InventoryIcon ?? ip.Sprite, scaleToFit: true)
676  {
677  CanBeFocused = false
678  };
679  img.Color = img.Sprite == ip.InventoryIcon ? ip.InventoryIconColor : ip.SpriteColor;
680  }
681 
682  new GUITextBlock(new RectTransform(new Vector2(0.75f, 1.0f), itemFrame.RectTransform),
683  ip.Name, font: GUIStyle.SmallFont)
684  {
685  Wrap = true,
686  CanBeFocused = false
687  };
688 
689  ExtraCargo.TryGetValue(ip, out int cargoVal);
690  var amountInput = new GUINumberInput(new RectTransform(new Vector2(0.35f, 1.0f), itemFrame.RectTransform),
691  NumberType.Int, textAlignment: Alignment.CenterLeft)
692  {
693  MinValueInt = 0,
694  MaxValueInt = MaxExtraCargoItemsOfType,
695  IntValue = cargoVal
696  };
697  amountInput.OnValueChanged += (numberInput) =>
698  {
699  if (ExtraCargo.ContainsKey(ip))
700  {
701  ExtraCargo[ip] = numberInput.IntValue;
702  if (numberInput.IntValue <= 0) { ExtraCargo.Remove(ip); }
703  }
704  else if (ExtraCargo.Keys.Count < MaxExtraCargoItemTypes)
705  {
706  ExtraCargo.Add(ip, numberInput.IntValue);
707  }
708  numberInput.IntValue = ExtraCargo.ContainsKey(ip) ? ExtraCargo[ip] : 0;
709  CoroutineManager.Invoke(() =>
710  {
711  foreach (var child in cargoList.Content.GetAllChildren())
712  {
713  if (child.GetChild<GUINumberInput>() is GUINumberInput otherNumberInput)
714  {
715  otherNumberInput.PlusButton.Enabled = ExtraCargo.Keys.Count < MaxExtraCargoItemTypes && otherNumberInput.IntValue < otherNumberInput.MaxValueInt;
716  }
717  }
718  }, 0.0f);
719  };
720  }
721  if (GameMain.Client == null ||
722  !GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings))
723  {
724  SetElementInteractability(cargoList.Content, false);
725  }
726 
727  return cargoFrame;
728  }
729 
730  private void CreateAntigriefingTab(GUIComponent parent)
731  {
732  var listBox = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform), style: "GUIListBoxNoBorder")
733  {
734  AutoHideScrollBar = true,
735  CurrentSelectMode = GUIListBox.SelectMode.None
736  };
737 
738  //--------------------------------------------------------------------------------
739  // antigriefing
740  //--------------------------------------------------------------------------------
741 
742  var tickBoxContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.268f), listBox.Content.RectTransform))
743  {
744  AutoHideScrollBar = true,
745  UseGridLayout = true
746  };
747  tickBoxContainer.Padding *= 2.0f;
748 
749  var allowFriendlyFire = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
750  TextManager.Get("ServerSettingsAllowFriendlyFire"));
751  AssignGUIComponent(nameof(AllowFriendlyFire), allowFriendlyFire);
752 
753  var allowDragAndDropGive = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
754  TextManager.Get("ServerSettingsAllowDragAndDropGive"));
755  AssignGUIComponent(nameof(AllowDragAndDropGive), allowDragAndDropGive);
756 
757  var killableNPCs = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
758  TextManager.Get("ServerSettingsKillableNPCs"));
759  AssignGUIComponent(nameof(KillableNPCs), killableNPCs);
760 
761  var destructibleOutposts = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
762  TextManager.Get("ServerSettingsDestructibleOutposts"));
763  AssignGUIComponent(nameof(DestructibleOutposts), destructibleOutposts);
764 
765  var lockAllDefaultWires = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
766  TextManager.Get("ServerSettingsLockAllDefaultWires"));
767  AssignGUIComponent(nameof(LockAllDefaultWires), lockAllDefaultWires);
768 
769  var allowRewiring = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
770  TextManager.Get("ServerSettingsAllowRewiring"));
771  AssignGUIComponent(nameof(AllowRewiring), allowRewiring);
772 
773  var allowWifiChatter = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
774  TextManager.Get("ServerSettingsAllowWifiChat"));
775  AssignGUIComponent(nameof(AllowLinkingWifiToChat), allowWifiChatter);
776 
777  var allowDisguises = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
778  TextManager.Get("ServerSettingsAllowDisguises"));
779  AssignGUIComponent(nameof(AllowDisguises), allowDisguises);
780 
781  var allowImmediateItemDeliveryBox = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
782  TextManager.Get("ServerSettingsImmediateItemDelivery"));
783  AssignGUIComponent(nameof(AllowImmediateItemDelivery), allowImmediateItemDeliveryBox);
784 
785  GUITextBlock.AutoScaleAndNormalize(tickBoxContainer.Content.Children.Select(c => ((GUITickBox)c).TextBlock));
786 
787  tickBoxContainer.RectTransform.MinSize = new Point(0, (int)(tickBoxContainer.Content.Children.First().Rect.Height * 2.0f + tickBoxContainer.Padding.Y + tickBoxContainer.Padding.W));
788 
789  tickBoxContainer.RectTransform.MinSize = new Point(0, (int)(tickBoxContainer.Content.Children.First().Rect.Height * 2.0f + tickBoxContainer.Padding.Y + tickBoxContainer.Padding.W));
790 
791  var voteKickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform),
792  TextManager.Get("ServerSettingsAllowVoteKick"));
793  AssignGUIComponent(nameof(AllowVoteKick), voteKickBox);
794 
795  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: "ServerSettingsKickVotesRequired", tooltipTag: string.Empty, out var slider, out var sliderLabel);
796  LocalizedString votesRequiredLabel = sliderLabel.Text + " ";
797  slider.Step = 0.2f;
798  slider.Range = new Vector2(0.5f, 1.0f);
799  slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
800  {
801  ((GUITextBlock)scrollBar.UserData).Text = votesRequiredLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
802  return true;
803  };
804  AssignGUIComponent(nameof(KickVoteRequiredRatio), slider);
805  slider.OnMoved(slider, slider.BarScroll);
806 
807  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: "ServerSettingsAutobanTime", tooltipTag: "ServerSettingsAutobanTime.Tooltip", out slider, out sliderLabel);
808  LocalizedString autobanLabel = sliderLabel.Text + " ";
809  slider.Range = new Vector2(0.0f, MaxAutoBanTime);
810  slider.StepValue = 60.0f * 15.0f; //15 minutes
811  slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
812  {
813  ((GUITextBlock)scrollBar.UserData).Text = autobanLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
814  return true;
815  };
816  AssignGUIComponent(nameof(AutoBanTime), slider);
817  slider.OnMoved(slider, slider.BarScroll);
818 
819  var maximumTransferAmount = NetLobbyScreen.CreateLabeledNumberInput(listBox.Content, "serversettingsmaximumtransferrequest", 0, CampaignMode.MaxMoney, "serversettingsmaximumtransferrequesttooltip");
820  AssignGUIComponent(nameof(MaximumMoneyTransferRequest), maximumTransferAmount);
821 
822  var lootedMoneyDestination = NetLobbyScreen.CreateLabeledDropdown(listBox.Content, "serversettingslootedmoneydestination", numElements: 2, "serversettingslootedmoneydestinationtooltip");
823  lootedMoneyDestination.AddItem(TextManager.Get("lootedmoneydestination.bank"), LootedMoneyDestination.Bank);
824  lootedMoneyDestination.AddItem(TextManager.Get("lootedmoneydestination.wallet"), LootedMoneyDestination.Wallet);
825  AssignGUIComponent(nameof(LootedMoneyDestination), lootedMoneyDestination);
826 
827  var enableDosProtection = new GUITickBox(new RectTransform(new Vector2(0.5f, 0.0f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsEnableDoSProtection"))
828  {
829  ToolTip = TextManager.Get("ServerSettingsEnableDoSProtectionTooltip")
830  };
831  AssignGUIComponent(nameof(EnableDoSProtection), enableDosProtection);
832 
833  NetLobbyScreen.CreateLabeledSlider(listBox.Content, headerTag: string.Empty, valueLabelTag: "ServerSettingsMaxPacketAmount", tooltipTag: string.Empty, out GUIScrollBar maxPacketSlider, out GUITextBlock maxPacketSliderLabel);
834  LocalizedString maxPacketCountLabel = maxPacketSliderLabel.Text;
835  maxPacketSlider.Step = 0.001f;
836  maxPacketSlider.Range = new Vector2(PacketLimitMin, PacketLimitMax);
837  maxPacketSlider.ToolTip = packetAmountTooltip;
838  maxPacketSlider.OnMoved = (scrollBar, _) =>
839  {
840  GUITextBlock textBlock = (GUITextBlock)scrollBar.UserData;
841  int value = (int)MathF.Floor(scrollBar.BarScrollValue);
842 
843  LocalizedString valueText = value > PacketLimitMin
844  ? value.ToString()
845  : TextManager.Get("ServerSettingsNoLimit");
846 
847  switch (value)
848  {
849  case <= PacketLimitMin:
850  textBlock.TextColor = GUIStyle.Green;
851  scrollBar.ToolTip = packetAmountTooltip;
852  break;
853  case < PacketLimitWarning:
854  textBlock.TextColor = GUIStyle.Red;
855  scrollBar.ToolTip = packetAmountTooltipWarning;
856  break;
857  default:
858  textBlock.TextColor = GUIStyle.TextColorNormal;
859  scrollBar.ToolTip = packetAmountTooltip;
860  break;
861  }
862 
863  textBlock.Text = $"{maxPacketCountLabel} {valueText}";
864  return true;
865  };
866  AssignGUIComponent(nameof(MaxPacketAmount), maxPacketSlider);
867  maxPacketSlider.OnMoved(maxPacketSlider, maxPacketSlider.BarScroll);
868 
869  // karma --------------------------------------------------------------------------
870 
871  NetLobbyScreen.CreateSubHeader("Karma", listBox.Content, toolTipTag: "KarmaExplanation");
872 
873  var karmaBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1f), listBox.Content.RectTransform), TextManager.Get("ServerSettingsUseKarma"))
874  {
875  ToolTip = TextManager.Get("KarmaExplanation")
876  };
877  AssignGUIComponent(nameof(KarmaEnabled), karmaBox);
878 
879  karmaPresetDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), listBox.Content.RectTransform));
880  foreach (string karmaPreset in GameMain.NetworkMember.KarmaManager.Presets.Keys)
881  {
882  karmaPresetDD.AddItem(TextManager.Get("KarmaPreset." + karmaPreset), karmaPreset);
883  }
884  karmaElements.Add(karmaPresetDD);
885 
886  var karmaSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), listBox.Content.RectTransform), style: null);
887  karmaElements.Add(karmaSettingsContainer);
888  karmaSettingsList = new GUIListBox(new RectTransform(Vector2.One, karmaSettingsContainer.RectTransform))
889  {
890  Spacing = (int)(8 * GUI.Scale)
891  };
892  karmaSettingsList.Padding *= 2.0f;
893 
894  karmaPresetDD.SelectItem(KarmaPreset);
895  SetElementInteractability(karmaSettingsList.Content, !karmaBox.Selected || KarmaPreset != "custom");
896  GameMain.NetworkMember.KarmaManager.CreateSettingsFrame(karmaSettingsList.Content);
897  karmaPresetDD.OnSelected = (selected, obj) =>
898  {
899  string newKarmaPreset = obj as string;
900  if (newKarmaPreset == KarmaPreset) { return true; }
901 
902  List<NetPropertyData> properties = netProperties.Values.ToList();
903  List<object> prevValues = new List<object>();
904  foreach (NetPropertyData prop in netProperties.Values)
905  {
906  prevValues.Add(prop.TempValue);
907  if (prop.GUIComponent != null) { prop.Value = prop.GUIComponentValue; }
908  }
909  if (KarmaPreset == "custom")
910  {
911  GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
912  GameMain.NetworkMember?.KarmaManager?.Save();
913  }
914  KarmaPreset = newKarmaPreset;
915  GameMain.NetworkMember.KarmaManager.SelectPreset(KarmaPreset);
916  karmaSettingsList.Content.ClearChildren();
917  GameMain.NetworkMember.KarmaManager.CreateSettingsFrame(karmaSettingsList.Content);
918  SetElementInteractability(karmaSettingsList.Content, !karmaBox.Selected || KarmaPreset != "custom");
919  for (int i = 0; i < netProperties.Count; i++)
920  {
921  properties[i].TempValue = prevValues[i];
922  }
923  return true;
924  };
925  AssignGUIComponent(nameof(KarmaPreset), karmaPresetDD);
926  karmaBox.OnSelected = (tb) =>
927  {
928  SetElementInteractability(karmaSettingsList.Content, !karmaBox.Selected || KarmaPreset != "custom");
929  karmaElements.ForEach(e => e.Visible = tb.Selected);
930  return true;
931  };
932  karmaElements.ForEach(e => e.Visible = KarmaEnabled);
933 
934  listBox.Content.InheritTotalChildrenMinHeight();
935  }
936 
937  private void CreateBanlistTab(GUIComponent parent)
938  {
939  BanList.CreateBanFrame(parent);
940  }
941 
942  private bool SelectSettingsTab(GUIButton button, object obj)
943  {
944  selectedTab = (SettingsTab)obj;
945  foreach (var key in settingsTabs.Keys)
946  {
947  settingsTabs[key].Visible = key == selectedTab;
948  tabButtons[key].Selected = key == selectedTab;
949  }
950  return true;
951  }
952 
953  public void Close()
954  {
955  if (KarmaPreset == "custom")
956  {
957  GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
958  GameMain.NetworkMember?.KarmaManager?.Save();
959  }
960  ClientAdminWrite(NetFlags.Properties);
961  foreach (NetPropertyData prop in netProperties.Values)
962  {
963  prop.GUIComponent = null;
964  }
965  settingsFrame = null;
966  //give control of server settings back to elements in the lobby
968  }
969 
970  public bool ToggleSettingsFrame(GUIButton button, object obj)
971  {
972  if (GameMain.NetworkMember == null) { return false; }
973  if (settingsFrame == null)
974  {
975  CreateSettingsFrame();
976  }
977  else
978  {
979  Close();
980  }
981  return false;
982  }
983  }
984 }
OnClickedHandler OnClicked
Definition: GUIButton.cs:16
static NetLobbyScreen NetLobbyScreen
Definition: GameMain.cs:55
static NetworkMember NetworkMember
Definition: GameMain.cs:190
bool ToggleSettingsFrame(GUIButton button, object obj)
void ClientAdminWrite(NetFlags dataToSend, Identifier addedMissionType=default, Identifier removedMissionType=default, int traitorDangerLevel=0)
void AssignGUIComponent(string propertyName, GUIComponent component)
NumberType
Definition: Enums.cs:741