633e54b...7cc231b

commit 7cc231bc51890e7fde50bbac3413328dd7bc5189
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Wed Mar 20 14:23:06 2019 +0200

    Fixed server creating network events in Item.Load due to CreateServerEvent calls in some of the ItemComponent properties (e.g. LightComponent.IsOn). Caused syncing problems because the entity spawn events aren't created until the item has been loaded, leading to situations where clients fail to read events because the entity doesn't exist at their end yet (see #1293). TODO: get rid of console errors when attempting to create events during component initialization in the Item constructor.

commit ac1bf32edf125d95d56775e1e8ce54ac7671328c
Author: itchyOwl <lauri.harkanen@gmail.com>
Date:   Wed Mar 20 13:49:55 2019 +0200

    Fix Hammerhead attack causing warping. Adjust the targeting priorities.

commit e3e032d7c3a753397269bb4236c1494ab0809004
Author: itchyOwl <lauri.harkanen@gmail.com>
Date:   Wed Mar 20 13:48:47 2019 +0200

    Enemy AI fixes:
    - Fix enemies "fleeing" after they have been shot. There was a steering issue when they targeted characters that were inside the sub when they were outside of it
    - Fix the previous target resetting too often
    - Fix the wall target resetting too often
    - Use world positions instead of sim positions where possible, because the sub positions are then taken into account

commit 847cf5ffd9212a542000dbf12332b2c08756579a
Author: Daniel Asteljoki <daniel.asteljoki@gmail.com>
Date:   Wed Mar 20 12:00:15 2019 +0200

    Remora: added power connection between sub and drone, removed non-scaling hull parts

commit a9c2e8cc124713e90dd44a9adf2fcbb3204b2c4d
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Wed Mar 20 11:24:37 2019 +0200

    Server sets clients' last received campaign save/update IDs to one before the current up-to-date IDs (instead of zero) when a campaign changes. Zero would get interpreted as a more up-to-date ID if the IDs of the current campaign are close to ushort.MaxValue where the IDs wrap around.

commit 07d82b64e6990eacaf8905aed1a5d7c61224e47d
Author: Joonas Rikkonen <poe.regalis@gmail.com>
Date:   Tue Mar 19 18:24:01 2019 +0200

    Log level inequality error messages & client error reports handled by the server to GameAnalytics
This commit is contained in:
Joonas Rikkonen
2019-03-20 14:25:03 +02:00
parent 6a12058148
commit 81fafaf3f5
16 changed files with 139 additions and 120 deletions

View File

@@ -24,7 +24,7 @@ namespace Barotrauma
if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
wallTargetPos.Y = -wallTargetPos.Y;
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red);

View File

