bbc4a31...e6715d6

commit e6715d605db9bb1d608e4a4990ac41f6214f61d1
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 5 17:22:31 2019 +0200

    Fixed the "control" console command not being usable by clients, changed the way arguments are given to the "setclientcharacter" command (no semicolon to separate the names, quotation marks have to be used for multi-word names just like with any other command). Closes #1224

commit acb7c1e0dc05bf619e7ec4875196cc45647d3fb4
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 5 16:30:38 2019 +0200

    Steam Workshop fixes:
    - Install content packages for items that only contain a sub. Otherwise the system can't determine if the item has been updated (and might also be useful for toggling off incompatible subs when switching from mod to another).
    - Log an error instead of crashing the game if CheckWorkshopItemEnabled or CheckWorkshopItemUpToDate fails due to a missing filelist.xml.
    - Show a messagebox when a workshop item is updated succesfully.

commit b2e8ed565bc03f466930799268c13b2fca4bb9c9
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 5 14:43:42 2019 +0200

    Fixed nullref exception when disabling a workshop item that doesn't have an update button (or when enabling the item fails)

commit 26f1f285cd80ca6f023b12e6dd80dc71e87ee9c3
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 5 14:15:14 2019 +0200

    Fixed console command aliases not being taken into account in GameClient.HasConsoleCommandPermission (meaning that the client needed a permission for each name variant of a command, making it impossible to for example use "fixwalls" instead of "fixhulls"). Closes #1225

commit dee02de681a212efd0e0a82c14619f3fe4839cc4
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 5 13:35:48 2019 +0200

    Fixed traitor rounds failing to start if there's no owner client, fixed occasional "traitorCount somehow ended up less than 1" errors due to Rand.Int using 0 as the minimum value. Closes #1217
