public static void Update(float deltaTime, Character character, Camera cam) { if (GUI.DisableHUD) { return; } if (!character.IsIncapacitated && character.Stun <= 0.0f) { if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null) { bool mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null; if (mouseOnPortrait && PlayerInput.PrimaryMouseButtonClicked()) { CharacterHealth.OpenHealthWindow = character.CharacterHealth; } } if (character.Inventory != null) { if (!LockInventory(character)) { character.Inventory.Update(deltaTime, cam); } for (int i = 0; i < character.Inventory.Items.Length - 1; i++) { var item = character.Inventory.Items[i]; if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) { continue; } foreach (ItemComponent ic in item.Components) { if (ic.DrawHudWhenEquipped) { ic.UpdateHUD(character, deltaTime, cam); } } } } if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null) { if (character.SelectedCharacter.CanInventoryBeAccessed) { character.SelectedCharacter.Inventory.Update(deltaTime, cam); } character.SelectedCharacter.CharacterHealth.UpdateHUD(deltaTime); } Inventory.UpdateDragging(); } if (focusedItem != null) { if (character.FocusedItem != null) { focusedItemOverlayTimer = Math.Min(focusedItemOverlayTimer + deltaTime, ItemOverlayDelay + 1.0f); } else { focusedItemOverlayTimer = Math.Max(focusedItemOverlayTimer - deltaTime, 0.0f); if (focusedItemOverlayTimer <= 0.0f) { focusedItem = null; shouldRecreateHudTexts = true; } } } if (brokenItemsCheckTimer > 0.0f) { brokenItemsCheckTimer -= deltaTime; } else { brokenItems.Clear(); brokenItemsCheckTimer = 1.0f; foreach (Item item in Item.ItemList) { if (item.Submarine == null || item.Submarine.TeamID != character.TeamID || item.Submarine.Info.IsWreck) { continue; } if (!item.Repairables.Any(r => item.ConditionPercentage <= r.RepairThreshold)) { continue; } if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; } Vector2 diff = item.WorldPosition - character.WorldPosition; if (Submarine.CheckVisibility(character.SimPosition, character.SimPosition + ConvertUnits.ToSimUnits(diff)) == null) { brokenItems.Add(item); } } } }
public static void UpdateDragging() { if (draggingItem != null && PlayerInput.LeftButtonReleased()) { Character.Controlled.ClearInputs(); if (CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.OnItemDropped(draggingItem, false)) { draggingItem = null; return; } if (selectedSlot == null) { if (DraggingItemToWorld && Character.Controlled.FocusedItem?.OwnInventory != null && Character.Controlled.FocusedItem.OwnInventory.CanBePut(draggingItem) && Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled)) { GUI.PlayUISound(GUISoundType.PickItem); } else { GUI.PlayUISound(GUISoundType.DropItem); draggingItem.Drop(Character.Controlled); } } else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem) { Inventory selectedInventory = selectedSlot.ParentInventory; int slotIndex = selectedSlot.SlotIndex; if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled)) { if (selectedInventory.slots != null) { selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f); } GUI.PlayUISound(GUISoundType.PickItem); } else { if (selectedInventory.slots != null) { selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f); } GUI.PlayUISound(GUISoundType.PickItemFail); } selectedInventory.HideTimer = 1.0f; if (selectedSlot.ParentInventory?.Owner is Item parentItem && parentItem.ParentInventory != null) { for (int i = 0; i < parentItem.ParentInventory.capacity; i++) { if (parentItem.ParentInventory.HideSlot(i)) { continue; } if (parentItem.ParentInventory.Items[i] != parentItem) { continue; } highlightedSubInventorySlots.Add(new SlotReference( parentItem.ParentInventory, parentItem.ParentInventory.slots[i], i, false, selectedSlot.ParentInventory)); break; } } draggingItem = null; draggingSlot = null; } draggingItem = null; } if (selectedSlot != null && !selectedSlot.Slot.MouseOn()) { selectedSlot = null; } }
public static void DrawSlot(SpriteBatch spriteBatch, Inventory inventory, InventorySlot slot, Item item, bool drawItem = true) { Rectangle rect = slot.Rect; rect.Location += slot.DrawOffset.ToPoint(); if (slot.HighlightColor.A > 0) { float inflateAmount = (slot.HighlightColor.A / 255.0f) * slot.HighlightScaleUpAmount * 0.5f; rect.Inflate(rect.Width * inflateAmount, rect.Height * inflateAmount); } var itemContainer = item?.GetComponent <ItemContainer>(); if (itemContainer != null && (itemContainer.InventoryTopSprite != null || itemContainer.InventoryBottomSprite != null)) { if (!highlightedSubInventorySlots.Any(s => s.Slot == slot)) { itemContainer.InventoryBottomSprite?.Draw(spriteBatch, new Vector2(rect.Center.X, rect.Y), 0, UIScale); itemContainer.InventoryTopSprite?.Draw(spriteBatch, new Vector2(rect.Center.X, rect.Y), 0, UIScale); } drawItem = false; } else { Sprite slotSprite = slot.SlotSprite ?? slotSpriteSmall; Color slotColor = slot.IsHighlighted ? Color.White : Color.White * 0.8f; if (inventory != null && inventory.Locked) { slotColor = Color.Gray * 0.5f; } spriteBatch.Draw(slotSprite.Texture, rect, slotSprite.SourceRect, slotColor); if (item != null && drawItem) { if (!item.IsFullCondition && (itemContainer == null || !itemContainer.ShowConditionInContainedStateIndicator)) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, rect.Width, 8), Color.Black * 0.8f, true); GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * item.Condition / item.MaxCondition), 8), Color.Lerp(Color.Red, Color.Green, item.Condition / item.MaxCondition) * 0.8f, true); } if (itemContainer != null) { float containedState = 0.0f; if (itemContainer.ShowConditionInContainedStateIndicator) { containedState = item.Condition / item.MaxCondition; } else { containedState = itemContainer.Inventory.Capacity == 1 ? (itemContainer.Inventory.Items[0] == null ? 0.0f : itemContainer.Inventory.Items[0].Condition / itemContainer.Inventory.Items[0].MaxCondition) : itemContainer.Inventory.Items.Count(i => i != null) / (float)itemContainer.Inventory.capacity; } int dir = slot.SubInventoryDir; Rectangle containedIndicatorArea = new Rectangle(rect.X, dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight); containedIndicatorArea.Inflate(-4, 0); if (itemContainer.ContainedStateIndicator?.Texture == null) { containedIndicatorArea.Inflate(0, -2); GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.DarkGray * 0.9f, true); GUI.DrawRectangle(spriteBatch, new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height), Color.Lerp(Color.Red, Color.Green, containedState) * 0.8f, true); } else { Sprite indicatorSprite = itemContainer.ContainedStateIndicator; float indicatorScale = Math.Min( containedIndicatorArea.Width / (float)indicatorSprite.SourceRect.Width, containedIndicatorArea.Height / (float)indicatorSprite.SourceRect.Height); if (containedState >= 0.0f && containedState < 0.25f) { indicatorScale += ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) * 0.25f; } indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(), (inventory != null && inventory.Locked) ? Color.DarkGray * 0.5f : Color.DarkGray * 0.9f, origin: indicatorSprite.size / 2, rotate: 0.0f, scale: indicatorScale); Color indicatorColor = ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.Green); if (inventory != null && inventory.Locked) { indicatorColor *= 0.5f; } spriteBatch.Draw(indicatorSprite.Texture, containedIndicatorArea.Center.ToVector2(), sourceRectangle: new Rectangle(indicatorSprite.SourceRect.Location, new Point((int)(indicatorSprite.SourceRect.Width * containedState), indicatorSprite.SourceRect.Height)), color: indicatorColor, rotation: 0.0f, origin: indicatorSprite.size / 2, scale: indicatorScale, effects: SpriteEffects.None, layerDepth: 0.0f); } } } } if (GameMain.DebugDraw) { GUI.DrawRectangle(spriteBatch, rect, Color.White, false, 0, 1); GUI.DrawRectangle(spriteBatch, slot.EquipButtonRect, Color.White, false, 0, 1); } if (slot.HighlightColor != Color.Transparent) { GUI.UIGlow.Draw(spriteBatch, rect, slot.HighlightColor); } if (item != null && drawItem) { Sprite sprite = item.Prefab.InventoryIcon ?? item.Sprite; float scale = Math.Min(Math.Min((rect.Width - 10) / sprite.size.X, (rect.Height - 10) / sprite.size.Y), 3.0f); Vector2 itemPos = rect.Center.ToVector2(); if (itemPos.Y > GameMain.GraphicsHeight) { itemPos.Y -= Math.Min( (itemPos.Y + sprite.size.Y / 2 * scale) - GameMain.GraphicsHeight, (itemPos.Y - sprite.size.Y / 2 * scale) - rect.Y); } float rotation = 0.0f; if (slot.HighlightColor.A > 0) { rotation = (float)Math.Sin(slot.HighlightTimer * MathHelper.TwoPi) * slot.HighlightTimer * 0.3f; } Color spriteColor = sprite == item.Sprite ? item.GetSpriteColor() : item.GetInventoryIconColor(); if (inventory != null && inventory.Locked) { spriteColor *= 0.5f; } if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface) { spriteColor = Color.Lerp(spriteColor, Color.TransparentBlack, 0.5f); } else { sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black * 0.6f, rotate: rotation, scale: scale); } sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale); } if (inventory != null && !inventory.Locked && Character.Controlled?.Inventory == inventory && slot.QuickUseKey != Keys.None) { GUI.DrawString(spriteBatch, rect.Location.ToVector2(), slot.QuickUseKey.ToString().Substring(1, 1), item == null || !drawItem ? Color.Gray : Color.White, Color.Black * 0.8f); } }
protected void Apply(float deltaTime, Entity entity, List <ISerializableEntity> targets, Vector2?worldPosition = null) { if (lifeTime > 0) { lifeTimer -= deltaTime; if (lifeTimer <= 0) { return; } } Hull hull = null; if (entity is Character) { hull = ((Character)entity).AnimController.CurrentHull; } else if (entity is Item) { hull = ((Item)entity).CurrentHull; } Vector2 position = worldPosition ?? entity.WorldPosition; if (targetLimb != LimbType.None) { if (entity is Character c) { Limb limb = c.AnimController.GetLimb(targetLimb); if (limb != null) { position = limb.WorldPosition; } } } foreach (ISerializableEntity serializableEntity in targets) { if (!(serializableEntity is Item item)) { continue; } Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character; if (targetCharacter == null) { foreach (var target in targets) { if (target is Limb limb && limb.character != null && !limb.character.Removed) { targetCharacter = ((Limb)target).character; } } } for (int i = 0; i < useItemCount; i++) { if (item.Removed) { continue; } item.Use(deltaTime, targetCharacter, targets.FirstOrDefault(t => t is Limb) as Limb); } } if (removeItem) { foreach (var target in targets) { if (target is Item item) { Entity.Spawner?.AddToRemoveQueue(item); } } } if (removeCharacter) { foreach (var target in targets) { if (target is Character character) { Entity.Spawner?.AddToRemoveQueue(character); } } } if (duration > 0.0f) { DurationListElement element = new DurationListElement { Parent = this, Timer = duration, Entity = entity, Targets = targets, User = user }; DurationList.Add(element); } else { foreach (ISerializableEntity target in targets) { if (target is Entity targetEntity) { if (targetEntity.Removed) { continue; } } for (int i = 0; i < propertyNames.Length; i++) { if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out SerializableProperty property)) { continue; } ApplyToProperty(target, property, propertyEffects[i], deltaTime); } } } if (explosion != null && entity != null) { explosion.Explode(position, damageSource: entity, attacker: user); } foreach (ISerializableEntity target in targets) { foreach (Affliction affliction in Afflictions) { Affliction multipliedAffliction = affliction; if (!disableDeltaTime) { multipliedAffliction = affliction.CreateMultiplied(deltaTime); } if (target is Character character) { if (character.Removed) { continue; } character.LastDamageSource = entity; foreach (Limb limb in character.AnimController.Limbs) { limb.character.DamageLimb(position, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability); //only apply non-limb-specific afflictions to the first limb if (!affliction.Prefab.LimbSpecific) { break; } } } else if (target is Limb limb) { if (limb.character.Removed) { continue; } limb.character.DamageLimb(position, limb, new List <Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); limb.character.TrySeverLimbJoints(limb, SeverLimbsProbability); } } foreach (Pair <string, float> reduceAffliction in ReduceAffliction) { float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime; Limb targetLimb = null; Character targetCharacter = null; if (target is Character character) { targetCharacter = character; } else if (target is Limb limb) { targetLimb = limb; targetCharacter = limb.character; } if (targetCharacter != null && !targetCharacter.Removed) { float prevVitality = targetCharacter.Vitality; targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAmount); #if SERVER GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, user, prevVitality - targetCharacter.Vitality); #endif } } } if (FireSize > 0.0f && entity != null) { var fire = new FireSource(position, hull); fire.Size = new Vector2(FireSize, fire.Size.Y); } bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient; if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn entities { foreach (CharacterSpawnInfo characterSpawnInfo in spawnCharacters) { var characters = new List <Character>(); for (int i = 0; i < characterSpawnInfo.Count; i++) { Entity.Spawner.AddToSpawnQueue(characterSpawnInfo.SpeciesName, position + Rand.Vector(characterSpawnInfo.Spread, Rand.RandSync.Server), onSpawn: newCharacter => { characters.Add(newCharacter); if (characters.Count == characterSpawnInfo.Count) { SwarmBehavior.CreateSwarm(characters.Cast <AICharacter>()); } }); } } foreach (ItemSpawnInfo itemSpawnInfo in spawnItems) { switch (itemSpawnInfo.SpawnPosition) { case ItemSpawnInfo.SpawnPositionType.This: Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, position); break; case ItemSpawnInfo.SpawnPositionType.ThisInventory: { if (entity is Character character) { if (character.Inventory != null && character.Inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory); } } else if (entity is Item item) { var inventory = item?.GetComponent <ItemContainer>()?.Inventory; if (inventory != null && inventory.Items.Any(it => it == null)) { Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory); } } } break; case ItemSpawnInfo.SpawnPositionType.ContainedInventory: { Inventory thisInventory = null; if (entity is Character character) { thisInventory = character.Inventory; } else if (entity is Item item) { thisInventory = item?.GetComponent <ItemContainer>()?.Inventory; } if (thisInventory != null) { foreach (Item item in thisInventory.Items) { if (item == null) { continue; } Inventory containedInventory = item.GetComponent <ItemContainer>()?.Inventory; if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) { continue; } Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory); break; } } } break; } } } ApplyProjSpecific(deltaTime, entity, targets, hull, position); }
public SlotReference(Inventory parentInventory, InventorySlot slot, int slotIndex, bool isSubSlot, Inventory subInventory = null) { ParentInventory = parentInventory; Slot = slot; SlotIndex = slotIndex; Inventory = subInventory; IsSubSlot = isSubSlot; }
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { switch (type) { case ServerNetObject.ENTITY_POSITION: bool facingRight = AnimController.Dir > 0.0f; lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now; AnimController.Frozen = false; Enabled = true; UInt16 networkUpdateID = 0; if (msg.ReadBoolean()) { networkUpdateID = msg.ReadUInt16(); } else { bool aimInput = msg.ReadBoolean(); keys[(int)InputType.Aim].Held = aimInput; keys[(int)InputType.Aim].SetState(false, aimInput); bool shootInput = msg.ReadBoolean(); keys[(int)InputType.Shoot].Held = shootInput; keys[(int)InputType.Shoot].SetState(false, shootInput); bool useInput = msg.ReadBoolean(); keys[(int)InputType.Use].Held = useInput; keys[(int)InputType.Use].SetState(false, useInput); if (AnimController is HumanoidAnimController) { bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); } bool attackInput = msg.ReadBoolean(); keys[(int)InputType.Attack].Held = attackInput; keys[(int)InputType.Attack].SetState(false, attackInput); double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI; cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f; TransformCursorPos(); bool ragdollInput = msg.ReadBoolean(); keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); facingRight = msg.ReadBoolean(); } bool entitySelected = msg.ReadBoolean(); Character selectedCharacter = null; Item selectedItem = null; AnimController.Animation animation = AnimController.Animation.None; if (entitySelected) { ushort characterID = msg.ReadUInt16(); ushort itemID = msg.ReadUInt16(); selectedCharacter = FindEntityByID(characterID) as Character; selectedItem = FindEntityByID(itemID) as Item; if (characterID != NullEntityID) { bool doingCpr = msg.ReadBoolean(); if (doingCpr && SelectedCharacter != null) { animation = AnimController.Animation.CPR; } } } Vector2 pos = new Vector2( msg.ReadSingle(), msg.ReadSingle()); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float?rotation = null; float?angularVelocity = null; if (!fixedRotation) { rotation = msg.ReadSingle(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); if (readStatus) { ReadStatus(msg); } msg.ReadPadBits(); int index = 0; if (GameMain.Client.Character == this && CanMove) { var posInfo = new CharacterStateInfo( pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) { index++; } memState.Insert(index, posInfo); } else { var posInfo = new CharacterStateInfo( pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) { index++; } memState.Insert(index, posInfo); } break; case ServerNetObject.ENTITY_EVENT: int eventType = msg.ReadRangedInteger(0, 5); switch (eventType) { case 0: //NetEntityEvent.Type.InventoryState if (Inventory == null) { string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); //read anyway to prevent messing up reading the rest of the message UInt16 lastEventID = msg.ReadUInt16(); byte itemCount = msg.ReadByte(); for (int i = 0; i < itemCount; i++) { msg.ReadUInt16(); } } else { Inventory.ClientRead(type, msg, sendingTime); } break; case 1: //NetEntityEvent.Type.Control byte ownerID = msg.ReadByte(); ResetNetState(); if (ownerID == GameMain.Client.ID) { if (controlled != null) { LastNetworkUpdateID = controlled.LastNetworkUpdateID; } if (!IsDead) { Controlled = this; } IsRemotePlayer = false; GameMain.Client.HasSpawned = true; GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; } else { if (controlled == this) { Controlled = null; IsRemotePlayer = ownerID > 0; } } break; case 2: //NetEntityEvent.Type.Status ReadStatus(msg); break; case 3: //NetEntityEvent.Type.UpdateSkills int skillCount = msg.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = msg.ReadString(); float skillLevel = msg.ReadSingle(); info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f); } break; case 4: //NetEntityEvent.Type.ExecuteAttack int attackLimbIndex = msg.ReadByte(); UInt16 targetEntityID = msg.ReadUInt16(); int targetLimbIndex = msg.ReadByte(); //255 = entity already removed, no need to do anything if (attackLimbIndex == 255 || Removed) { break; } if (attackLimbIndex >= AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"); break; } Limb attackLimb = AnimController.Limbs[attackLimbIndex]; Limb targetLimb = null; if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity)) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target entity not found (ID {targetEntityID})"); break; } if (targetEntity is Character targetCharacter) { if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"); break; } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; } if (attackLimb?.attack != null) { attackLimb.ExecuteAttack(targetEntity, targetLimb, out _); } break; case 5: //NetEntityEvent.Type.AssignCampaignInteraction byte campaignInteractionType = msg.ReadByte(); (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType); break; } msg.ReadPadBits(); break; } }
public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory, float?condition = null) { Prefab = prefab ?? throw new ArgumentException("ItemSpawnInfo prefab cannot be null."); Inventory = inventory; Condition = condition ?? prefab.Health; }
public virtual void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null) { if (GameMain.Server == null) { return; } if (extraData != null) { switch ((NetEntityEvent.Type)extraData[0]) { case NetEntityEvent.Type.InventoryState: msg.WriteRangedInteger(0, 0, 3); Inventory.SharedWrite(msg, extraData); break; case NetEntityEvent.Type.Control: msg.WriteRangedInteger(1, 0, 3); Client owner = ((Client)extraData[1]); msg.Write(owner == null ? (byte)0 : owner.ID); break; case NetEntityEvent.Type.Status: msg.WriteRangedInteger(2, 0, 3); WriteStatus(msg); break; case NetEntityEvent.Type.UpdateSkills: msg.WriteRangedInteger(3, 0, 3); if (Info?.Job == null) { msg.Write((byte)0); } else { msg.Write((byte)Info.Job.Skills.Count); foreach (Skill skill in Info.Job.Skills) { msg.Write(skill.Identifier); msg.Write(skill.Level); } } break; default: DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")"); break; } msg.WritePadBits(); } else { msg.Write(ID); IWriteMessage tempBuffer = new WriteOnlyMessage(); if (this == c.Character) { tempBuffer.Write(true); if (LastNetworkUpdateID < memInput.Count + 1) { tempBuffer.Write((UInt16)0); } else { tempBuffer.Write((UInt16)(LastNetworkUpdateID - memInput.Count - 1)); } } else { tempBuffer.Write(false); bool aiming = false; bool use = false; bool attack = false; bool shoot = false; if (IsRemotePlayer) { aiming = dequeuedInput.HasFlag(InputNetFlags.Aim); use = dequeuedInput.HasFlag(InputNetFlags.Use); attack = dequeuedInput.HasFlag(InputNetFlags.Attack); shoot = dequeuedInput.HasFlag(InputNetFlags.Shoot); } else if (keys != null) { aiming = keys[(int)InputType.Aim].GetHeldQueue; use = keys[(int)InputType.Use].GetHeldQueue; attack = keys[(int)InputType.Attack].GetHeldQueue; shoot = keys[(int)InputType.Shoot].GetHeldQueue; networkUpdateSent = true; } tempBuffer.Write(aiming); tempBuffer.Write(shoot); tempBuffer.Write(use); if (AnimController is HumanoidAnimController) { tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching); } tempBuffer.Write(attack); Vector2 relativeCursorPos = cursorPosition - AimRefPosition; tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI))); tempBuffer.Write(IsRagdolled || IsUnconscious || Stun > 0.0f || IsDead); tempBuffer.Write(AnimController.Dir > 0.0f); } if (SelectedCharacter != null || SelectedConstruction != null) { tempBuffer.Write(true); tempBuffer.Write(SelectedCharacter != null ? SelectedCharacter.ID : NullEntityID); tempBuffer.Write(SelectedConstruction != null ? SelectedConstruction.ID : NullEntityID); if (SelectedCharacter != null) { tempBuffer.Write(AnimController.Anim == AnimController.Animation.CPR); } } else { tempBuffer.Write(false); } tempBuffer.Write(SimPosition.X); tempBuffer.Write(SimPosition.Y); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; AnimController.Collider.LinearVelocity = new Vector2( MathHelper.Clamp(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel), MathHelper.Clamp(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel)); tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel, 12); tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12); bool fixedRotation = AnimController.Collider.FarseerBody.FixedRotation || !AnimController.Collider.PhysEnabled; tempBuffer.Write(fixedRotation); if (!fixedRotation) { tempBuffer.Write(AnimController.Collider.Rotation); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; AnimController.Collider.AngularVelocity = NetConfig.Quantize(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8); } bool writeStatus = healthUpdateTimer <= 0.0f; tempBuffer.Write(writeStatus); if (writeStatus) { WriteStatus(tempBuffer); } tempBuffer.WritePadBits(); msg.Write((byte)tempBuffer.LengthBytes); msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes); } }
public virtual void ServerRead(ClientNetObject type, IReadMessage msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); if (AllowInput) { Enabled = true; } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft) { c.KickAFKTimer = 0.0f; } else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft)) { //character changed the direction they're facing c.KickAFKTimer = 0.0f; } newAim = msg.ReadUInt16(); if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Deselect) || newInput.HasFlag(InputNetFlags.Use) || newInput.HasFlag(InputNetFlags.Health) || newInput.HasFlag(InputNetFlags.Grab)) { newInteract = msg.ReadUInt16(); } if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { if ((i > 0 && memInput[i - 1].intAim != newAim)) { c.KickAFKTimer = 0.0f; } NetInputMem newMem = new NetInputMem { states = newInput, intAim = newAim, interact = newInteract, networkUpdateID = (ushort)(networkUpdateID - i) }; memInput.Insert(i, newMem); LastInputTime = Timing.TotalTime; } } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 3); switch (eventType) { case 0: Inventory.ServerRead(type, msg, c); break; case 1: bool doingCPR = msg.ReadBoolean(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsUnconscious) { var causeOfDeath = CharacterHealth.GetCauseOfDeath(); Kill(causeOfDeath.First, causeOfDeath.Second); } break; } break; } msg.ReadPadBits(); }
public InventoryPlaceCommand(Inventory inventory, List <Item> items, bool dropped) { Inventory = inventory; Receivers = items.Select(item => new InventorySlotItem(inventory.FindIndex(item), item)).ToList(); wasDropped = dropped; }