@@ -1103,8 +1103,9 @@ namespace Barotrauma.Networking
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
{
string errorMsg = " Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
DebugConsole.ThrowError(errorMsg, createMessageBox: true);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch"+levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}

View File

@@ -4,11 +4,6 @@ namespace Barotrauma
{
partial class CharacterInfo
{
partial void SpawnInventoryItemProjSpecific(Item item)
{
Entity.Spawner.CreateNetworkEvent(item, false);
}
public void ServerWrite(NetBuffer msg)
{
msg.Write(ID);

View File

@@ -335,6 +335,14 @@ namespace Barotrauma
{
if (GameMain.Server == null) return;
if (!ItemList.Contains(this))
{
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}
int index = components.IndexOf(ic);
if (index == -1) return;

View File

@@ -782,6 +782,7 @@ namespace Barotrauma.Networking
}
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:LevelsDontMatch" + error, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
KickClient(c, errorStr);
}
@@ -839,8 +840,8 @@ namespace Barotrauma.Networking
//(the server started a new campaign and the client isn't aware of it yet?)
if (campaign.CampaignID != campaignID)
{
c.LastRecvCampaignSave = 0;
c.LastRecvCampaignUpdate = 0;
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
}
}
}

View File

@@ -74,6 +74,8 @@
<Submarine file="Submarines/Bunyip.sub" />
<Submarine file="Submarines/Humpback.sub" />
<Submarine file="Submarines/Dugong.sub" />
<Submarine file="Submarines/Remora.sub" />
<Submarine file="Submarines/RemoraDrone.sub" />
<Text file="Content/Texts/EnglishVanilla.xml" />
<UIStyle file="Content/UI/style.xml"/>
<Afflictions file="Content/Afflictions.xml"/>

View File

@@ -3129,8 +3129,10 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Remora.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\RemoraDrone.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Typhon.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@@ -419,12 +419,7 @@ namespace Barotrauma
selectedTargetMemory.Priority -= deltaTime * 0.1f;
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition) : SelectedAiTarget.SimPosition;
if (Character.Submarine != null && SelectedAiTarget.Entity.Submarine != null && Character.Submarine != SelectedAiTarget.Entity.Submarine)
{
attackSimPosition = ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition - Character.Submarine.Position);
}
Vector2 attackPos = SelectedAiTarget.WorldPosition;
if (SelectedAiTarget.Entity is Item item)
{
@@ -440,35 +435,6 @@ namespace Barotrauma
}
}
if (wallTarget != null)
{
attackSimPosition = ConvertUnits.ToSimUnits(wallTarget.Position);
if (Character.Submarine == null && SelectedAiTarget.Entity?.Submarine != null)
{
attackSimPosition += ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
}
}
else if (SelectedAiTarget.Entity is Character c)
{
//target the closest limb if the target is a character
float closestDist = Vector2.DistanceSquared(SelectedAiTarget.SimPosition, SimPosition) * 10.0f;
foreach (Limb limb in ((Character)SelectedAiTarget.Entity).AnimController.Limbs)
{
if (limb == null) continue;
float dist = Vector2.DistanceSquared(limb.SimPosition, SimPosition) / Math.Max(limb.AttackPriority, 0.1f);
if (dist < closestDist)
{
closestDist = dist;
attackSimPosition = limb.SimPosition;
}
}
}
if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater)
{
Character.AnimController.TargetDir = Character.SimPosition.X < attackSimPosition.X ? Direction.Right : Direction.Left;
}
if (raycastTimer > 0.0)
{
raycastTimer -= deltaTime;
@@ -479,6 +445,35 @@ namespace Barotrauma
raycastTimer = RaycastInterval;
}
if (wallTarget != null)
{
attackPos = wallTarget.Position;
if (Character.Submarine == null && wallTarget.Structure.Submarine != null)
{
attackPos += wallTarget.Structure.Submarine.Position;
}
}
else if (SelectedAiTarget.Entity is Character c)
{
//target the closest limb if the target is a character
float closestDist = Vector2.DistanceSquared(SelectedAiTarget.WorldPosition, WorldPosition) * 10.0f;
foreach (Limb limb in c.AnimController.Limbs)
{
if (limb == null) continue;
float dist = Vector2.DistanceSquared(limb.WorldPosition, WorldPosition) / Math.Max(limb.AttackPriority, 0.1f);
if (dist < closestDist)
{
closestDist = dist;
attackPos = limb.WorldPosition;
}
}
}
if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater)
{
Character.AnimController.TargetDir = Character.WorldPosition.X < attackPos.X ? Direction.Right : Direction.Left;
}
if (aggressiveBoarding)
{
//targeting a wall section that can be passed through -> steer manually through the hole
@@ -511,9 +506,9 @@ namespace Barotrauma
return;
}
}
else if (SelectedAiTarget.Entity is Item)
else if (SelectedAiTarget.Entity is Item i)
{
var door = ((Item)SelectedAiTarget.Entity).GetComponent<Door>();
var door = i.GetComponent<Door>();
//steer through the door manually if it's open or broken
if (door?.LinkedGap?.FlowTargetHull != null && !door.LinkedGap.IsRoomToRoom && (door.IsOpen || door.Item.Condition <= 0.0f))
{
@@ -556,7 +551,7 @@ namespace Barotrauma
}
else
{
UpdateFallBack(attackSimPosition, deltaTime);
UpdateFallBack(attackPos, deltaTime);
return;
}
}
@@ -564,14 +559,14 @@ namespace Barotrauma
{
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0)
{
// Don't allow attacking when the attack target has changed.
// Don't allow attacking when the attack target has just changed.
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
{
canAttack = false;
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
{
// Fall back if cannot attack.
UpdateFallBack(attackSimPosition, deltaTime);
UpdateFallBack(attackPos, deltaTime);
return;
}
attackingLimb = null;
@@ -580,7 +575,7 @@ namespace Barotrauma
{
// If the secondary cooldown is defined and expired, check if we can switch the attack
var previousLimb = attackingLimb;
var newLimb = GetAttackLimb(attackSimPosition, previousLimb);
var newLimb = GetAttackLimb(attackPos, previousLimb);
if (newLimb != null)
{
attackingLimb = newLimb;
@@ -594,7 +589,7 @@ namespace Barotrauma
}
else
{
UpdateFallBack(attackSimPosition, deltaTime);
UpdateFallBack(attackPos, deltaTime);
return;
}
}
@@ -609,7 +604,7 @@ namespace Barotrauma
break;
case AIBehaviorAfterAttack.FallBack:
default:
UpdateFallBack(attackSimPosition, deltaTime);
UpdateFallBack(attackPos, deltaTime);
return;
}
@@ -617,7 +612,7 @@ namespace Barotrauma
if (attackingLimb == null)
{
attackingLimb = GetAttackLimb(attackSimPosition);
attackingLimb = GetAttackLimb(attackPos);
}
if (canAttack)
{
@@ -627,18 +622,18 @@ namespace Barotrauma
if (canAttack)
{
// Check that we can reach the target
distance = ConvertUnits.ToDisplayUnits(Vector2.Distance(attackingLimb.SimPosition, attackSimPosition));
distance = Vector2.Distance(attackingLimb.WorldPosition, attackPos);
canAttack = distance < attackingLimb.attack.Range;
}
Limb steeringLimb = Character.AnimController.MainLimb;
if (steeringLimb != null)
{
Vector2 steeringVector = attackSimPosition - steeringLimb.SimPosition;
Vector2 targetingVector = Vector2.Normalize(steeringVector) * attackingLimb.attack.Range;
Vector2 toTarget = Vector2.Normalize(attackPos - steeringLimb.WorldPosition);
Vector2 targetingVector = toTarget * attackingLimb.attack.Range;
// Offset the position a bit so that we don't overshoot the movement.
Vector2 steerPos = attackSimPosition + targetingVector;
steeringManager.SteeringSeek(steerPos, 10);
Vector2 steerPos = attackPos + targetingVector;
steeringManager.SteeringSeek(ConvertUnits.ToSimUnits(attackPos), 10);
if (Character.CurrentHull == null)
{
SteeringManager.SteeringAvoid(deltaTime, colliderSize * 1.5f);
@@ -656,7 +651,7 @@ namespace Barotrauma
}
else if (indoorsSteering.CurrentPath.Finished)
{
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(steeringVector));
steeringManager.SteeringManual(deltaTime, toTarget);
}
else if (indoorsSteering.CurrentPath.CurrentNode?.ConnectedDoor != null)
{
@@ -674,11 +669,11 @@ namespace Barotrauma
if (canAttack)
{
UpdateLimbAttack(deltaTime, attackingLimb, attackSimPosition, distance);
UpdateLimbAttack(deltaTime, attackingLimb, ConvertUnits.ToSimUnits(attackPos), distance);
}
}
private Limb GetAttackLimb(Vector2 attackSimPosition, Limb ignoredLimb = null)
private Limb GetAttackLimb(Vector2 attackWorldPos, Limb ignoredLimb = null)
{
AttackContext currentContext = Character.GetAttackContext();
var target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity;
@@ -692,7 +687,7 @@ namespace Barotrauma
l.attack.IsValidTarget(target) &&
l.attack.Conditionals.All(c => (target is ISerializableEntity se && c.Matches(se)) || !(target is ISerializableEntity) || !(target is Character)))
.OrderByDescending(l => l.attack.Priority)
.ThenBy(l => ConvertUnits.ToDisplayUnits(Vector2.Distance(l.SimPosition, attackSimPosition)));
.ThenBy(l => Vector2.Distance(l.WorldPosition, attackWorldPos));
// TODO: priority should probably not override the distance -> use values instead of booleans
return limbs.FirstOrDefault();
}
@@ -705,12 +700,13 @@ namespace Barotrauma
{
return;
}
//check if there's a wall between the target and the Character
Vector2 rayStart = Character.SimPosition;
Vector2 rayEnd = SelectedAiTarget.SimPosition;
bool offset = SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null;
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
if (offset)
{
rayStart -= ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
}
@@ -721,18 +717,7 @@ namespace Barotrauma
return;
}
Structure wall = closestBody.UserData as Structure;
if (wall?.Submarine == null)
{
return;
/*if (selectedAiTarget.Entity.Submarine != null)
{
wallTarget = new WallTarget(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition), selectedAiTarget.Entity.Submarine);
latchOntoAI?.SetAttachTarget(closestBody, selectedAiTarget.Entity.Submarine, Submarine.LastPickedPosition);
}*/
//if (selectedAiTarget.Entity.Submarine != null && Character.Submarine == null) wallAttackPos += ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
}
else
if (closestBody.UserData is Structure wall && wall.Submarine != null)
{
int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
int passableHoleCount = GetMinimumPassableHoleCount();
@@ -755,36 +740,27 @@ namespace Barotrauma
if (wall.SectionDamage(i) > sectionDamage) sectionIndex = i;
}
Vector2 sectionPos = ConvertUnits.ToSimUnits(wall.SectionPosition(sectionIndex));
Vector2 sectionPos = wall.SectionPosition(sectionIndex);
Vector2 attachTargetNormal;
if (wall.IsHorizontal)
{
attachTargetNormal = new Vector2(0.0f, Math.Sign(Character.WorldPosition.Y - wall.WorldPosition.Y));
sectionPos.Y += ConvertUnits.ToSimUnits((wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2) * attachTargetNormal.Y;
sectionPos.Y += (wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2 * attachTargetNormal.Y;
}
else
{
attachTargetNormal = new Vector2(Math.Sign(Character.WorldPosition.X - wall.WorldPosition.X), 0.0f);
sectionPos.X += ConvertUnits.ToSimUnits((wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2) * attachTargetNormal.X;
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
}
wallTarget = new WallTarget(ConvertUnits.ToDisplayUnits(sectionPos), wall, sectionIndex);
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, sectionPos, attachTargetNormal);
wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
}
}
public override void OnAttacked(Character attacker, AttackResult attackResult)
{
updateTargetsTimer = Math.Min(updateTargetsTimer, 0.1f);
// Reduce the cooldown so that the character can react
foreach (var limb in Character.AnimController.Limbs)
{
if (limb.attack != null)
{
limb.attack.CoolDownTimer *= 0.1f;
// secondary cooldown?
}
}
if (attackResult.Damage > 0.0f && attackWhenProvoked)
{
@@ -801,18 +777,31 @@ namespace Barotrauma
if (attacker == null || attacker.AiTarget == null) return;
AITargetMemory targetMemory = FindTargetMemory(attacker.AiTarget);
targetMemory.Priority += GetRelativeDamage(attackResult.Damage, Character.Vitality) * aggressionhurt;
// Reduce the cooldown so that the character can react
// Only allow to react once. Otherwise would attack the target with only a fraction of cooldown
if (SelectedAiTarget != attacker.AiTarget)
{
foreach (var limb in Character.AnimController.Limbs)
{
if (limb.attack != null)
{
limb.attack.CoolDownTimer *= 0.1f;
}
}
}
}
// 10 dmg, 100 health -> 0.1
private float GetRelativeDamage(float dmg, float vitality) => dmg / Math.Max(vitality, 1.0f);
private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackPosition, float distance = -1)
private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackSimPos, float distance = -1)
{
var damageTarget = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity as IDamageable;
if (damageTarget == null) return;
float prevHealth = damageTarget.Health;
if (limb.UpdateAttack(deltaTime, attackPosition, damageTarget, out AttackResult attackResult, distance))
if (limb.UpdateAttack(deltaTime, attackSimPos, damageTarget, out AttackResult attackResult, distance))
{
if (damageTarget.Health > 0)
{
@@ -820,24 +809,19 @@ namespace Barotrauma
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * aggressiongreed;
}
}
if (!limb.attack.IsRunning)
{
wallTarget = null;
}
}
private void UpdateFallBack(Vector2 attackPosition, float deltaTime)
{
float dist = Vector2.Distance(attackPosition, Character.SimPosition);
Vector2 attackVector = attackPosition - Character.WorldPosition;
float dist = attackVector.Length();
float desiredDist = colliderSize * 2.0f;
if (dist < desiredDist)
{
Vector2 attackDir = Vector2.Normalize(Character.SimPosition - attackPosition);
Vector2 attackDir = Vector2.Normalize(-attackVector);
if (!MathUtils.IsValid(attackDir)) attackDir = Vector2.UnitY;
steeringManager.SteeringManual(deltaTime, attackDir * (1.0f - (dist / 500.0f)));
}
steeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f);
}
@@ -888,8 +872,8 @@ namespace Barotrauma
//sight/hearing range
public void UpdateTargets(Character character, out TargetingPriority targetingPriority)
{
AITarget newTarget = null;
targetingPriority = null;
SelectedAiTarget = null;
selectedTargetMemory = null;
targetValue = 0.0f;
@@ -1021,13 +1005,15 @@ namespace Barotrauma
if (valueModifier > targetValue)
{
SelectedAiTarget = target;
newTarget = target;
selectedTargetMemory = targetMemory;
targetingPriority = targetingPriorities[targetingTag];
targetValue = valueModifier;
}
}
SelectedAiTarget = newTarget;
if (SelectedAiTarget != _previousAiTarget)
{
wallTarget = null;

View File

@@ -801,7 +801,7 @@ namespace Barotrauma
{
foreach (XElement itemElement in element.Elements())
{
var newItem = Item.Load(itemElement, inventory.Owner.Submarine);
var newItem = Item.Load(itemElement, inventory.Owner.Submarine, createNetworkEvent: true);
if (newItem == null) { continue; }
int[] slotIndices = itemElement.GetAttributeIntArray("i", new int[] { 0 });
@@ -810,9 +810,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Invalid inventory data in character \"" + Name + "\" - no slot indices found");
continue;
}
SpawnInventoryItemProjSpecific(newItem);
inventory.TryPutItem(newItem, slotIndices[0], false, false, null);
//force the item to the correct slots
@@ -842,8 +840,6 @@ namespace Barotrauma
}
}
partial void SpawnInventoryItemProjSpecific(Item item);
public void ReloadHeadAttachments()
{
ResetLoadedAttachments();

View File

@@ -491,10 +491,10 @@ namespace Barotrauma
/// <summary>
/// Returns true if the attack successfully hit something. If the distance is not given, it will be calculated.
/// </summary>
public bool UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget, out AttackResult attackResult, float distance = -1)
public bool UpdateAttack(float deltaTime, Vector2 attackSimPos, IDamageable damageTarget, out AttackResult attackResult, float distance = -1)
{
attackResult = default(AttackResult);
float dist = distance > -1 ? distance : ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));
float dist = distance > -1 ? distance : ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackSimPos));
bool wasRunning = attack.IsRunning;
attack.UpdateAttackTimer(deltaTime);
@@ -511,7 +511,7 @@ namespace Barotrauma
ignoredBodies.Add(character.AnimController.Collider.FarseerBody);
structureBody = Submarine.PickBody(
SimPosition, attackPosition,
SimPosition, attackSimPos,
ignoredBodies, Physics.CollisionWall);
if (damageTarget is Item)
@@ -607,7 +607,7 @@ namespace Barotrauma
attack.SetCoolDown();
}
Vector2 diff = attackPosition - SimPosition;
Vector2 diff = attackSimPos - SimPosition;
bool applyForces = (!attack.ApplyForcesOnlyOnce || !wasRunning) && diff.LengthSquared() > 0.00001f;
if (applyForces)
{
@@ -620,13 +620,13 @@ namespace Barotrauma
Limb limb = character.AnimController.Limbs[limbIndex];
Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos);
}
}
else
{
Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos);
}
}
return wasHit;