This commit is contained in:
Joonas Rikkonen
2019-03-18 22:30:27 +02:00
parent a9d8c14b05
commit b48aa89004
18 changed files with 493 additions and 237 deletions
@@ -1233,6 +1233,189 @@ namespace Barotrauma
TextManager.WriteToCSV();
NPCConversation.WriteToCSV();
}));
#endif
commands.Add(new Command("cleanbuild", "", (string[] args) =>
{
GameMain.Config.MusicVolume = 0.5f;
GameMain.Config.SoundVolume = 0.5f;
NewMessage("Music and sound volume set to 0.5", Color.Green);
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
{
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out defaultZoom);
float zoomSmoothness = Screen.Selected.Cam.ZoomSmoothness;
if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out zoomSmoothness);
float moveSmoothness = Screen.Selected.Cam.MoveSmoothness;
if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out moveSmoothness);
float minZoom = Screen.Selected.Cam.MinZoom;
if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out minZoom);
float maxZoom = Screen.Selected.Cam.MaxZoom;
if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out maxZoom);
Screen.Selected.Cam.DefaultZoom = defaultZoom;
Screen.Selected.Cam.ZoomSmoothness = zoomSmoothness;
Screen.Selected.Cam.MoveSmoothness = moveSmoothness;
Screen.Selected.Cam.MinZoom = minZoom;
Screen.Selected.Cam.MaxZoom = maxZoom;
}));
commands.Add(new Command("waterparams", "waterparams [distortionscalex] [distortionscaley] [distortionstrengthx] [distortionstrengthy] [bluramount]: default 0.5 0.5 0.5 0.5 1", (string[] args) =>
{
float distortScaleX = 0.5f, distortScaleY = 0.5f;
float distortStrengthX = 0.5f, distortStrengthY = 0.5f;
float blurAmount = 0.0f;
if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleX);
if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleY);
if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthX);
if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthY);
if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out blurAmount);
WaterRenderer.DistortionScale = new Vector2(distortScaleX, distortScaleY);
WaterRenderer.DistortionStrength = new Vector2(distortStrengthX, distortStrengthY);
WaterRenderer.BlurAmount = blurAmount;
}));
commands.Add(new Command("refreshrect", "Updates the dimensions of the selected items to match the ones defined in the prefab. Applied only in the subeditor.", (string[] args) =>
{
//TODO: maybe do this automatically during loading when possible?
if (Screen.Selected == GameMain.SubEditorScreen)
{
if (!MapEntity.SelectedAny)
{
ThrowError("You have to select item(s) first!");
}
else
{
foreach (var mapEntity in MapEntity.SelectedList)
{
if (mapEntity is Item item)
{
item.Rect = new Rectangle(item.Rect.X, item.Rect.Y,
(int)(item.Prefab.sprite.size.X * item.Prefab.Scale),
(int)(item.Prefab.sprite.size.Y * item.Prefab.Scale));
}
else if (mapEntity is Structure structure)
{
if (!structure.ResizeHorizontal)
{
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
(int)structure.Prefab.ScaledSize.X,
structure.Rect.Height);
}
if (!structure.ResizeVertical)
{
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
structure.Rect.Width,
(int)structure.Prefab.ScaledSize.Y);
}
}
}
}
}
}, isCheat: false));
#endif
GameMain.Config.SaveNewPlayerConfig();
commands.Add(new Command("loadtexts", "loadtexts [sourcefile] [destinationfile]: Loads all lines of text from a given .txt file and inserts them sequientially into the elements of an xml file. If the file paths are omitted, EnglishVanilla.txt and EnglishVanilla.xml are used.", (string[] args) =>
{
string sourcePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.txt";
string destinationPath = args.Length > 1 ? args[1] : "Content/Texts/EnglishVanilla.xml";
string[] lines;
try
{
lines = File.ReadAllLines(sourcePath);
}
catch (Exception e)
{
ThrowError("Reading the file \"" + sourcePath + "\" failed.", e);
return;
}
var doc = XMLExtensions.TryLoadXml(destinationPath);
int i = 0;
foreach (XElement element in doc.Root.Elements())
{
if (i >= lines.Length)
{
ThrowError("Error while loading texts to the xml file. The xml has more elements than the number of lines in the text file.");
return;
}
element.Value = lines[i];
i++;
}
doc.Save(destinationPath);
},
() =>
{
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
return new string[][]
{
files.Where(f => Path.GetExtension(f)==".txt").ToArray(),
files.Where(f => Path.GetExtension(f)==".xml").ToArray()
};
}));
commands.Add(new Command("updatetextfile", "updatetextfile [sourcefile] [destinationfile]: Inserts all the xml elements that are only present in the source file into the destination file. Can be used to update outdated translation files more easily.", (string[] args) =>
{
if (args.Length < 2) return;
string sourcePath = args[0];
string destinationPath = args[1];
var sourceDoc = XMLExtensions.TryLoadXml(sourcePath);
var destinationDoc = XMLExtensions.TryLoadXml(destinationPath);
XElement destinationElement = destinationDoc.Root.Elements().First();
foreach (XElement element in sourceDoc.Root.Elements())
{
if (destinationDoc.Root.Element(element.Name) == null)
{
element.Value = "!!!!!!!!!!!!!" + element.Value;
destinationElement.AddAfterSelf(element);
}
XNode nextNode = destinationElement.NextNode;
while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode;
destinationElement = nextNode as XElement;
}
destinationDoc.Save(destinationPath);
},
() =>
{
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.Replace("\\", "/")).ToArray();
return new string[][]
{
files,
files
};
}));
commands.Add(new Command("dumpentitytexts", "dumpentitytexts [filepath]: gets the names and descriptions of all entity prefabs and writes them into a file along with xml tags that can be used in translation files. If the filepath is omitted, the file is written to Content/Texts/EntityTexts.txt", (string[] args) =>
{
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EntityTexts.txt";
List<string> lines = new List<string>();
foreach (MapEntityPrefab me in MapEntityPrefab.List)
{
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</" + me.Identifier + ".Name>");
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</" + me.Identifier + ".Description>");
}
File.WriteAllLines(filePath, lines);
}));
#if DEBUG
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
{
if (args.Length != 1) return;
TextManager.CheckForDuplicates(args[0]);
}));
commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) =>
{
TextManager.WriteToCSV();
NPCConversation.WriteToCSV();
}));
commands.Add(new Command("loadtexts", "loadtexts [sourcefile] [destinationfile]: Loads all lines of text from a given .txt file and inserts them sequientially into the elements of an xml file. If the file paths are omitted, EnglishVanilla.txt and EnglishVanilla.xml are used.", (string[] args) =>
{
@@ -149,6 +149,32 @@ namespace Barotrauma
CanBeFocused = false
};
//report buttons
foreach (Order order in reports)
{
if (!order.TargetAllCharacters || order.SymbolSprite == null) continue;
var btn = new GUIButton(new RectTransform(new Point(reportButtonFrame.Rect.Width), reportButtonFrame.RectTransform), style: null)
{
OnClicked = (GUIButton button, object userData) =>
{
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false;
SetCharacterOrder(null, order, null, Character.Controlled);
return true;
},
UserData = order,
ToolTip = order.Name
};
new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow")
{
Color = Color.Red * 0.8f,
HoverColor = Color.Red * 1.0f,
PressedColor = Color.Red * 0.6f,
UserData = "highlighted",
CanBeFocused = false,
Visible = false
};
var characterInfo = new CharacterInfo(subElement);
characterInfos.Add(characterInfo);
foreach (XElement invElement in subElement.Elements())
@@ -164,16 +190,6 @@ namespace Barotrauma
prevUIScale = GUI.Scale;
}
#endregion
#region Character list management
public Rectangle GetCharacterListArea()
{
return characterListBox.Rect;
}
partial void InitProjectSpecific()
{
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
@@ -626,6 +626,28 @@ namespace Barotrauma
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
return true;
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft),
TextManager.Get("Cancel"))
{
IgnoreLayoutGroups = true,
OnClicked = (x, y) =>
{
if (UnsavedSettings)
{
LoadPlayerConfig();
}
if (Screen.Selected == GameMain.MainMenuScreen) GameMain.MainMenuScreen.ReturnToMainMenu(null, null);
GUI.SettingsMenuOpen = false;
return true;
}
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
@@ -184,6 +184,63 @@ namespace Barotrauma.Items.Components
}
}
}
public void ApplyTo(RectTransform target)
{
if (RelativeOffset.HasValue)
{
target.RelativeOffset = RelativeOffset.Value;
}
else if (AbsoluteOffset.HasValue)
{
target.AbsoluteOffset = AbsoluteOffset.Value;
}
if (RelativeSize.HasValue)
{
target.RelativeSize = RelativeSize.Value;
}
else if (AbsoluteSize.HasValue)
{
target.NonScaledSize = AbsoluteSize.Value;
}
if (Anchor.HasValue)
{
target.Anchor = Anchor.Value;
}
if (Pivot.HasValue)
{
target.Pivot = Pivot.Value;
}
else
{
target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor);
}
target.RecalculateChildren(true, true);
}
}
public GUIFrame GuiFrame { get; protected set; }
[Serialize(false, false)]
public bool AllowUIOverlap
{
get;
set;
}
private ItemComponent linkToUIComponent;
[Serialize("", false)]
public string LinkUIToComponent
{
get;
set;
}
[Serialize(0, false)]
public int HudPriority
{
get;
private set;
}
private bool shouldMuffleLooping;
@@ -847,6 +847,16 @@ namespace Barotrauma.Networking
waitInServerQueueBox = null;
CoroutineManager.StopCoroutines("WaitInServerQueue");
}
else
{
string msg = "";
if (disconnectReason == DisconnectReason.Unknown)
{
msg = disconnectMsg;
}
else
{
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
if (allowReconnect && disconnectReason == DisconnectReason.Unknown)
{
@@ -1678,12 +1688,24 @@ namespace Barotrauma.Networking
return permissions.HasFlag(permission);
}
public bool HasConsoleCommandPermission(string command)
public bool HasConsoleCommandPermission(string commandName)
{
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) return false;
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) { return false; }
command = command.ToLowerInvariant();
return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command);
commandName = commandName.ToLowerInvariant();
if (permittedConsoleCommands.Any(c => c.ToLowerInvariant() == commandName)) { return true; }
//check aliases
foreach (DebugConsole.Command command in DebugConsole.Commands)
{
if (command.names.Contains(commandName))
{
if (command.names.Intersect(permittedConsoleCommands).Any()) { return true; }
break;
}
}
return false;
}
public override void Disconnect()
@@ -327,46 +327,7 @@ namespace Barotrauma.Steam
item.Subscribe();
item.Download();
}
public static void SaveToWorkshop(Submarine sub)
{
if (instance == null || !instance.isInitialized) return;
Workshop.Editor item;
ContentPackage contentPackage;
try
{
CreateWorkshopItemStaging(
new List<ContentFile>() { new ContentFile(sub.FilePath, ContentType.None) },
out item, out contentPackage);
}
catch (Exception e)
{
DebugConsole.ThrowError("Creating the workshop item failed.", e);
return;
}
item.Description = sub.Description;
item.Title = sub.Name;
item.Tags.Add("Submarine");
string subPreviewPath = Path.GetFullPath(Path.Combine(item.Folder, PreviewImageName));
try
{
using (Stream s = File.Create(subPreviewPath))
{
sub.PreviewImage.Texture.SaveAsPng(s, (int)sub.PreviewImage.size.X, (int)sub.PreviewImage.size.Y);
item.PreviewImage = subPreviewPath;
}
}
catch (Exception e)
{
DebugConsole.ThrowError("Saving submarine preview image failed.", e);
item.PreviewImage = null;
}
StartPublishItem(contentPackage, item);
}
/// <summary>
/// Creates a new folder, copies the specified files there and creates a metadata file with install instructions.
/// </summary>
@@ -568,14 +529,15 @@ namespace Barotrauma.Steam
return false;
}
ContentPackage contentPackage = new ContentPackage(Path.Combine(item.Directory.FullName, MetadataFileName));
string metaDataFilePath = Path.Combine(item.Directory.FullName, MetadataFileName);
ContentPackage contentPackage = new ContentPackage(metaDataFilePath);
string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);
var allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories);
List<string> nonContentFiles = new List<string>();
foreach (string file in allPackageFiles)
{
if (file == MetadataFileName) { continue; }
if (file == metaDataFilePath) { continue; }
string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory.FullName);
string fullPath = Path.GetFullPath(relativePath);
if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return fp == fullPath; })) { continue; }
@@ -612,13 +574,6 @@ namespace Barotrauma.Steam
try
{
//we only need to create a new content package for the item if it contains content with a type other than None or Submarine
//e.g. items that are just a sub file are just copied to the game folder
if (contentPackage.Files.Any(f => f.Type != ContentType.None && f.Type != ContentType.Submarine))
{
File.Copy(contentPackage.Path, newContentPackagePath);
}
foreach (ContentFile contentFile in contentPackage.Files)
{
string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path);
@@ -789,14 +744,13 @@ namespace Barotrauma.Steam
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
if (!File.Exists(metaDataPath))
{
throw new FileNotFoundException("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
return false;
}
ContentPackage contentPackage = new ContentPackage(metaDataPath);
//make sure the contentpackage file is present
//(unless the package only contains submarine files, in which case we don't need a content package)
if (contentPackage.Files.Any(f => f.Type != ContentType.Submarine) &&
!File.Exists(GetWorkshopItemContentPackagePath(contentPackage)) &&
if (!File.Exists(GetWorkshopItemContentPackagePath(contentPackage)) &&
!ContentPackage.List.Any(cp => cp.Name == contentPackage.Name))
{
return false;
@@ -819,7 +773,8 @@ namespace Barotrauma.Steam
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
if (!File.Exists(metaDataPath))
{
throw new FileNotFoundException("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
return false;
}
ContentPackage steamPackage = new ContentPackage(metaDataPath);
@@ -839,15 +794,20 @@ namespace Barotrauma.Steam
bool itemsUpdated = false;
foreach (ulong subscribedItemId in instance.client.Workshop.GetSubscribedItemIds())
{
//TODO: fix this, GetItem doesn't query item.Modified
var item = instance.client.Workshop.GetItem(subscribedItemId);
if (item.Installed && CheckWorkshopItemEnabled(item) && !CheckWorkshopItemUpToDate(item))
{
if (!UpdateWorkshopItem(item, out string errorMsg))
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg));
}
else
{
new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title));
itemsUpdated = true;
}
}
@@ -475,6 +475,43 @@ namespace Barotrauma
UpdateSourceRect(limb, newRect);
}
}
UpdateJointCreation();
if (PlayerInput.KeyHit(Keys.Left))
{
foreach (var limb in selectedLimbs)
{
var newRect = limb.ActiveSprite.SourceRect;
newRect.X--;
UpdateSourceRect(limb, newRect);
}
}
if (PlayerInput.KeyHit(Keys.Right))
{
foreach (var limb in selectedLimbs)
{
var newRect = limb.ActiveSprite.SourceRect;
newRect.X++;
UpdateSourceRect(limb, newRect);
}
}
if (PlayerInput.KeyHit(Keys.Down))
{
foreach (var limb in selectedLimbs)
{
var newRect = limb.ActiveSprite.SourceRect;
newRect.Y++;
UpdateSourceRect(limb, newRect);
}
}
if (PlayerInput.KeyHit(Keys.Up))
{
foreach (var limb in selectedLimbs)
{
var newRect = limb.ActiveSprite.SourceRect;
newRect.Y--;
UpdateSourceRect(limb, newRect);
}
}
}
if (!isFreezed)
{
@@ -366,7 +366,17 @@ namespace Barotrauma
IgnoreLayoutGroups = true,
OnClicked = (btn, userdata) =>
{
SteamManager.UpdateWorkshopItem(item, out string errorMsg);
if (SteamManager.UpdateWorkshopItem(item, out string errorMsg))
{
new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title));
}
else
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg));
}
btn.Enabled = false;
btn.Visible = false;
return true;
@@ -544,9 +554,10 @@ namespace Barotrauma
tickBox.Enabled = false;
}
}
if (!tickBox.Enabled && updateButton == null)
if (updateButton != null)
{
updateButton.Enabled = false;
//cannot update if enabling/disabling the item failed or if the item is not enabled
updateButton.Enabled = tickBox.Enabled && tickBox.Selected;
}
if (!string.IsNullOrEmpty(errorMsg))
{
@@ -666,7 +677,7 @@ namespace Barotrauma
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to copy submarine file \""+sub.FilePath+"\" to the Workshop item staging folder.", e);
DebugConsole.ThrowError("Failed to copy submarine file \"" + sub.FilePath + "\" to the Workshop item staging folder.", e);
return;
}