Release v0.15.12.0
This commit is contained in:
@@ -28,6 +28,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter))
|
||||
{
|
||||
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
|
||||
if (ownerClient != null)
|
||||
{
|
||||
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
|
||||
}
|
||||
}
|
||||
|
||||
healthUpdateTimer = 0.0f;
|
||||
|
||||
if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this)
|
||||
@@ -46,5 +55,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMoneyChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -9,8 +10,9 @@ namespace Barotrauma
|
||||
{
|
||||
private readonly Dictionary<string, float> prevSentSkill = new Dictionary<string, float>();
|
||||
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
if (!prevSentSkill.ContainsKey(skillIdentifier))
|
||||
{
|
||||
prevSentSkill[skillIdentifier] = prevLevel;
|
||||
@@ -22,6 +24,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnExperienceChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
if (prevAmount != newAmount)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience });
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnPermanentStatChanged(StatTypes statType)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdatePermanentStats, statType });
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(ID);
|
||||
@@ -30,10 +47,13 @@ namespace Barotrauma
|
||||
msg.Write((byte)Gender);
|
||||
msg.Write((byte)Race);
|
||||
msg.Write((byte)HeadSpriteId);
|
||||
msg.Write((byte)Head.HairIndex);
|
||||
msg.Write((byte)Head.BeardIndex);
|
||||
msg.Write((byte)Head.MoustacheIndex);
|
||||
msg.Write((byte)Head.FaceAttachmentIndex);
|
||||
msg.Write((byte)HairIndex);
|
||||
msg.Write((byte)BeardIndex);
|
||||
msg.Write((byte)MoustacheIndex);
|
||||
msg.Write((byte)FaceAttachmentIndex);
|
||||
msg.WriteColorR8G8B8(SkinColor);
|
||||
msg.WriteColorR8G8B8(HairColor);
|
||||
msg.WriteColorR8G8B8(FacialHairColor);
|
||||
msg.Write(ragdollFileName);
|
||||
|
||||
if (Job != null)
|
||||
@@ -53,6 +73,19 @@ namespace Barotrauma
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
// TODO: animations
|
||||
msg.Write((byte)SavedStatValues.SelectMany(s => s.Value).Count());
|
||||
foreach (var savedStatValuePair in SavedStatValues)
|
||||
{
|
||||
foreach (var savedStatValue in savedStatValuePair.Value)
|
||||
{
|
||||
msg.Write((byte)savedStatValuePair.Key);
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
msg.Write((ushort)ExperiencePoints);
|
||||
msg.Write((ushort)AdditionalTalentPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ namespace Barotrauma
|
||||
break;
|
||||
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
int eventType = msg.ReadRangedInteger(0, 3);
|
||||
int eventType = msg.ReadRangedInteger(0, 4);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0:
|
||||
@@ -268,8 +268,35 @@ namespace Barotrauma
|
||||
if (IsIncapacitated)
|
||||
{
|
||||
var causeOfDeath = CharacterHealth.GetCauseOfDeath();
|
||||
Kill(causeOfDeath.First, causeOfDeath.Second);
|
||||
Kill(causeOfDeath.type, causeOfDeath.affliction);
|
||||
}
|
||||
break;
|
||||
case 3: // NetEntityEvent.Type.UpdateTalents
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// get the full list of talents from the player, only give the ones
|
||||
// that are not already given (or otherwise not viable)
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
List<string> talentSelection = new List<string>();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
|
||||
if (prefab != null) { talentSelection.Add(prefab.Identifier); }
|
||||
}
|
||||
talentSelection = TalentTree.CheckTalentSelection(this, talentSelection);
|
||||
|
||||
foreach (string talent in talentSelection)
|
||||
{
|
||||
GiveTalent(talent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -283,7 +310,7 @@ namespace Barotrauma
|
||||
|
||||
if (extraData != null)
|
||||
{
|
||||
const int min = 0, max = 9;
|
||||
const int min = 0, max = 13;
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
@@ -394,6 +421,47 @@ namespace Barotrauma
|
||||
msg.Write(inventoryItemIDs[i]);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateExperience:
|
||||
msg.WriteRangedInteger(10, min, max);
|
||||
msg.Write(Info.ExperiencePoints);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateTalents:
|
||||
msg.WriteRangedInteger(11, min, max);
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.AddedThisRound);
|
||||
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateMoney:
|
||||
msg.WriteRangedInteger(12, min, max);
|
||||
msg.Write(GameMain.GameSession.Campaign.Money);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdatePermanentStats:
|
||||
msg.WriteRangedInteger(13, min, max);
|
||||
if (Info == null || extraData.Length < 2 || !(extraData[1] is StatTypes statType))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else if (!Info.SavedStatValues.ContainsKey(statType))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)statType);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)Info.SavedStatValues[statType].Count);
|
||||
msg.Write((byte)statType);
|
||||
foreach (var savedStatValue in Info.SavedStatValues[statType])
|
||||
{
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||
break;
|
||||
@@ -499,7 +567,7 @@ namespace Barotrauma
|
||||
if (writeStatus)
|
||||
{
|
||||
WriteStatus(tempBuffer);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ServerWrite(tempBuffer);
|
||||
AIController?.ServerWrite(tempBuffer);
|
||||
HealthUpdatePending = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1187,6 +1187,7 @@ namespace Barotrauma
|
||||
NewMessage("*****************", Color.Lime);
|
||||
GameServer.Log("Console command \"restart\" executed: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
GameMain.Instance.CloseServer();
|
||||
GameMain.Instance.TryStartChildServerRelay();
|
||||
GameMain.Instance.StartServer();
|
||||
}));
|
||||
|
||||
@@ -1676,10 +1677,25 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
bool relativeStrength = false;
|
||||
if (args.Length > 4)
|
||||
{
|
||||
bool.TryParse(args[4], out relativeStrength);
|
||||
}
|
||||
|
||||
Character targetCharacter = (args.Length <= 2) ? client.Character : FindMatchingCharacter(args.Skip(2).ToArray());
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.CharacterHealth.ApplyAffliction(targetCharacter.AnimController.MainLimb, afflictionPrefab.Instantiate(afflictionStrength));
|
||||
Limb targetLimb = targetCharacter.AnimController.MainLimb;
|
||||
if (args.Length > 3)
|
||||
{
|
||||
targetLimb = targetCharacter.AnimController.Limbs.FirstOrDefault(l => l.type.ToString().Equals(args[3], StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
if (relativeStrength)
|
||||
{
|
||||
afflictionStrength *= targetCharacter.MaxVitality / afflictionPrefab.MaxStrength;
|
||||
}
|
||||
targetCharacter.CharacterHealth.ApplyAffliction(targetLimb ?? targetCharacter.AnimController.MainLimb, afflictionPrefab.Instantiate(afflictionStrength));
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -1716,16 +1732,86 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.Character != revivedCharacter) continue;
|
||||
if (c.Character != revivedCharacter) { continue; }
|
||||
|
||||
//clients stop controlling the character when it dies, force control back
|
||||
GameMain.Server.SetClientCharacter(c, revivedCharacter);
|
||||
//clients stop controlling the character when it dies, force control back
|
||||
GameMain.Server.SetClientCharacter(c, revivedCharacter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"givetalent",
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) { return; }
|
||||
Character targetCharacter = (args.Length >= 2) ? FindMatchingCharacter(args.Skip(1).ToArray(), false) : client.Character;
|
||||
|
||||
if (targetCharacter == null) { return; }
|
||||
|
||||
TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c =>
|
||||
c.Identifier.Equals(args[0], StringComparison.OrdinalIgnoreCase) ||
|
||||
c.DisplayName.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (talentPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Couldn't find the talent \"" + args[0] + "\".", client);
|
||||
return;
|
||||
}
|
||||
targetCharacter.GiveTalent(talentPrefab);
|
||||
NewMessage($"Talent \"{talentPrefab.DisplayName}\" given to \"{targetCharacter.Name}\" by \"{client.Name}\".");
|
||||
GameMain.Server.SendConsoleMessage($"Gave talent \"{talentPrefab.DisplayName}\" to \"{targetCharacter.Name}\".", client);
|
||||
}
|
||||
);
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"unlocktalents",
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
var targetCharacter = args.Length >= 2 ? FindMatchingCharacter(args.Skip(1).ToArray()) : Character.Controlled;
|
||||
if (targetCharacter == null) { return; }
|
||||
|
||||
List<TalentTree> talentTrees = new List<TalentTree>();
|
||||
if (args.Length == 0 || args[0].Equals("all", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
talentTrees.AddRange(TalentTree.JobTalentTrees.Values);
|
||||
}
|
||||
else
|
||||
{
|
||||
var job = JobPrefab.Prefabs.Find(jp => jp.Name != null && jp.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
if (job == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Failed to find the job \"{args[0]}\".", client);
|
||||
return;
|
||||
}
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(job.Identifier, out TalentTree talentTree))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"No talents configured for the job \"{args[0]}\".", client);
|
||||
return;
|
||||
}
|
||||
talentTrees.Add(talentTree);
|
||||
}
|
||||
|
||||
foreach (var talentTree in talentTrees)
|
||||
{
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
foreach (var option in subTree.TalentOptionStages)
|
||||
{
|
||||
foreach (var talent in option.Talents)
|
||||
{
|
||||
targetCharacter.GiveTalent(talent);
|
||||
NewMessage($"Talent \"{talent.DisplayName}\" given to \"{targetCharacter.Name}\" by \"{client.Name}\".");
|
||||
GameMain.Server.SendConsoleMessage($"Gave talent \"{talent.DisplayName}\" to \"{targetCharacter.Name}\".", client);
|
||||
NewMessage($"Unlocked talent \"{talent.DisplayName}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"freeze",
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
@@ -1776,7 +1862,7 @@ namespace Barotrauma
|
||||
"control",
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) return;
|
||||
if (args.Length < 1) { return; }
|
||||
var character = FindMatchingCharacter(args, ignoreRemotePlayers: true, allowedRemotePlayer: client);
|
||||
if (character != null)
|
||||
{
|
||||
@@ -2100,6 +2186,7 @@ namespace Barotrauma
|
||||
if (client == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||
return;
|
||||
}
|
||||
|
||||
var character = FindMatchingCharacter(args.Skip(1).ToArray(), false);
|
||||
@@ -2190,13 +2277,13 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Skill skill in character.Info.Job.Skills)
|
||||
{
|
||||
character.Info.SetSkillLevel(skill.Identifier, level, character.WorldPosition);
|
||||
character.Info.SetSkillLevel(skill.Identifier, level);
|
||||
}
|
||||
GameMain.Server.SendConsoleMessage($"Set all {character.Name}'s skills to {level}", senderClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Info.SetSkillLevel(skillIdentifier, level, character.WorldPosition);
|
||||
character.Info.SetSkillLevel(skillIdentifier, level);
|
||||
GameMain.Server.SendConsoleMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", senderClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Barotrauma
|
||||
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((ushort)spawnedItems.Count);
|
||||
foreach (Item item in spawnedItems)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AlienRuinMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((ushort)existingTargets.Count);
|
||||
foreach (var t in existingTargets)
|
||||
{
|
||||
msg.Write(t != null ? t.ID : Entity.NullEntityID);
|
||||
}
|
||||
msg.Write((ushort)spawnedTargets.Count);
|
||||
foreach (var t in spawnedTargets)
|
||||
{
|
||||
t.WriteSpawnData(msg, t.ID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BeaconMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((ushort)items.Count);
|
||||
foreach (Item item in items)
|
||||
{
|
||||
|
||||
@@ -83,10 +83,5 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
|
||||
if (characters.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write escort mission data when no characters had been spawned.");
|
||||
|
||||
@@ -6,16 +6,17 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((byte)caves.Count);
|
||||
foreach (var cave in caves)
|
||||
{
|
||||
msg.Write((byte)(Level.Loaded == null || !Level.Loaded.Caves.Contains(cave) ? 255 : Level.Loaded.Caves.IndexOf(cave)));
|
||||
}
|
||||
|
||||
foreach (var kvp in SpawnedResources)
|
||||
foreach (var kvp in spawnedResources)
|
||||
{
|
||||
msg.Write((byte)kvp.Value.Count);
|
||||
var rotation = ResourceClusters[kvp.Key].Second;
|
||||
var rotation = resourceClusters[kvp.Key].rotation;
|
||||
msg.Write(rotation);
|
||||
foreach (var r in kvp.Value)
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kvp in RelevantLevelResources)
|
||||
foreach (var kvp in relevantLevelResources)
|
||||
{
|
||||
msg.Write(kvp.Key);
|
||||
msg.Write((byte)kvp.Value.Length);
|
||||
|
||||
@@ -16,6 +16,14 @@ namespace Barotrauma
|
||||
GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
|
||||
public abstract void ServerWriteInitial(IWriteMessage msg, Client c);
|
||||
public virtual void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.Write((ushort)State);
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write((ushort)State);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
|
||||
if (monsters.Count == 0 && monsterPrefabs.Count > 0)
|
||||
{
|
||||
throw new InvalidOperationException("Server attempted to write monster mission data when no monsters had been spawned.");
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Barotrauma
|
||||
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((byte)(selectedCave == null || Level.Loaded == null || !Level.Loaded.Caves.Contains(selectedCave) ? 255 : Level.Loaded.Caves.IndexOf(selectedCave)));
|
||||
msg.Write(nestPosition.X);
|
||||
msg.Write(nestPosition.Y);
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
|
||||
// duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not
|
||||
if (characters.Count == 0)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma
|
||||
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
|
||||
msg.Write(usedExistingItem);
|
||||
if (usedExistingItem)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class ScanMission : Mission
|
||||
{
|
||||
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||
{
|
||||
base.ServerWriteInitial(msg, c);
|
||||
msg.Write((ushort)startingItems.Count);
|
||||
foreach (var item in startingItems)
|
||||
{
|
||||
item.WriteSpawnData(msg,
|
||||
item.ID,
|
||||
parentInventoryIDs.ContainsKey(item) ? parentInventoryIDs[item] : Entity.NullEntityID,
|
||||
parentItemContainerIndices.ContainsKey(item) ? parentItemContainerIndices[item] : (byte)0);
|
||||
}
|
||||
ServerWriteScanTargetStatus(msg);
|
||||
}
|
||||
|
||||
public override void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
base.ServerWrite(msg);
|
||||
ServerWriteScanTargetStatus(msg);
|
||||
}
|
||||
|
||||
private void ServerWriteScanTargetStatus(IWriteMessage msg)
|
||||
{
|
||||
msg.Write((byte)scanTargets.Count);
|
||||
foreach (var kvp in scanTargets)
|
||||
{
|
||||
msg.Write(kvp.Key != null ? kvp.Key.ID : Entity.NullEntityID);
|
||||
msg.Write(kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,17 @@ namespace Barotrauma
|
||||
{
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static World World;
|
||||
|
||||
private static World world;
|
||||
public static World World
|
||||
{
|
||||
get
|
||||
{
|
||||
if (world == null) { world = new World(new Vector2(0, -9.82f)); }
|
||||
return world;
|
||||
}
|
||||
set { world = value; }
|
||||
}
|
||||
public static GameSettings Config;
|
||||
|
||||
public static GameServer Server;
|
||||
@@ -123,6 +133,8 @@ namespace Barotrauma
|
||||
ItemAssemblyPrefab.LoadAll();
|
||||
LevelObjectPrefab.LoadAll();
|
||||
BallastFloraPrefab.LoadAll(GetFilesOfType(ContentType.MapCreature));
|
||||
TalentPrefab.LoadAll(GetFilesOfType(ContentType.Talents));
|
||||
TalentTree.LoadAll(GetFilesOfType(ContentType.TalentTrees));
|
||||
|
||||
GameModePreset.Init();
|
||||
DecalManager = new DecalManager();
|
||||
@@ -179,6 +191,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryStartChildServerRelay()
|
||||
{
|
||||
for (int i = 0; i < CommandLineArgs.Length; i++)
|
||||
{
|
||||
switch (CommandLineArgs[i].Trim())
|
||||
{
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void StartServer()
|
||||
{
|
||||
string name = "Server";
|
||||
@@ -264,7 +290,7 @@ namespace Barotrauma
|
||||
i++;
|
||||
break;
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
|
||||
//handled in TryStartChildServerRelay
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
@@ -323,6 +349,7 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
TryStartChildServerRelay();
|
||||
Init();
|
||||
StartServer();
|
||||
|
||||
|
||||
+58
-2
@@ -1,4 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -11,11 +13,65 @@ namespace Barotrauma
|
||||
get { return itemData != null; }
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(Client client)
|
||||
public CharacterCampaignData(Client client, bool giveRespawnPenaltyAffliction = false)
|
||||
{
|
||||
Name = client.Name;
|
||||
ClientEndPoint = client.Connection.EndPointString;
|
||||
SteamID = client.SteamID;
|
||||
CharacterInfo = client.CharacterInfo;
|
||||
|
||||
healthData = new XElement("health");
|
||||
client.Character?.CharacterHealth?.Save(healthData);
|
||||
if (giveRespawnPenaltyAffliction)
|
||||
{
|
||||
var respawnPenaltyAffliction = RespawnManager.GetRespawnPenaltyAffliction();
|
||||
healthData.Add(new XElement("Affliction",
|
||||
new XAttribute("identifier", respawnPenaltyAffliction.Identifier),
|
||||
new XAttribute("strength", respawnPenaltyAffliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
|
||||
}
|
||||
if (client.Character?.Inventory != null)
|
||||
{
|
||||
itemData = new XElement("inventory");
|
||||
Character.SaveInventory(client.Character.Inventory, itemData);
|
||||
}
|
||||
OrderData = new XElement("orders");
|
||||
if (client.CharacterInfo != null)
|
||||
{
|
||||
CharacterInfo.SaveOrderData(client.CharacterInfo, OrderData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public CharacterCampaignData(XElement element)
|
||||
{
|
||||
Name = element.GetAttributeString("name", "Unnamed");
|
||||
ClientEndPoint = element.GetAttributeString("endpoint", null) ?? element.GetAttributeString("ip", "");
|
||||
string steamID = element.GetAttributeString("steamid", "");
|
||||
if (!string.IsNullOrEmpty(steamID))
|
||||
{
|
||||
ulong.TryParse(steamID, out ulong parsedID);
|
||||
SteamID = parsedID;
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "character":
|
||||
case "characterinfo":
|
||||
CharacterInfo = new CharacterInfo(subElement);
|
||||
break;
|
||||
case "inventory":
|
||||
itemData = subElement;
|
||||
break;
|
||||
case "health":
|
||||
healthData = subElement;
|
||||
break;
|
||||
case "orders":
|
||||
OrderData = subElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool MatchesClient(Client client)
|
||||
@@ -56,6 +112,6 @@ namespace Barotrauma
|
||||
public void ApplyOrderData(Character character)
|
||||
{
|
||||
CharacterInfo.ApplyOrderData(character, OrderData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+70
-8
@@ -27,6 +27,29 @@ namespace Barotrauma
|
||||
|
||||
public bool GameOver { get; private set; }
|
||||
|
||||
class SavedExperiencePoints
|
||||
{
|
||||
public readonly ulong SteamID;
|
||||
public readonly string EndPoint;
|
||||
public readonly int ExperiencePoints;
|
||||
|
||||
public SavedExperiencePoints(Client client)
|
||||
{
|
||||
SteamID = client.SteamID;
|
||||
EndPoint = client.Connection.EndPointString;
|
||||
ExperiencePoints = client.Character?.Info?.ExperiencePoints ?? 0;
|
||||
}
|
||||
|
||||
public SavedExperiencePoints(XElement element)
|
||||
{
|
||||
SteamID = element.GetAttributeUInt64("steamid", 0);
|
||||
EndPoint = element.GetAttributeString("endpoint", string.Empty);
|
||||
ExperiencePoints = element.GetAttributeInt("points", 0);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<SavedExperiencePoints> savedExperiencePoints = new List<SavedExperiencePoints>();
|
||||
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
@@ -155,6 +178,20 @@ namespace Barotrauma
|
||||
c.InGame && (IsOwner(c) || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
}
|
||||
|
||||
public void SaveExperiencePoints(Client client)
|
||||
{
|
||||
ClearSavedExperiencePoints(client);
|
||||
savedExperiencePoints.Add(new SavedExperiencePoints(client));
|
||||
}
|
||||
public int GetSavedExperiencePoints(Client client)
|
||||
{
|
||||
return savedExperiencePoints.Find(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint))?.ExperiencePoints ?? 0;
|
||||
}
|
||||
public void ClearSavedExperiencePoints(Client client)
|
||||
{
|
||||
savedExperiencePoints.RemoveAll(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint));
|
||||
}
|
||||
|
||||
public void LoadPets()
|
||||
{
|
||||
if (petsElement != null)
|
||||
@@ -163,7 +200,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveInventories()
|
||||
public void SavePlayers()
|
||||
{
|
||||
List<CharacterCampaignData> prevCharacterData = new List<CharacterCampaignData>(characterData);
|
||||
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character)
|
||||
@@ -172,7 +209,12 @@ namespace Barotrauma
|
||||
//refresh the character data of clients who are still in the server
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
||||
if (c.Character != null && c.Character.Info == null)
|
||||
{
|
||||
c.Character = null;
|
||||
}
|
||||
|
||||
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
//the client has opted to spawn this round with Reaper's Tax
|
||||
if (c.WaitForNextRoundRespawn.HasValue && !c.WaitForNextRoundRespawn.Value)
|
||||
@@ -183,14 +225,15 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c.Character?.Info == null) { continue; }
|
||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
||||
var characterInfo = c.Character?.Info ?? c.CharacterInfo;
|
||||
if (characterInfo == null) { continue; }
|
||||
if (c.CharacterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
continue;
|
||||
RespawnManager.ReduceCharacterSkills(characterInfo);
|
||||
}
|
||||
c.CharacterInfo = c.Character.Info;
|
||||
c.CharacterInfo = characterInfo;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
}
|
||||
|
||||
//refresh the character data of clients who aren't in the server anymore
|
||||
@@ -259,6 +302,16 @@ namespace Barotrauma
|
||||
Map.ProgressWorld(transitionType, (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime));
|
||||
|
||||
bool success = GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead);
|
||||
if (success)
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.Character?.HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter) ?? false)
|
||||
{
|
||||
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.GameSession.EndRound("", traitorResults, transitionType);
|
||||
|
||||
@@ -266,7 +319,7 @@ namespace Barotrauma
|
||||
|
||||
if (success)
|
||||
{
|
||||
SaveInventories();
|
||||
SavePlayers();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -965,6 +1018,15 @@ namespace Barotrauma
|
||||
// save bots
|
||||
CrewManager.SaveMultiplayer(modeElement);
|
||||
|
||||
XElement savedExperiencePointsElement = new XElement("SavedExperiencePoints");
|
||||
foreach (var savedExperiencePoint in savedExperiencePoints)
|
||||
{
|
||||
savedExperiencePointsElement.Add(new XElement("Point",
|
||||
new XAttribute("steamid", savedExperiencePoint.SteamID),
|
||||
new XAttribute("endpoint", savedExperiencePoint?.EndPoint ?? string.Empty),
|
||||
new XAttribute("points", savedExperiencePoint.ExperiencePoints)));
|
||||
}
|
||||
|
||||
// save available submarines
|
||||
XElement availableSubsElement = new XElement("AvailableSubs");
|
||||
for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class GeneticMaterial : ItemComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(tainted);
|
||||
if (tainted)
|
||||
{
|
||||
msg.Write(selectedTaintedEffect?.UIntIdentifier ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(selectedEffect?.UIntIdentifier ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,12 @@ namespace Barotrauma.Items.Components
|
||||
set { unsentChanges = value; }
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
pathFinder = null;
|
||||
}
|
||||
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(deteriorationTimer);
|
||||
msg.Write(deteriorateAlwaysResetTimer);
|
||||
msg.Write(DeteriorateAlways);
|
||||
msg.Write(tinkeringDuration);
|
||||
msg.Write(tinkeringStrength);
|
||||
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
|
||||
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Scanner : ItemComponent, IServerSerializable
|
||||
{
|
||||
private float LastSentScanTimer { get; set; }
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(scanTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ButtonTerminal : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
{
|
||||
int signalIndex = msg.ReadRangedInteger(0, Signals.Length - 1);
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
if (!SendSignal(signalIndex)) { return; }
|
||||
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} sent a signal \"{Signals[signalIndex]}\" from {item.Name}", ServerLog.MessageType.ItemInteraction);
|
||||
item.CreateServerEvent(this, new object[] { signalIndex });
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
Write(msg, extraData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace Barotrauma.Items.Components
|
||||
var panel2 = selectedWire.Connections[1]?.ConnectionPanel;
|
||||
if (panel2 != null && panel2 != this) { panel2.item.CreateServerEvent(panel2); }
|
||||
|
||||
CoroutineManager.InvokeAfter(() =>
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
if (panel1 != null && panel1 != this) { panel1.item.CreateServerEvent(panel1); }
|
||||
|
||||
@@ -19,13 +19,13 @@ namespace Barotrauma.Items.Components
|
||||
GameServer.Log(GameServer.CharacterLogName(c.Character) + " entered \"" + newOutputValue + "\" on " + item.Name,
|
||||
ServerLog.MessageType.ItemInteraction);
|
||||
OutputValue = newOutputValue;
|
||||
ShowOnDisplay(newOutputValue);
|
||||
ShowOnDisplay(newOutputValue, addToHistory: true);
|
||||
item.SendSignal(newOutputValue, "signal_out");
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true)
|
||||
partial void ShowOnDisplay(string input, bool addToHistory)
|
||||
{
|
||||
if (addToHistory)
|
||||
{
|
||||
|
||||
@@ -282,6 +282,7 @@ namespace Barotrauma
|
||||
msg.Write(body == null ? (byte)0 : (byte)body.BodyType);
|
||||
msg.Write(SpawnedInOutpost);
|
||||
msg.Write(AllowStealing);
|
||||
msg.WriteRangedInteger(Quality, 0, Items.Components.Quality.MaxQuality);
|
||||
|
||||
byte teamID = 0;
|
||||
foreach (WifiComponent wifiComponent in GetComponents<WifiComponent>())
|
||||
@@ -289,6 +290,14 @@ namespace Barotrauma
|
||||
teamID = (byte)wifiComponent.TeamID;
|
||||
break;
|
||||
}
|
||||
if (teamID == 0)
|
||||
{
|
||||
foreach (IdCard idCard in GetComponents<IdCard>())
|
||||
{
|
||||
teamID = (byte)idCard.TeamID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write(teamID);
|
||||
bool tagsChanged = tags.Count != prefab.Tags.Count || !tags.All(t => prefab.Tags.Contains(t));
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Barotrauma.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
|
||||
@@ -1181,6 +1181,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
c.Character.ServerRead(objHeader, inc, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.AddWarning($"Received character inputs from a client who's not controlling a character ({c.Name}).");
|
||||
}
|
||||
break;
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
entityEventManager.Read(inc, c);
|
||||
@@ -1318,7 +1322,7 @@ namespace Barotrauma.Networking
|
||||
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
|
||||
if (mpCampaign != null && Level.IsLoadedOutpost)
|
||||
{
|
||||
mpCampaign.SaveInventories();
|
||||
mpCampaign.SavePlayers();
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
@@ -2354,8 +2358,16 @@ namespace Barotrauma.Networking
|
||||
characterData.ApplyHealthData(spawnedCharacter);
|
||||
characterData.ApplyOrderData(spawnedCharacter);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
spawnedCharacter.LoadTalents();
|
||||
|
||||
characterData.HasSpawned = true;
|
||||
}
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && spawnedCharacter.Info != null)
|
||||
{
|
||||
spawnedCharacter.Info.SetExperience(Math.Max(spawnedCharacter.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(teamClients[i])));
|
||||
mpCampaign.ClearSavedExperiencePoints(teamClients[i]);
|
||||
}
|
||||
|
||||
spawnedCharacter.OwnerClientEndPoint = teamClients[i].Connection.EndPointString;
|
||||
spawnedCharacter.OwnerClientName = teamClients[i].Name;
|
||||
}
|
||||
@@ -2366,6 +2378,8 @@ namespace Barotrauma.Networking
|
||||
spawnedCharacter.TeamID = teamID;
|
||||
spawnedCharacter.GiveJobItems(mainSubWaypoints[i]);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
// talents are only avilable for players in online sessions, but modders or someone else might want to have them loaded anyway
|
||||
spawnedCharacter.LoadTalents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2431,6 +2445,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
roundStartTime = DateTime.Now;
|
||||
|
||||
startGameCoroutine = null;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -2455,6 +2470,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.AllowRespawn && missionAllowRespawn);
|
||||
msg.Write(serverSettings.AllowDisguises);
|
||||
msg.Write(serverSettings.AllowRewiring);
|
||||
msg.Write(serverSettings.AllowFriendlyFire);
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.UseRespawnShuttle);
|
||||
@@ -2619,8 +2635,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
Submarine.Unload();
|
||||
entityEventManager.Clear();
|
||||
Submarine.Unload();
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
Log("Round ended.", ServerLog.MessageType.ServerMessage);
|
||||
|
||||
@@ -3145,28 +3161,19 @@ namespace Barotrauma.Networking
|
||||
public void SendOrderChatMessage(OrderChatMessage message)
|
||||
{
|
||||
if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) { return; }
|
||||
//ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
|
||||
//check which clients can receive the message and apply distance effects
|
||||
foreach (Client client in ConnectedClients)
|
||||
{
|
||||
string modifiedMessage = message.Text;
|
||||
|
||||
if (message.Sender != null &&
|
||||
client.Character != null && !client.Character.IsDead)
|
||||
if (message.Sender != null && client.Character != null && !client.Character.IsDead)
|
||||
{
|
||||
//too far to hear the msg -> don't send
|
||||
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
|
||||
}
|
||||
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender), client);
|
||||
}
|
||||
|
||||
string myReceivedMessage = message.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage))
|
||||
if (!string.IsNullOrWhiteSpace(message.Text))
|
||||
{
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, myReceivedMessage, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.Text, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3462,15 +3469,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//gender = Gender.Male;
|
||||
//race = Race.White;
|
||||
//headSpriteId = 0;
|
||||
DebugConsole.Log("Received invalid characterinfo from \"" + sender.Name + "\"! { " + e.Message + " }");
|
||||
}
|
||||
int hairIndex = message.ReadByte();
|
||||
int beardIndex = message.ReadByte();
|
||||
int moustacheIndex = message.ReadByte();
|
||||
int faceAttachmentIndex = message.ReadByte();
|
||||
Color skinColor = message.ReadColorR8G8B8();
|
||||
Color hairColor = message.ReadColorR8G8B8();
|
||||
Color facialHairColor = message.ReadColorR8G8B8();
|
||||
|
||||
List<Pair<JobPrefab, int>> jobPreferences = new List<Pair<JobPrefab, int>>();
|
||||
int count = message.ReadByte();
|
||||
@@ -3487,6 +3494,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
|
||||
sender.CharacterInfo.RecreateHead(headSpriteId, race, gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||
sender.CharacterInfo.SkinColor = skinColor;
|
||||
sender.CharacterInfo.HairColor = hairColor;
|
||||
sender.CharacterInfo.FacialHairColor = facialHairColor;
|
||||
|
||||
if (jobPreferences.Count > 0)
|
||||
{
|
||||
@@ -3786,7 +3796,7 @@ namespace Barotrauma.Networking
|
||||
return preferredClient;
|
||||
}
|
||||
|
||||
public void UpdateMissionState(Mission mission, int state)
|
||||
public void UpdateMissionState(Mission mission)
|
||||
{
|
||||
foreach (var client in connectedClients)
|
||||
{
|
||||
@@ -3794,7 +3804,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)ServerPacketHeader.MISSION);
|
||||
int missionIndex = GameMain.GameSession.GetMissionIndex(mission);
|
||||
msg.Write((byte)(missionIndex == -1 ? 255: missionIndex));
|
||||
msg.Write((ushort)state);
|
||||
mission?.ServerWrite(msg);
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,14 +518,22 @@ namespace Barotrauma
|
||||
AdjustKarma(character, karmaIncrease, "Repaired item");
|
||||
}
|
||||
|
||||
public void OnReactorOverHeating(Character character, float deltaTime)
|
||||
public void OnReactorOverHeating(Item reactor, Character character, float deltaTime)
|
||||
{
|
||||
AdjustKarma(character, -ReactorOverheatKarmaDecrease * deltaTime, "Caused reactor to overheat");
|
||||
if (reactor?.Submarine == null || character == null) { return; }
|
||||
if (reactor.Submarine.TeamID == CharacterTeamType.FriendlyNPC || reactor.Submarine.TeamID == character.TeamID)
|
||||
{
|
||||
AdjustKarma(character, -ReactorOverheatKarmaDecrease * deltaTime, "Caused reactor to overheat");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReactorMeltdown(Character character)
|
||||
public void OnReactorMeltdown(Item reactor, Character character)
|
||||
{
|
||||
AdjustKarma(character, -ReactorMeltdownKarmaDecrease, "Caused a reactor meltdown");
|
||||
if (reactor?.Submarine == null || character == null) { return; }
|
||||
if (reactor.Submarine.TeamID == CharacterTeamType.FriendlyNPC || reactor.Submarine.TeamID == character.TeamID)
|
||||
{
|
||||
AdjustKarma(character, -ReactorMeltdownKarmaDecrease, "Caused a reactor meltdown");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnExtinguishingFire(Character character, float deltaTime)
|
||||
|
||||
+4
-4
@@ -44,11 +44,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
class ServerEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ServerEntityEvent> events;
|
||||
private readonly List<ServerEntityEvent> events;
|
||||
|
||||
//list of unique events (i.e. !IsDuplicate) created during the round
|
||||
//used for syncing clients who join mid-round
|
||||
private List<ServerEntityEvent> uniqueEvents;
|
||||
private readonly List<ServerEntityEvent> uniqueEvents;
|
||||
|
||||
private UInt16 lastSentToAll;
|
||||
private UInt16 lastSentToAnyone;
|
||||
@@ -90,11 +90,11 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private List<BufferedEvent> bufferedEvents;
|
||||
private readonly List<BufferedEvent> bufferedEvents;
|
||||
|
||||
private UInt16 ID;
|
||||
|
||||
private GameServer server;
|
||||
private readonly GameServer server;
|
||||
|
||||
private double lastEventCountHighWarning;
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class RespawnManager : Entity, IServerSerializable
|
||||
{
|
||||
/// <summary>
|
||||
/// How much skills drop towards the job's default skill levels when respawning midround in the campaign
|
||||
/// </summary>
|
||||
const float SkillReductionOnCampaignMidroundRespawn = 0.75f;
|
||||
|
||||
private DateTime despawnTime;
|
||||
|
||||
private float shuttleEmptyTimer;
|
||||
@@ -284,6 +289,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
||||
{
|
||||
respawnedCharacters.Clear();
|
||||
|
||||
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
||||
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||
@@ -300,7 +307,7 @@ namespace Barotrauma.Networking
|
||||
if (matchingData != null && !matchingData.HasSpawned)
|
||||
{
|
||||
c.CharacterInfo = matchingData.CharacterInfo;
|
||||
}
|
||||
}
|
||||
|
||||
//all characters are in Team 1 in game modes/missions with only one team.
|
||||
//if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked
|
||||
@@ -355,8 +362,28 @@ namespace Barotrauma.Networking
|
||||
|
||||
characterInfos[i].ClearCurrentOrders();
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot);
|
||||
bool forceSpawnInMainSub = false;
|
||||
if (!bot && campaign != null)
|
||||
{
|
||||
var matchingData = campaign?.GetClientCharacterData(clients[i]);
|
||||
if (matchingData != null)
|
||||
{
|
||||
if (!matchingData.HasSpawned)
|
||||
{
|
||||
forceSpawnInMainSub = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReduceCharacterSkills(characterInfos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var character = Character.Create(characterInfos[i], (forceSpawnInMainSub ? mainSubSpawnPoints[i] : shuttleSpawnPoints[i]).WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot);
|
||||
character.TeamID = CharacterTeamType.Team1;
|
||||
character.LoadTalents();
|
||||
|
||||
respawnedCharacters.Add(character);
|
||||
|
||||
if (bot)
|
||||
{
|
||||
@@ -364,6 +391,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && character.Info != null)
|
||||
{
|
||||
character.Info.SetExperience(Math.Max(character.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(clients[i])));
|
||||
mpCampaign.ClearSavedExperiencePoints(clients[i]);
|
||||
}
|
||||
|
||||
//tell the respawning client they're no longer a traitor
|
||||
if (GameMain.Server.TraitorManager?.Traitors != null && clients[i].Character != null)
|
||||
{
|
||||
@@ -455,6 +488,17 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReduceCharacterSkills(CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterInfo?.Job == null) { return; }
|
||||
foreach (Skill skill in characterInfo.Job.Skills)
|
||||
{
|
||||
var skillPrefab = characterInfo.Job.Prefab.Skills.Find(s => skill.Prefab == s);
|
||||
if (skillPrefab == null) { continue; }
|
||||
skill.Level = MathHelper.Lerp(skill.Level, skillPrefab.LevelRange.X, SkillReductionOnCampaignMidroundRespawn);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)CurrentState, 0, Enum.GetNames(typeof(State)).Length);
|
||||
|
||||
@@ -163,9 +163,7 @@ namespace Barotrauma.Networking
|
||||
RadiationEnabled = incMsg.ReadBoolean();
|
||||
|
||||
int maxMissionCount = MaxMissionCount + incMsg.ReadByte() - 1;
|
||||
if (maxMissionCount < CampaignSettings.MinMissionCountLimit) maxMissionCount = CampaignSettings.MaxMissionCountLimit;
|
||||
if (maxMissionCount > CampaignSettings.MaxMissionCountLimit) maxMissionCount = CampaignSettings.MinMissionCountLimit;
|
||||
MaxMissionCount = maxMissionCount;
|
||||
MaxMissionCount = MathHelper.Clamp(maxMissionCount, CampaignSettings.MinMissionCountLimit, CampaignSettings.MaxMissionCountLimit);
|
||||
|
||||
changed |= true;
|
||||
}
|
||||
@@ -267,7 +265,7 @@ namespace Barotrauma.Networking
|
||||
"192-255",
|
||||
"384-591",
|
||||
"1024-1279",
|
||||
"19968-40959","13312-19903","131072-15043983","15043985-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
|
||||
"19968-21327","21329-40959","13312-19903","131072-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
|
||||
};
|
||||
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", defaultAllowedClientNameChars);
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Barotrauma
|
||||
case VoteType.Mode:
|
||||
string modeIdentifier = inc.ReadString();
|
||||
GameModePreset mode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
|
||||
if (!mode.Votable) { break; }
|
||||
if (mode == null || !mode.Votable) { break; }
|
||||
sender.SetVote(voteType, mode);
|
||||
break;
|
||||
case VoteType.EndRound:
|
||||
|
||||
@@ -185,7 +185,10 @@ namespace Barotrauma
|
||||
{
|
||||
existingItems.Add(item);
|
||||
}
|
||||
Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory);
|
||||
Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory, null, item =>
|
||||
{
|
||||
item.AddTag("traitormissionitem");
|
||||
});
|
||||
target = null;
|
||||
}
|
||||
else if (allowExisting)
|
||||
|
||||
Reference in New Issue
Block a user