View File

@@ -60,7 +60,6 @@ namespace Barotrauma
public readonly XElement StaticBodyConfig;
private bool needsPositionUpdate;
private float lastSentCondition;
private float condition;
@@ -1811,8 +1810,20 @@ namespace Barotrauma
}
partial void UpdateNetPosition(float deltaTime);
public static Item Load(XElement element, Submarine submarine)
{
return Load(element, submarine, createNetworkEvent: false);
}
/// <summary>
/// Instantiate a new item and load its data from the XML element.
/// </summary>
/// <param name="element">The element containing the data of the item</param>
/// <param name="submarine">The submarine to spawn the item in (can be null)</param>
/// <param name="createNetworkEvent">Should an EntitySpawner event be created to notify clients about the item being created.</param>
/// <returns></returns>
public static Item Load(XElement element, Submarine submarine, bool createNetworkEvent)
{
string name = element.Attribute("name").Value;
string identifier = element.GetAttributeString("identifier", "");
@@ -1858,6 +1869,13 @@ namespace Barotrauma
linkedToID = new List<ushort>()
};
#if SERVER
if (createNetworkEvent)
{
Spawner.CreateNetworkEvent(item, remove: false);
}
#endif
foreach (XAttribute attribute in element.Attributes())
{
if (!item.properties.TryGetValue(attribute.Name.ToString(), out SerializableProperty property)) continue;
@@ -1904,7 +1922,7 @@ namespace Barotrauma
{
component.OnItemLoaded();
}
return item;
}

View File

@@ -91,6 +91,16 @@ namespace Barotrauma
public override void CreateNetworkEvent()
{
if (!Item.ItemList.Contains(container.Item))
{
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}
int componentIndex = container.Item.GetComponentIndex(container);
if (componentIndex == -1)
{

View File

@@ -407,7 +407,7 @@ namespace Barotrauma
try
{
MethodInfo loadMethod = t.GetMethod("Load");
MethodInfo loadMethod = t.GetMethod("Load", new [] { typeof(XElement), typeof(Submarine) });
if (loadMethod == null)
{
DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");

View File

@@ -70,7 +70,7 @@ namespace Barotrauma
private readonly Queue<IEntitySpawnInfo> spawnQueue;
private readonly Queue<Entity> removeQueue;
class SpawnOrRemove
public class SpawnOrRemove
{
public readonly Entity Entity;