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

View File

@@ -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) =>
{

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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()

View File

@@ -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;
}
}

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -641,25 +641,20 @@ namespace Barotrauma
AssignOnExecute("setclientcharacter", (string[] args) =>
{
if (GameMain.Server == null) return;
int separatorIndex = Array.IndexOf(args, ";");
if (separatorIndex == -1 || args.Length < 3)
if (args.Length < 2)
{
ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"");
ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.");
return;
}
string[] argsLeft = args.Take(separatorIndex).ToArray();
string[] argsRight = args.Skip(separatorIndex + 1).ToArray();
string clientName = string.Join(" ", argsLeft);
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == clientName);
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (client == null)
{
ThrowError("Client \"" + clientName + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
}
var character = FindMatchingCharacter(argsRight, false);
var character = FindMatchingCharacter(args.Skip(1).ToArray(), false);
GameMain.Server.SetClientCharacter(client, character);
});
@@ -1255,7 +1250,7 @@ namespace Barotrauma
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (args.Length < 1) return;
var character = FindMatchingCharacter(args, true);
var character = FindMatchingCharacter(args, ignoreRemotePlayers: true, allowedRemotePlayer: client);
if (character != null)
{
GameMain.Server.SetClientCharacter(client, character);
@@ -1496,24 +1491,25 @@ namespace Barotrauma
"setclientcharacter",
(Client senderClient, Vector2 cursorWorldPos, string[] args) =>
{
int separatorIndex = Array.IndexOf(args, ";");
if (separatorIndex == -1 || args.Length < 3)
if (args.Length < 2)
{
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"", senderClient);
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient);
return;
}
string[] argsLeft = args.Take(separatorIndex).ToArray();
string[] argsRight = args.Skip(separatorIndex + 1).ToArray();
string clientName = string.Join(" ", argsLeft);
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == clientName);
if (args.Length < 2)
{
ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.");
return;
}
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client \"" + clientName + "\" not found.", senderClient);
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
}
var character = FindMatchingCharacter(argsRight, false);
var character = FindMatchingCharacter(args.Skip(1).ToArray(), false);
GameMain.Server.SetClientCharacter(client, character);
}
);

View File

@@ -27,14 +27,14 @@ namespace Barotrauma
var greetingMsgBox = ChatMessage.Create(null, greetingMessage, ChatMessageType.MessageBox, null);
var moreAgentsMsgBox = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.MessageBox, null);
Client client = server.ConnectedClients.Find(c => c.Character == Character);
GameMain.Server.SendDirectChatMessage(greetingChatMsg, client);
GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, client);
GameMain.Server.SendDirectChatMessage(greetingMsgBox, client);
GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, client);
Client traitorClient = server.ConnectedClients.Find(c => c.Character == Character);
GameMain.Server.SendDirectChatMessage(greetingChatMsg, traitorClient);
GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, traitorClient);
GameMain.Server.SendDirectChatMessage(greetingMsgBox, traitorClient);
GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, traitorClient);
Client ownerClient = server.ConnectedClients.Find(c => c.Connection == server.OwnerConnection);
if (client != ownerClient)
if (traitorClient != ownerClient && ownerClient != null && ownerClient.Character == null)
{
var ownerMsg = ChatMessage.Create(
null,//TextManager.Get("NewTraitor"),

View File

@@ -1701,7 +1701,7 @@ namespace Barotrauma.Networking
}
int max = Math.Max(serverSettings.TraitorUseRatio ? (int)Math.Round(characters.Count * serverSettings.TraitorRatio, 1) : 1, 1);
int traitorCount = Rand.Int(max + 1);
int traitorCount = Rand.Range(1, max + 1);
TraitorManager = new TraitorManager(this, traitorCount);
if (TraitorManager.TraitorList.Count > 0)
@@ -2054,6 +2054,14 @@ namespace Barotrauma.Networking
public void SendDirectChatMessage(ChatMessage msg, Client recipient)
{
if (recipient == null)
{
string errorMsg = "Attempted to send a chat message to a null client.\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.SendDirectChatMessage:ClientNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}
msg.NetStateID = recipient.ChatMsgQueue.Count > 0 ?
(ushort)(recipient.ChatMsgQueue.Last().NetStateID + 1) :
(ushort)(recipient.LastRecvChatMsgID + 1);

View File

@@ -1110,110 +1110,6 @@ namespace Barotrauma
return currMaxSpeed;
}
public void Control(float deltaTime, Camera cam)
{
ViewTarget = null;
if (!AllowInput) return;
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
if (Controlled == this)
{
SmoothedCursorPosition = cursorPosition;
}
else
{
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
}
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
{
Vector2 targetMovement = GetTargetMovement();
AnimController.TargetMovement = targetMovement;
AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f;
}
if (AnimController is HumanoidAnimController)
{
((HumanoidAnimController) AnimController).Crouching = IsKeyDown(InputType.Crouch);
}
return currMaxSpeed;
}
/// <summary>
/// Can be used to modify the character's speed via StatusEffects
/// </summary>
public float SpeedMultiplier
{
get
{
if (speedMultipliers.Count == 0) return 1f;
float greatestPositive = 1f;
float greatestNegative = 1f;
for (int i = 0; i < speedMultipliers.Count; i++)
{
float val = speedMultipliers[i];
if (val < 1f)
{
if (val < greatestNegative)
{
greatestNegative = val;
}
}
else
{
if (val > greatestPositive)
{
greatestPositive = val;
}
}
}
return greatestPositive - (1f - greatestNegative);
}
set
{
if (value == 1f) return;
speedMultipliers.Add(value);
}
}
public void ResetSpeedMultiplier()
{
speedMultipliers.Clear();
}
/// <summary>
/// Applies temporary limits to the speed (damage).
/// </summary>
public float GetCurrentMaxSpeed(bool run)
{
float currMaxSpeed = AnimController.GetCurrentSpeed(run);
//?
//currMaxSpeed *= 1.5f;
var leftFoot = AnimController.GetLimb(LimbType.LeftFoot);
if (leftFoot != null)
{
float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", leftFoot, true);
currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f));
}
var rightFoot = AnimController.GetLimb(LimbType.RightFoot);
if (rightFoot != null)
{
float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", rightFoot, true);
currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f));
}
return currMaxSpeed;
}
public void Control(float deltaTime, Camera cam)
{
ViewTarget = null;

View File

@@ -801,7 +801,7 @@ namespace Barotrauma
}
}, null, true));
commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] ; [character name]: Gives the client control of the specified character.", null,
commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] [character name]: Gives the client control of the specified character.", null,
() =>
{
if (GameMain.NetworkMember == null) return null;
@@ -1276,7 +1276,7 @@ namespace Barotrauma
}
}
private static Character FindMatchingCharacter(string[] args, bool ignoreRemotePlayers = false)
private static Character FindMatchingCharacter(string[] args, bool ignoreRemotePlayers = false, Client allowedRemotePlayer = null)
{
if (args.Length == 0) return null;
@@ -1292,7 +1292,9 @@ namespace Barotrauma
characterIndex = -1;
}
var matchingCharacters = Character.CharacterList.FindAll(c => (!ignoreRemotePlayers || !c.IsRemotePlayer) && c.Name.ToLowerInvariant() == characterName);
var matchingCharacters = Character.CharacterList.FindAll(c =>
c.Name.ToLowerInvariant() == characterName &&
(!c.IsRemotePlayer || !ignoreRemotePlayers || allowedRemotePlayer?.Character == c));
if (!matchingCharacters.Any())
{

View File

@@ -65,6 +65,8 @@ namespace Barotrauma
public int ParticleLimit { get; set; }
public int ParticleLimit { get; set; }
public float LightMapScale { get; set; }
public bool SpecularityEnabled { get; set; }
public bool ChromaticAberrationEnabled { get; set; }
@@ -395,6 +397,8 @@ namespace Barotrauma
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
@@ -566,34 +570,6 @@ namespace Barotrauma
TextManager.LoadTextPacks(SelectedContentPackages);
//display error messages after all content packages have been loaded
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
{
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
}
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
{
DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
.Replace("[packagename]", incompatiblePackage.Name)
.Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
.Replace("[gameversion]", GameMain.Version.ToString()));
}
foreach (ContentPackage contentPackage in SelectedContentPackages)
{
foreach (ContentFile file in contentPackage.Files)
{
if (!System.IO.File.Exists(file.Path))
{
DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\" - file \"" + file.Path + "\" not found.");
continue;
}
ToolBox.IsProperFilenameCase(file.Path);
}
}
TextManager.LoadTextPacks(SelectedContentPackages);
//display error messages after all content packages have been loaded
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
@@ -1198,6 +1174,32 @@ namespace Barotrauma
NewLineOnAttributes = true
};
#if CLIENT
if (Tutorial.Tutorials != null)
{
foreach (Tutorial tutorial in Tutorial.Tutorials)
{
if (tutorial.Completed && !CompletedTutorialNames.Contains(tutorial.Name))
{
CompletedTutorialNames.Add(tutorial.Name);
}
}
}
#endif
var tutorialElement = new XElement("tutorials");
foreach (string tutorialName in CompletedTutorialNames)
{
tutorialElement.Add(new XElement("Tutorial", new XAttribute("name", tutorialName)));
}
doc.Root.Add(tutorialElement);
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true,
NewLineOnAttributes = true
};
#if CLIENT
if (Tutorial.Tutorials != null)
{

View File

@@ -223,6 +223,24 @@ namespace Barotrauma.Items.Components
return base.Select(character);
}
public override bool Select(Character character)
{
if (item.Container != null) { return false; }
if (AutoInteractWithContained)
{
foreach (Item contained in Inventory.Items)
{
if (contained == null) continue;
if (contained.TryInteract(character))
{
return false;
}
}
}
return base.Select(character);
}
public override bool Pick(Character picker)
{
if (AutoInteractWithContained)

View File

@@ -430,6 +430,13 @@ namespace Barotrauma
}
CurrentLocation.SelectedMissionIndex = missionIndex;
//the destination must be the same as the destination of the mission
if (CurrentLocation.SelectedMission != null &&
CurrentLocation.SelectedMission.Locations[1] != SelectedLocation)
{
SelectLocation(CurrentLocation.SelectedMission.Locations[1]);
}
SelectedLocation = location;
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);

View File

@@ -526,6 +526,10 @@ namespace Barotrauma
{
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
}
else
{
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
}
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
}
@@ -550,6 +554,11 @@ namespace Barotrauma
spawnPos.X = (minX + maxX) / 2;
}
if (minX < 0.0f && maxX > Level.Loaded.Size.X)
{
//no walls found at either side, just use the initial spawnpos and hope for the best
}
if (minX < 0.0f && maxX > Level.Loaded.Size.X)
{
//no walls found at either side, just use the initial spawnpos and hope for the best

View File

@@ -160,6 +160,16 @@ namespace Barotrauma
}
#endif
public void SetState()
{
hit = binding.IsHit();
if (hit) hitQueue = true;
held = binding.IsDown();
if (held) heldQueue = true;
}
#endif
public bool Hit
{
get