
using Engine;
using GameEntitySystem;
using System;
using TemplatesDatabase;

namespace Game
{
    public class ComponentHealth : Component, IUpdateable
    {
        public SubsystemTime m_subsystemTime;

        public SubsystemTimeOfDay m_subsystemTimeOfDay;

        public SubsystemTerrain m_subsystemTerrain;

        public SubsystemParticles m_subsystemParticles;

        public SubsystemGameInfo m_subsystemGameInfo;

        public SubsystemPickables m_subsystemPickables;

        public ComponentCreature m_componentCreature;

        public ComponentPlayer m_componentPlayer;

        public ComponentOnFire m_componentOnFire;

        public ComponentFactors m_componentFactors;

        //public Block ExperienceOrbBlock;

        public int ExperienceOrbBlockIndex = 8;

        public float m_lastHealth;

        public bool m_wasStanding;

        public float m_redScreenFactor;

        public Random m_random = new();

        public bool m_regenerateLifeEnabled = true;//生命再生

		public float? RedScreenFactorInCrush = 1f;
		public virtual float VoidDamageFactor { get; set; }//y轴过高或者过低造成的伤害系数
        public virtual float AirLackResilience { get; set; }//溺水伤害抗性
        public virtual float MagmaResilience { get; set; }//熔岩伤害抗性
        public virtual float CrushResilience { get; set; }//挤压伤害抗性
        public virtual float SpikeResilience { get; set; }//尖刺伤害抗性
        public virtual float ExplosionResilience { get; set; }//爆炸伤害抗性

        public virtual void OnSpiked(SubsystemBlockBehavior spikeBlockBehavior, float damage , CellFace cellFace, float velocity, ComponentBody componentBody, string causeOfDeath)
        {
            Injury blockInjury = new BlockInjury(damage, cellFace, causeOfDeath, componentBody.m_subsystemTerrain);
            ModsManager.HookAction("OnCreatureSpiked", loader =>
            {
                loader.OnCreatureSpiked(this, spikeBlockBehavior, cellFace, velocity, ref blockInjury);
                return false;
            });
            Injure(blockInjury);
        }

        public virtual float CalculateFallDamage()
        {
            float velocityChange = MathF.Abs(m_componentCreature.ComponentBody.CollisionVelocityChange.Y);
            if (!m_wasStanding && velocityChange > FallResilience && !m_componentCreature.ComponentLocomotion.IsCreativeFlyEnabled)
            {
                float num4 = MathUtils.Sqr(MathUtils.Max(velocityChange - FallResilience, 0f)) / 15f;
                num4 /= m_componentFactors?.ResilienceFactor ?? 1;
                return num4;
            }
            return 0f;
        }

        public virtual bool StackExperienceOnKill { get; set; }

        public virtual string CauseOfDeath
        {
            get;
            set;
        }

        public virtual bool IsInvulnerable
        {
            get;
            set;
        }

        public virtual float Health
        {
            get;
            set;
        }

        public virtual float HealthChange
        {
            get;
            set;
        }

        public virtual BreathingMode BreathingMode
        {
            get;
            set;
        }

        public virtual float Air
        {
            get;
            set;
        }

        public virtual float AirCapacity
        {
            get;
            set;
        }

        public virtual bool CanStrand
        {
            get;
            set;
        }
        public float m_attackResilience;
        public float m_fallResilience;
        public float m_fireResilience;

        /// <summary>
        /// 攻击抗性
        /// </summary>
        public virtual float AttackResilience
        {
            get;
            set;
        }
        /// <summary>
        /// 掉落抗性
        /// </summary>
        public virtual float FallResilience
        {
            get;
            set;
        }

        public virtual float FireResilience
        {
            get;
            set;
        }

        public virtual double? DeathTime
        {
            get;
            set;
        }

        public virtual float CorpseDuration
        {
            get;
            set;
        }

        /// <summary>
        /// 攻击抗性加成系数
        /// </summary>
        public virtual float AttackResilienceFactor { get; set; }
        /// <summary>
        /// 掉落抗性加成系数
        /// </summary>
        public virtual float FallResilienceFactor { get; set; }
        /// <summary>
        /// 火焰伤害抗性系数
        /// </summary>
        public virtual float FireResilienceFactor { get; set; }
        /// <summary>
        /// 生命恢复速度系数
        /// </summary>
        public virtual float HealFactor { get; set; }

        public UpdateOrder UpdateOrder => UpdateOrder.Default;

        [Obsolete("Use ComponentHealth.Injured instead of attacked.")]
        public virtual Action<ComponentCreature> Attacked {  get; set; }
        public virtual Action<Injury> Injured { get; set; }

        public virtual void Heal(float amount)
        {
            lock (this)
            {
                if (amount > 0f && Health < 1f)
                {
                    Health = MathUtils.Saturate(Health + (amount * HealFactor));
                }
            }
        }

        public virtual void Injure(float amount, ComponentCreature attacker, bool ignoreInvulnerability, string cause)
        {
            Injury injury = new Injury(amount, attacker, ignoreInvulnerability, cause);
            Injure(injury);
        }
        public virtual void Injure(Injury injury)
        {
            if (injury == null) return;
            if (injury.ComponentHealth == null) injury.ComponentHealth = this;
            if (Health > 0f)
            {
                lock(this) {
                    injury.Process();
                    if (Health <= 0f)
                    {
                        ModsManager.HookAction("OnCreatureDying", loader =>
                        {
                            loader.OnCreatureDying(this, injury);
                            return false;
                        });
                    }
                    if (Health <= 0f)
                    {
                        Die(injury);
                    }
                }
            }
        }
        public virtual void Die(Injury injury)
        {
            Health = 0f;
            ComponentCreature attacker = injury?.Attacker;
            int experienceOrbDropCount = (int)MathF.Ceiling(m_componentCreature.ComponentHealth.AttackResilience / 12f);
            bool calculateInKill = true;
            ModsManager.HookAction("OnCreatureDied", loader =>
            {
                loader.OnCreatureDied(this, injury, ref experienceOrbDropCount, ref calculateInKill);
                return false;
            });
            CauseOfDeath = injury?.Cause;
            if (m_componentCreature.PlayerStats != null && calculateInKill)
            {
                m_componentCreature.PlayerStats.AddDeathRecord(new PlayerStats.DeathRecord
                {
                    Day = m_subsystemTimeOfDay.Day,
                    Location = m_componentCreature.ComponentBody.Position,
                    Cause = CauseOfDeath
                });
            }
            if (attacker != null)
            {
                ComponentPlayer componentPlayer = attacker?.Entity.FindComponent<ComponentPlayer>();
                if (componentPlayer != null)
                {
                    if (calculateInKill)
                    {
                        if (m_componentPlayer != null)
                        {
                            componentPlayer.PlayerStats.PlayerKills++;
                        }
                        else if (m_componentCreature.Category == CreatureCategory.LandPredator || m_componentCreature.Category == CreatureCategory.LandOther)
                        {
                            componentPlayer.PlayerStats.LandCreatureKills++;
                        }
                        else if (m_componentCreature.Category == CreatureCategory.WaterPredator || m_componentCreature.Category == CreatureCategory.WaterOther)
                        {
                            componentPlayer.PlayerStats.WaterCreatureKills++;
                        }
                        else
                        {
                            componentPlayer.PlayerStats.AirCreatureKills++;
                        }
                    }

                    if (StackExperienceOnKill)
                    {
                        for (int i = 0; i < Math.Min(100, experienceOrbDropCount); i++) //调整经验球的掉落逻辑，多于100个时则成组掉落防止卡顿
                        {
                            Vector2 vector = m_random.Vector2(2.5f, 3.5f);
                            int dropInWave = experienceOrbDropCount / 100;
                            if (i < experienceOrbDropCount % 100) dropInWave++;
                            m_subsystemPickables.AddPickable(ExperienceOrbBlockIndex, dropInWave, m_componentCreature.ComponentBody.Position, new Vector3(vector.X, 6f, vector.Y), null, Entity);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < experienceOrbDropCount; i++)
                        {
                            Vector2 vector = m_random.Vector2(2.5f, 3.5f);
                            m_subsystemPickables.AddPickable(ExperienceOrbBlockIndex, 1, m_componentCreature.ComponentBody.Position, new Vector3(vector.X, 6f, vector.Y), null, Entity);
                        }
                    }
                }
            }
        }
        public void Update(float dt)
        {
            lock (this)
            {
                //更新属性加成
                AttackResilience = m_attackResilience * AttackResilienceFactor;
                FallResilience = m_fallResilience * FallResilienceFactor;
                FireResilienceFactor = m_fireResilience * FireResilienceFactor;
                Vector3 position = m_componentCreature.ComponentBody.Position;
                if (m_regenerateLifeEnabled && Health > 0f && Health < 1f)
                {
                    float num = 0f;
                    if (m_componentPlayer != null)
                    {
                        if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless)
                        {
                            num = 0.0166666675f;
                        }
                        else if (m_componentPlayer.ComponentSleep.SleepFactor == 1f && m_componentPlayer.ComponentVitalStats.Food > 0f)
                        {
                            num = 0.00166666671f;
                        }
                        else if (m_componentPlayer.ComponentVitalStats.Food > 0.5f)
                        {
                            num = 0.00111111114f;
                        }
                    }
                    else
                    {
                        num = 0.00111111114f;
                    }
                    Heal(m_subsystemGameInfo.TotalElapsedGameTimeDelta * num);
                }
                //溺水空气值
                if (BreathingMode == BreathingMode.Air)
                {
                    int cellContents = m_subsystemTerrain.Terrain.GetCellContents(Terrain.ToCell(position.X), Terrain.ToCell(m_componentCreature.ComponentCreatureModel.EyePosition.Y), Terrain.ToCell(position.Z));
                    Air = BlocksManager.Blocks[cellContents] is FluidBlock || position.Y > 259f ? MathUtils.Saturate(Air - (dt / AirCapacity)) : 1f;
                }
                else if (BreathingMode == BreathingMode.Water)
                {
                    Air = (m_componentCreature.ComponentBody.ImmersionFactor > 0.25f || m_componentCreature.ComponentBody.IsEmbeddedInIce) ? 1f : MathUtils.Saturate(Air - (dt / AirCapacity));
                }
                //岩浆伤害
                if (m_componentCreature.ComponentBody.ImmersionFactor > 0f && m_componentCreature.ComponentBody.ImmersionFluidBlock is MagmaBlock)
                {
                    Injure(1f / MagmaResilience * m_componentCreature.ComponentBody.ImmersionFactor * dt, null, ignoreInvulnerability: false, LanguageControl.Get(GetType().Name, 1));
                    float num2 = 1.1f + (0.1f * (float)Math.Sin(12.0 * m_subsystemTime.GameTime));
                    m_redScreenFactor = MathUtils.Max(m_redScreenFactor, num2 * 0.75f * m_componentCreature.ComponentBody.ImmersionFactor / MagmaResilience);
                }
                //跌落伤害
                float fallDamage = CalculateFallDamage();
                ModsManager.HookAction("CalculateFallDamage", loader =>
                {
                    loader.CalculateFallDamage(this, ref fallDamage);
                    return false;
                });
                if (fallDamage > 0f) Injure(fallDamage, null, ignoreInvulnerability: false, LanguageControl.Get(GetType().Name, 2));
                m_wasStanding = m_componentCreature.ComponentBody.StandingOnValue.HasValue || m_componentCreature.ComponentBody.StandingOnBody != null;
                //虚空伤害
                if (VoidDamageFactor > 0f && (position.Y < 0f || position.Y > 296f) && m_subsystemTime.PeriodicGameTimeEvent(2.0, 0.0))
                {
                    Injure(VoidDamageFactor * 0.1f, null, ignoreInvulnerability: true, LanguageControl.Get(GetType().Name, 3));
                    m_componentPlayer?.ComponentGui.DisplaySmallMessage(LanguageControl.Get(GetType().Name, 4), Color.White, blinking: true, playNotificationSound: false);
                }
                //溺水伤害
                bool num5 = m_subsystemTime.PeriodicGameTimeEvent(1.0, 0.0);
                if (num5 && Air == 0f)
                {
                    float num6 = 1f / AirLackResilience;
                    num6 /= m_componentFactors?.ResilienceFactor ?? 1;
                    Injure(num6, null, ignoreInvulnerability: false, LanguageControl.Get(GetType().Name, 7));
                }
                //火焰伤害
                if (num5 && (m_componentOnFire.IsOnFire || m_componentOnFire.TouchesFire))
                {
                    float num7 = 1f / FireResilience;
                    num7 /= m_componentFactors?.ResilienceFactor ?? 1;
                    Injure(new FireInjury(num7, m_componentOnFire.Attacker));
                }
                //挤压伤害
                if (m_componentCreature.ComponentBody.CrushedTime > 0f)
                {
	                if (m_subsystemTime.PeriodicGameTimeEvent(1.0, 0.0) && m_componentCreature.ComponentBody.CrushedTime > 0.2f)
	                {
		                Injure(1 / CrushResilience, null, ignoreInvulnerability: true, LanguageControl.Get("ComponentMiner", "crushed"));
	                }
	                if(RedScreenFactorInCrush.HasValue) m_redScreenFactor = RedScreenFactorInCrush.Value;
                }
                //鱼类搁浅伤害
                if (num5 && CanStrand && m_componentCreature.ComponentBody.ImmersionFactor < 0.25f && (m_componentCreature.ComponentBody.StandingOnValue != 0 || m_componentCreature.ComponentBody.StandingOnBody != null))
                {
                    Injure(1f / AirLackResilience, null, ignoreInvulnerability: false, LanguageControl.Get(GetType().Name, 6));
                }
                //伤害结算
                float lastHealth = m_lastHealth;
                HealthChange = Health - m_lastHealth;
                m_lastHealth = Health;
                float redScreenFactorCalculated = m_redScreenFactor;
				float creatureModelRedFactorCalculated = MathUtils.Saturate(m_componentCreature.ComponentCreatureModel.m_injuryColorFactor - (3f * dt)); ;
                bool playPainSound = true;
                int healthBarFlashCount = Math.Clamp((int)((0f - HealthChange) * 30f), 0, 10);
                if (redScreenFactorCalculated > 0.01f)
                {
                    redScreenFactorCalculated *= MathF.Pow(0.2f, dt);
                }
                else
                {
                    redScreenFactorCalculated = 0f;
                }
                if (HealthChange < 0f)
                {
                    redScreenFactorCalculated += -4f * HealthChange;
					creatureModelRedFactorCalculated = 1f;
                }
                ModsManager.HookAction("ChangeVisualEffectOnInjury", loader =>
                {
                    loader.ChangeVisualEffectOnInjury(this, lastHealth, ref redScreenFactorCalculated, ref playPainSound, ref healthBarFlashCount, ref creatureModelRedFactorCalculated);
                    return false;
                });
                if (HealthChange < 0f)
                {
                    if (playPainSound) m_componentCreature.ComponentCreatureSounds.PlayPainSound();
                    m_componentPlayer?.ComponentGui.HealthBarWidget.Flash(healthBarFlashCount);
                }
                m_redScreenFactor = redScreenFactorCalculated;
				m_componentCreature.ComponentCreatureModel.m_injuryColorFactor = creatureModelRedFactorCalculated;
				if (m_componentPlayer != null)
                {
                    m_componentPlayer.ComponentScreenOverlays.RedoutFactor = MathUtils.Max(m_componentPlayer.ComponentScreenOverlays.RedoutFactor, m_redScreenFactor);
                }
                if (m_componentPlayer != null)
                {
                    m_componentPlayer.ComponentGui.HealthBarWidget.Value = Health;
                }
                if (Health == 0f && HealthChange < 0f)
				{
					DeathTime = m_subsystemGameInfo.TotalElapsedGameTime;
					Vector3 position2 = m_componentCreature.ComponentBody.Position + new Vector3(0f,m_componentCreature.ComponentBody.StanceBoxSize.Y / 2f,0f);
					float x = m_componentCreature.ComponentBody.StanceBoxSize.X;
					KillParticleSystem killParticleSystem = new KillParticleSystem(m_subsystemTerrain,position2,x);
					bool dropAllItems = true;
					ModsManager.HookAction("DeadBeforeDrops", loader =>
                    {
                        loader.DeadBeforeDrops(this, ref killParticleSystem, ref dropAllItems);
                        return false;
                    });
					if(killParticleSystem != null) m_subsystemParticles.AddParticleSystem(killParticleSystem);
					if (dropAllItems)
                    {
                        Vector3 position3 = (m_componentCreature.ComponentBody.BoundingBox.Min + m_componentCreature.ComponentBody.BoundingBox.Max) / 2f;
                        foreach (IInventory item in Entity.FindComponents<IInventory>())
                        {
                            item.DropAllItems(position3);
                        }
                    }
                }
                if (Health <= 0f && CorpseDuration > 0f && m_subsystemGameInfo.TotalElapsedGameTime - DeathTime > CorpseDuration)
                {
                    m_componentCreature.ComponentSpawn.Despawn();
                }
            }
        }

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
        {
            m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
            m_subsystemTimeOfDay = Project.FindSubsystem<SubsystemTimeOfDay>(throwOnError: true);
            m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
            m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(throwOnError: true);
            m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
            m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(throwOnError: true);
            m_componentCreature = Entity.FindComponent<ComponentCreature>(throwOnError: true);
            m_componentPlayer = Entity.FindComponent<ComponentPlayer>();
            m_componentOnFire = Entity.FindComponent<ComponentOnFire>(throwOnError: true);
            m_componentFactors = Entity.FindComponent<ComponentFactors>(throwOnError: true);
            AttackResilience = valuesDictionary.GetValue<float>("AttackResilience");
            FallResilience = valuesDictionary.GetValue<float>("FallResilience");
            FireResilience = valuesDictionary.GetValue<float>("FireResilience");
            m_attackResilience = AttackResilience;
            m_fallResilience = FallResilience;
            m_fireResilience = FireResilience;
            CorpseDuration = valuesDictionary.GetValue<float>("CorpseDuration");
            BreathingMode = valuesDictionary.GetValue<BreathingMode>("BreathingMode");
            CanStrand = valuesDictionary.GetValue<bool>("CanStrand");
            Health = valuesDictionary.GetValue<float>("Health");
            Air = valuesDictionary.GetValue<float>("Air");
            AirCapacity = valuesDictionary.GetValue<float>("AirCapacity");
            double value = valuesDictionary.GetValue<double>("DeathTime");
            AttackResilienceFactor = 1f;
            FallResilienceFactor = 1f;
            FireResilienceFactor = 1f;
            HealFactor = valuesDictionary.GetValue<float>("HealFactor");
            VoidDamageFactor = valuesDictionary.GetValue<float>("VoidDamageFactor");
            AirLackResilience = valuesDictionary.GetValue<float>("AirLackResilience");
            MagmaResilience = valuesDictionary.GetValue<float>("MagmaResilience");
            CrushResilience = valuesDictionary.GetValue<float>("CrushResilience");
            SpikeResilience = valuesDictionary.GetValue<float>("SpikeResilience");
            ExplosionResilience = valuesDictionary.GetValue<float>("ExplosionResilience");
            StackExperienceOnKill = true;
            DeathTime = (value >= 0.0) ? new double?(value) : null;
            CauseOfDeath = valuesDictionary.GetValue<string>("CauseOfDeath");
            ExperienceOrbBlockIndex = BlocksManager.GetBlockIndex<ExperienceBlock>();
            if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && Entity.FindComponent<ComponentPlayer>() != null)
            {
                IsInvulnerable = true;
            }
        }

        public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
        {
            valuesDictionary.SetValue("Health", Health);
            valuesDictionary.SetValue("Air", Air);
            if (DeathTime.HasValue)
            {
                valuesDictionary.SetValue("DeathTime", DeathTime);
            }
            if (!string.IsNullOrEmpty(CauseOfDeath))
            {
                valuesDictionary.SetValue("CauseOfDeath", CauseOfDeath);
            }
        }


    }
}
using Engine;
using Engine.Media;
using System.Xml.Linq;

namespace Game
{
	public class BevelledButtonWidget : ButtonWidget
	{
		public BevelledRectangleWidget m_rectangleWidget;

		public RectangleWidget m_imageWidget;

		public LabelWidget m_labelWidget;

		public ClickableWidget m_clickableWidget;
		public float FontScale
		{
			get { return m_labelWidget.FontScale; }
			set { m_labelWidget.FontScale = value; }
		}
		public override bool IsClicked => m_clickableWidget.IsClicked;

		public override bool IsChecked
		{
			get
			{
				return m_clickableWidget.IsChecked;
			}
			set
			{
				m_clickableWidget.IsChecked = value;
			}
		}

		public override bool IsAutoCheckingEnabled
		{
			get
			{
				return m_clickableWidget.IsAutoCheckingEnabled;
			}
			set
			{
				m_clickableWidget.IsAutoCheckingEnabled = value;
			}
		}

		public override string Text
		{
			get
			{
				return m_labelWidget.Text;
			}
			set
			{
				m_labelWidget.Text = value;
			}
		}

		public override BitmapFont Font
		{
			get
			{
				return m_labelWidget.Font;
			}
			set
			{
				m_labelWidget.Font = value;
			}
		}

		public Subtexture Subtexture
		{
			get
			{
				return m_imageWidget.Subtexture;
			}
			set
			{
				m_imageWidget.Subtexture = value;
			}
		}

		public override Color Color
		{
			get;
			set;
		}

		public Color BevelColor
		{
			get
			{
				return m_rectangleWidget.BevelColor;
			}
			set
			{
				m_rectangleWidget.BevelColor = value;
			}
		}

		public Color CenterColor
		{
			get
			{
				return m_rectangleWidget.CenterColor;
			}
			set
			{
				m_rectangleWidget.CenterColor = value;
			}
		}

		public float AmbientLight
		{
			get
			{
				return m_rectangleWidget.AmbientLight;
			}
			set
			{
				m_rectangleWidget.AmbientLight = value;
			}
		}

		public float DirectionalLight
		{
			get
			{
				return m_rectangleWidget.DirectionalLight;
			}
			set
			{
				m_rectangleWidget.DirectionalLight = value;
			}
		}

		public float BevelSize
		{
			get;
			set;
		}

		public BevelledButtonWidget()
		{
			Color = Color.White;
			BevelSize = 2f;
			XElement node = ContentManager.Get<XElement>("Widgets/BevelledButtonContents");
			LoadChildren(this, node);
			m_rectangleWidget = Children.Find<BevelledRectangleWidget>("BevelledButton.Rectangle");
			m_imageWidget = Children.Find<RectangleWidget>("BevelledButton.Image");
			m_labelWidget = Children.Find<LabelWidget>("BevelledButton.Label");
			m_clickableWidget = Children.Find<ClickableWidget>("BevelledButton.Clickable");
			m_labelWidget.VerticalAlignment = WidgetAlignment.Center;
			LoadProperties(this, node);
		}

		public override void MeasureOverride(Vector2 parentAvailableSize)
		{
			bool isEnabledGlobal = IsEnabledGlobal;
			m_labelWidget.Color = isEnabledGlobal ? Color : new Color(112, 112, 112);
			m_imageWidget.FillColor = isEnabledGlobal ? Color : new Color(112, 112, 112);
			m_rectangleWidget.BevelSize = m_clickableWidget.IsPressed || IsChecked ? -0.5f * BevelSize : BevelSize;
			base.MeasureOverride(parentAvailableSize);
		}
	}
}
using Engine;

namespace Game
{
	public struct MovingBlocksRaycastResult
	{
		public Ray3 Ray;

		public IMovingBlockSet MovingBlockSet;

		public float Distance;
		public Vector3 HitPoint()
		{
			return Ray.Position + (Ray.Direction * Distance);
		}

		public MovingBlock MovingBlock;

		public int CollisionBoxIndex;

		public BoundingBox? BlockBoundingBox;

		public int BlockValue
		{
			get
			{
				return MovingBlock?.Value ?? -1;
			}
		}
	}
}
using Engine;
using GameEntitySystem;
using System;
using System.Collections.Generic;
using TemplatesDatabase;

namespace Game
{
	public class ComponentLevel : ComponentFactors, IUpdateable
	{
		public struct Factor
		{
			public string Description;

			public float Value;
		}

		public static string fName = "ComponentLevel";

		public float? m_lastLevelTextValue;

		public ComponentPlayer m_componentPlayer;

		public const float FemaleStrengthFactor = 0.8f;

		public const float FemaleResilienceFactor = 0.8f;

		public const float FemaleSpeedFactor = 1.03f;

		public const float FemaleHungerFactor = 0.7f;

		public virtual void AddExperience(int count, bool playSound)
		{
			if (playSound)
			{
				m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 0.2f, m_random.Float(-0.1f, 0.4f), 0f, 0f);
			}
			for (int i = 0; i < count; i++)
			{
				float num = 0.012f / MathF.Pow(1.08f, MathF.Floor(m_componentPlayer.PlayerData.Level - 1f));
				if (MathF.Floor(m_componentPlayer.PlayerData.Level + num) > MathF.Floor(m_componentPlayer.PlayerData.Level))
				{
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.0, delegate
					{
						m_componentPlayer.ComponentGui.DisplaySmallMessage(LanguageControl.Get(fName, 1), Color.White, blinking: true, playNotificationSound: false);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.0, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, -0.2f, 0f, 0f);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.15000000596046448, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, -0.03333333f, 0f, 0f);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.30000001192092896, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, 142f / (339f * (float)Math.PI), 0f, 0f);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.45000001788139343, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, 23f / 60f, 0f, 0f);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.75, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, -0.03333333f, 0f, 0f);
					});
					Time.QueueTimeDelayedExecution(Time.FrameStartTime + 0.5 + 0.90000003576278687, delegate
					{
						m_subsystemAudio.PlaySound("Audio/ExperienceCollected", 1f, 23f / 60f, 0f, 0f);
					});
				}
				m_componentPlayer.PlayerData.Level += num;
			}
		}

		public override float CalculateStrengthFactor(ICollection<Factor> factors)
		{
			float num = (m_componentPlayer.PlayerData.PlayerClass == PlayerClass.Female) ? 0.8f : 1f;
			float num2 = 1f * num;
			Factor item;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num,
					Description = m_componentPlayer.PlayerData.PlayerClass.ToString()
				};
				factors.Add(item);
			}
			float level = m_componentPlayer.PlayerData.Level;
			float num3 = 1f + (0.05f * MathF.Floor(Math.Clamp(level, 1f, 21f) - 1f));
			float num4 = num2 * num3;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num3,
					Description = string.Format(LanguageControl.Get(fName, 2), MathF.Floor(level).ToString())
				};
				factors.Add(item);
			}
			float stamina = m_componentPlayer.ComponentVitalStats.Stamina;
			float num5 = MathUtils.Lerp(0.5f, 1f, MathUtils.Saturate(4f * stamina)) * MathUtils.Lerp(0.9f, 1f, MathUtils.Saturate(stamina));
			float num6 = num4 * num5;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num5,
					Description = string.Format(LanguageControl.Get(fName, 3), $"{stamina * 100f:0}")
				};
				factors.Add(item);
			}
			float num7 = m_componentPlayer.ComponentSickness.IsSick ? 0.75f : 1f;
			float num8 = num6 * num7;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num7,
					Description = m_componentPlayer.ComponentSickness.IsSick ? LanguageControl.Get(fName, 4) : LanguageControl.Get(fName, 5)
				};
				factors.Add(item);
			}
			float num9 = (!m_componentPlayer.ComponentSickness.IsPuking) ? 1 : 0;
			float num10 = num8 * num9;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num9,
					Description = m_componentPlayer.ComponentSickness.IsPuking ? LanguageControl.Get(fName, 6) : LanguageControl.Get(fName, 7)
				};
				factors.Add(item);
			}
			float num11 = m_componentPlayer.ComponentFlu.HasFlu ? 0.75f : 1f;
			float num12 = num10 * num11;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num11,
					Description = m_componentPlayer.ComponentFlu.HasFlu ? LanguageControl.Get(fName, 8) : LanguageControl.Get(fName, 9)
				};
				factors.Add(item);
			}
			float num13 = (!m_componentPlayer.ComponentFlu.IsCoughing) ? 1 : 0;
			float num14 = num12 * num13;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num13,
					Description = m_componentPlayer.ComponentFlu.IsCoughing ? LanguageControl.Get(fName, 10) : LanguageControl.Get(fName, 11)
				};
				factors.Add(item);
			}
			float num15 = (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless) ? 1.25f : 1f;
			float result = num14 * num15;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num15,
					Description = string.Format(LanguageControl.Get(fName, 12), m_subsystemGameInfo.WorldSettings.GameMode.ToString())
				};
				factors.Add(item);
			}
			return result;
		}

		public override float CalculateResilienceFactor(ICollection<Factor> factors)
		{
			float num = (m_componentPlayer.PlayerData.PlayerClass == PlayerClass.Female) ? 0.8f : 1f;
			float num2 = 1f * num;
			Factor item;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num,
					Description = m_componentPlayer.PlayerData.PlayerClass.ToString()
				};
				factors.Add(item);
			}
			float level = m_componentPlayer.PlayerData.Level;
			float num3 = 1f + (0.05f * MathF.Floor(Math.Clamp(level, 1f, 21f) - 1f));
			float num4 = num2 * num3;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num3,
					Description = string.Format(LanguageControl.Get(fName, 2), MathF.Floor(level).ToString())
				};
				factors.Add(item);
			}
			float num5 = m_componentPlayer.ComponentSickness.IsSick ? 0.75f : 1f;
			float num6 = num4 * num5;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num5,
					Description = m_componentPlayer.ComponentSickness.IsSick ? LanguageControl.Get(fName, 4) : LanguageControl.Get(fName, 5)
				};
				factors.Add(item);
			}
			float num7 = m_componentPlayer.ComponentFlu.HasFlu ? 0.75f : 1f;
			float num8 = num6 * num7;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num7,
					Description = m_componentPlayer.ComponentFlu.HasFlu ? LanguageControl.Get(fName, 8) : LanguageControl.Get(fName, 9)
				};
				factors.Add(item);
			}
			float num9 = 1f;
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless)
			{
				num9 = 1.5f;
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Survival)
			{
				num9 = 1.25f;
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative)
			{
				num9 = float.PositiveInfinity;
			}
			float result = num8 * num9;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num9,
					Description = string.Format(LanguageControl.Get(fName, 12), m_subsystemGameInfo.WorldSettings.GameMode.ToString())
				};
				factors.Add(item);
			}
			return result;
		}

		public override float CalculateSpeedFactor(ICollection<Factor> factors)
		{
			float num = 1f;
			float num2 = (m_componentPlayer.PlayerData.PlayerClass == PlayerClass.Female) ? 1.03f : 1f;
			num *= num2;
			Factor item;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num2,
					Description = m_componentPlayer.PlayerData.PlayerClass.ToString()
				};
				factors.Add(item);
			}
			float level = m_componentPlayer.PlayerData.Level;
			float num3 = 1f + (0.02f * MathF.Floor(Math.Clamp(level, 1f, 21f) - 1f));
			num *= num3;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num3,
					Description = string.Format(LanguageControl.Get(fName, 2), MathF.Floor(level).ToString())
				};
				factors.Add(item);
			}
			float clothingFactor = 1f;
			foreach (int clothe in m_componentPlayer.ComponentClothing.GetClothes(ClothingSlot.Head))
			{
				AddClothingFactor(clothe, ref clothingFactor, factors);
			}
			foreach (int clothe2 in m_componentPlayer.ComponentClothing.GetClothes(ClothingSlot.Torso))
			{
				AddClothingFactor(clothe2, ref clothingFactor, factors);
			}
			foreach (int clothe3 in m_componentPlayer.ComponentClothing.GetClothes(ClothingSlot.Legs))
			{
				AddClothingFactor(clothe3, ref clothingFactor, factors);
			}
			foreach (int clothe4 in m_componentPlayer.ComponentClothing.GetClothes(ClothingSlot.Feet))
			{
				AddClothingFactor(clothe4, ref clothingFactor, factors);
			}
			num *= clothingFactor;
			float stamina = m_componentPlayer.ComponentVitalStats.Stamina;
			float num4 = MathUtils.Lerp(0.5f, 1f, MathUtils.Saturate(4f * stamina)) * MathUtils.Lerp(0.9f, 1f, MathUtils.Saturate(stamina));
			num *= num4;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num4,
					Description = string.Format(LanguageControl.Get(fName, 3), $"{stamina * 100f:0}")
				};
				factors.Add(item);
			}
			float num5 = m_componentPlayer.ComponentSickness.IsSick ? 0.75f : 1f;
			num *= num5;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num5,
					Description = m_componentPlayer.ComponentSickness.IsSick ? LanguageControl.Get(fName, 4) : LanguageControl.Get(fName, 5)
				};
				factors.Add(item);
			}
			float num6 = (!m_componentPlayer.ComponentSickness.IsPuking) ? 1 : 0;
			num *= num6;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num6,
					Description = m_componentPlayer.ComponentSickness.IsPuking ? LanguageControl.Get(fName, 6) : LanguageControl.Get(fName, 7)
				};
				factors.Add(item);
			}
			float num7 = m_componentPlayer.ComponentFlu.HasFlu ? 0.75f : 1f;
			num *= num7;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num7,
					Description = m_componentPlayer.ComponentFlu.HasFlu ? LanguageControl.Get(fName, 8) : LanguageControl.Get(fName, 9)
				};
				factors.Add(item);
			}
			float num8 = (!m_componentPlayer.ComponentFlu.IsCoughing) ? 1 : 0;
			num *= num8;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num8,
					Description = m_componentPlayer.ComponentFlu.IsCoughing ? LanguageControl.Get(fName, 10) : LanguageControl.Get(fName, 11)
				};
				factors.Add(item);
			}
			return num;
		}

		public override float CalculateHungerFactor(ICollection<Factor> factors)
		{
			float num = (m_componentPlayer.PlayerData.PlayerClass == PlayerClass.Female) ? 0.7f : 1f;
			float num2 = 1f * num;
			Factor item;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num,
					Description = m_componentPlayer.PlayerData.PlayerClass.ToString()
				};
				factors.Add(item);
			}
			float level = m_componentPlayer.PlayerData.Level;
			float num3 = 1f - (0.01f * MathF.Floor(Math.Clamp(level, 1f, 21f) - 1f));
			float num4 = num2 * num3;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num3,
					Description = string.Format(LanguageControl.Get(fName, 2), MathF.Floor(level).ToString())
				};
				factors.Add(item);
			}
			float num5 = 1f;
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless)
			{
				num5 = 0.66f;
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Survival)
			{
				num5 = 0.75f;
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative)
			{
				num5 = 0f;
			}
			float result = num4 * num5;
			if (factors != null)
			{
				item = new Factor
				{
					Value = num5,
					Description = string.Format(LanguageControl.Get(fName, 12), m_subsystemGameInfo.WorldSettings.GameMode.ToString())
				};
				factors.Add(item);
			}
			return result;
		}

		public override void Update(float dt)
		{
			if (m_subsystemTime.PeriodicGameTimeEvent(180.0, 179.0))
			{
				AddExperience(1, playSound: false);
			}
			if (!m_lastLevelTextValue.HasValue || m_lastLevelTextValue.Value != MathF.Floor(m_componentPlayer.PlayerData.Level))
			{
				m_componentPlayer.ComponentGui.LevelLabelWidget.Text = string.Format(LanguageControl.Get(fName, 2), MathF.Floor(m_componentPlayer.PlayerData.Level).ToString());
				m_lastLevelTextValue = MathF.Floor(m_componentPlayer.PlayerData.Level);
			}
			m_componentPlayer.PlayerStats.HighestLevel = MathUtils.Max(m_componentPlayer.PlayerStats.HighestLevel, m_componentPlayer.PlayerData.Level);
			base.Update(dt);
			ModsManager.HookAction("OnLevelUpdate", modLoader =>
			{
				modLoader.OnLevelUpdate(this);
				return false;
			});
		}

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			base.Load(valuesDictionary, idToEntityMap);
			m_componentPlayer = Entity.FindComponent<ComponentPlayer>(throwOnError: true);
		}

		public static void AddClothingFactor(int clothingValue, ref float clothingFactor, ICollection<Factor> factors)
		{
			Block block = BlocksManager.Blocks[Terrain.ExtractContents(clothingValue)];
			ClothingData clothingData = block.GetClothingData(clothingValue);
			if (clothingData != null && clothingData.MovementSpeedFactor != 1f)
			{
				clothingFactor *= clothingData.MovementSpeedFactor;
				factors?.Add(new Factor
				{
					Value = clothingData.MovementSpeedFactor,
					Description = clothingData.DisplayName
				});
			}
		}
	}
}

using Engine;
using GameEntitySystem;
using System.Globalization;
using TemplatesDatabase;

namespace Game
{
	public class ComponentMiner : Component, IUpdateable
	{
		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemBodies m_subsystemBodies;

		public SubsystemMovingBlocks m_subsystemMovingBlocks;

		public SubsystemGameInfo m_subsystemGameInfo;

		public SubsystemTime m_subsystemTime;

		public SubsystemAudio m_subsystemAudio;

		public SubsystemSoundMaterials m_subsystemSoundMaterials;

		public SubsystemBlockBehaviors m_subsystemBlockBehaviors;

		private ComponentHealth m_componentHealth;

		public Random m_random = new();

		public static Random s_random = new();

		public double m_digStartTime;

		public float m_digProgress;

		public double m_lastHitTime;

		public static string fName = "ComponentMiner";

		public int m_lastDigFrameIndex;

		public float m_lastPokingPhase;

		private double m_lastToolHintTime;

		public virtual double HitInterval { get; set; }
		public ComponentCreature ComponentCreature
		{
			get;
			set;
		}

		public ComponentPlayer ComponentPlayer
		{
			get;
			set;
		}

		public ComponentFactors ComponentFactors { get; set; }

		public IInventory Inventory
		{
			get;
			set;
		}

		public int ActiveBlockValue
		{
			get
			{
				if (Inventory == null)
				{
					return 0;
				}
				return Inventory.GetSlotValue(Inventory.ActiveSlotIndex);
			}
		}

		public float AttackPower
		{
			get;
			set;
		}

		public float AutoInteractRate
		{
			get;
			set;
		}

		public float StrengthFactor
		{
			get
			{
				return ComponentFactors?.StrengthFactor ?? 1;
			}
		}

		public float PokingPhase
		{
			get;
			set;
		}

		public CellFace? DigCellFace
		{
			get;
			set;
		}

		public float DigTime
		{
			get
			{
				if (!DigCellFace.HasValue)
				{
					return 0f;
				}
				return (float)(m_subsystemTime.GameTime - m_digStartTime);
			}
		}

		public float DigProgress
		{
			get
			{
				if (!DigCellFace.HasValue)
				{
					return 0f;
				}
				return m_digProgress;
			}
		}

		public bool m_canSqueezeBlock = true;

		public bool m_canJumpToPlace = false;

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public virtual void Poke(bool forceRestart)
		{
			PokingPhase = forceRestart ? 0.0001f : MathUtils.Max(0.0001f, PokingPhase);
		}

		public bool Dig(TerrainRaycastResult raycastResult)
		{
			bool result = false;
			m_lastDigFrameIndex = Time.FrameIndex;
			CellFace cellFace = raycastResult.CellFace;
			int cellValue = m_subsystemTerrain.Terrain.GetCellValue(cellFace.X, cellFace.Y, cellFace.Z);
			int cellContents = Terrain.ExtractContents(cellValue);
			Block cellBlock = BlocksManager.Blocks[cellContents];
			int activeBlockValue = ActiveBlockValue;
			int activeBlockContents = Terrain.ExtractContents(activeBlockValue);
			Block activeBlock = BlocksManager.Blocks[activeBlockContents];
			if (!DigCellFace.HasValue || DigCellFace.Value.X != cellFace.X || DigCellFace.Value.Y != cellFace.Y || DigCellFace.Value.Z != cellFace.Z)
			{
				m_digStartTime = m_subsystemTime.GameTime;
				DigCellFace = cellFace;
			}
			float digTimeWithActiveTool = CalculateDigTime(cellValue, activeBlockValue);
			m_digProgress = (digTimeWithActiveTool > 0f) ? MathUtils.Saturate((float)(m_subsystemTime.GameTime - m_digStartTime) / digTimeWithActiveTool) : 1f;
			if (!IsLevelSufficientForTool(activeBlockValue))
			{
				m_digProgress = 0f;
				if (m_subsystemTime.PeriodicGameTimeEvent(5.0, m_digStartTime + 1.0))
				{
					ComponentPlayer?.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(fName, 1), activeBlock.PlayerLevelRequired, activeBlock.GetDisplayName(m_subsystemTerrain, activeBlockValue)), Color.White, blinking: true, playNotificationSound: true);
				}
			}
			bool flag2 = ComponentPlayer != null && !ComponentPlayer.ComponentInput.IsControlledByTouch && m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative;
			ModsManager.HookAction("OnMinerDig", modLoader =>
			{
				modLoader.OnMinerDig(this, raycastResult, ref m_digProgress, out bool flag3);
					flag2 |= flag3;
				return false;
			});
			if ((m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Survival || m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless) && ComponentPlayer != null && digTimeWithActiveTool >= 3f && m_digProgress > 0.5f && (m_lastToolHintTime == 0.0 || Time.FrameStartTime - m_lastToolHintTime > 300.0))
			{
				bool flag = digTimeWithActiveTool == CalculateDigTime(cellValue, 0);//flag:该物品挖掘时间和空手相同
				int bestInventoryToolValue = FindBestInventoryToolForDigging(cellValue);
				if (bestInventoryToolValue == 0)
				{
					if (activeBlockContents != 23 && flag)
					{
						ComponentPlayer.ComponentGui.DisplaySmallMessage(LanguageControl.Get(fName, "11"), Color.White, blinking: true, playNotificationSound: true);
						m_lastToolHintTime = Time.FrameStartTime;
					}
				}
				else if (CalculateDigTime(cellValue, bestInventoryToolValue) < 0.5f * digTimeWithActiveTool || flag)
				{
					string displayName = BlocksManager.Blocks[Terrain.ExtractContents(bestInventoryToolValue)].GetDisplayName(m_subsystemTerrain, bestInventoryToolValue);
					ComponentPlayer.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(fName, "12"), displayName), Color.White, blinking: true, playNotificationSound: true);
					m_lastToolHintTime = Time.FrameStartTime;
				}
			}
			if (flag2 || (m_lastPokingPhase <= 0.5f && PokingPhase > 0.5f))
			{
				if (m_digProgress >= 1f)
				{
					DigCellFace = null;
                    if (flag2)
                    {
                        Poke(forceRestart: true);
                    }
                    BlockPlacementData digValue = cellBlock.GetDigValue(m_subsystemTerrain, this, cellValue, activeBlockValue, raycastResult);
                    m_subsystemTerrain.DestroyCell(activeBlock.ToolLevel, digValue.CellFace.X, digValue.CellFace.Y, digValue.CellFace.Z, digValue.Value, noDrop: false, noParticleSystem: false);
					int durabilityReduction = 1;
					int playerDataAdd = 1;
					bool mute_ = false;
                    ModsManager.HookAction("OnBlockDug", modLoader =>
					{
						bool mute = false;
						modLoader.OnBlockDug(this, digValue, cellValue, ref durabilityReduction, ref mute, ref playerDataAdd);
						mute_ |= mute;
						return false;
					});
					if(!mute_) m_subsystemSoundMaterials.PlayImpactSound(cellValue, new Vector3(cellFace.X, cellFace.Y, cellFace.Z), 2f);
					DamageActiveTool(durabilityReduction);
					if (ComponentCreature.PlayerStats != null)
					{
						ComponentCreature.PlayerStats.BlocksDug += playerDataAdd;
					}
					result = true;
				}
				else
				{
					m_subsystemSoundMaterials.PlayImpactSound(cellValue, new Vector3(cellFace.X, cellFace.Y, cellFace.Z), 1f);
					BlockDebrisParticleSystem particleSystem = cellBlock.CreateDebrisParticleSystem(m_subsystemTerrain, raycastResult.HitPoint(0.1f), cellValue, 0.35f);
					base.Project.FindSubsystem<SubsystemParticles>(throwOnError: true).AddParticleSystem(particleSystem);
				}
			}
			return result;
		}

		public bool Place(TerrainRaycastResult raycastResult)
		{
			if (Place(raycastResult, ActiveBlockValue))
			{
				if (Inventory != null)
				{
					Inventory.RemoveSlotItems(Inventory.ActiveSlotIndex, 1);
				}
				return true;
			}
			return false;
		}

		public bool Place(TerrainRaycastResult raycastResult, int value)
		{
			int num = Terrain.ExtractContents(value);
			if (BlocksManager.Blocks[num].IsPlaceable_(value))
			{
				Block block = BlocksManager.Blocks[num];
				BlockPlacementData placementData = block.GetPlacementValue(m_subsystemTerrain, this, value, raycastResult);
				if (placementData.Value != 0)
				{
					Point3 point = CellFace.FaceToPoint3(placementData.CellFace.Face);
					int num2 = placementData.CellFace.X + point.X;
					int num3 = placementData.CellFace.Y + point.Y;
					int num4 = placementData.CellFace.Z + point.Z;
					bool placed = false;
					ModsManager.HookAction("OnMinerPlace", modLoader =>
					{
						modLoader.OnMinerPlace(this, raycastResult, num2, num3, num4, value, out bool Placed);
						placed |= Placed;
						return false;
					});
					if (placed) return true;
					if (!m_canSqueezeBlock)
					{
						if (m_subsystemTerrain.Terrain.GetCellContents(num2, num3, num4) != 0) return false;
					}
					if (num3 > 0 && num3 < 255 && (m_canJumpToPlace || IsBlockPlacingAllowed(ComponentCreature.ComponentBody) || m_subsystemGameInfo.WorldSettings.GameMode <= GameMode.Survival))
					{
						bool flag = false;
						if (block.IsCollidable_(value))
						{
							BoundingBox boundingBox = ComponentCreature.ComponentBody.BoundingBox;
							boundingBox.Min += new Vector3(0.2f);
							boundingBox.Max -= new Vector3(0.2f);
							BoundingBox[] customCollisionBoxes = block.GetCustomCollisionBoxes(m_subsystemTerrain, placementData.Value);
							for (int i = 0; i < customCollisionBoxes.Length; i++)
							{
								BoundingBox box = customCollisionBoxes[i];
								box.Min += new Vector3(num2, num3, num4);
								box.Max += new Vector3(num2, num3, num4);
								if (boundingBox.Intersection(box))
								{
									flag = true;
									break;
								}
							}
						}
						if (!flag)
						{
							SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(placementData.Value));
							for (int i = 0; i < blockBehaviors.Length; i++)
							{
								blockBehaviors[i].OnItemPlaced(num2, num3, num4, ref placementData, value);
							}
							m_subsystemTerrain.DestroyCell(0, num2, num3, num4, placementData.Value, noDrop: false, noParticleSystem: false);
							m_subsystemAudio.PlaySound("Audio/BlockPlaced", 1f, 0f, new Vector3(placementData.CellFace.X, placementData.CellFace.Y, placementData.CellFace.Z), 5f, autoDelay: false);
							Poke(forceRestart: false);
							if (ComponentCreature.PlayerStats != null)
							{
								ComponentCreature.PlayerStats.BlocksPlaced++;
							}
							return true;
						}
					}
				}
			}
			return false;
		}

		public bool Use(Ray3 ray)
		{
			int num = Terrain.ExtractContents(ActiveBlockValue);
			Block block = BlocksManager.Blocks[num];
			if (!IsLevelSufficientForTool(ActiveBlockValue))
			{
				ComponentPlayer?.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(fName, 1), block.PlayerLevelRequired, block.GetDisplayName(m_subsystemTerrain, ActiveBlockValue)), Color.White, blinking: true, playNotificationSound: true);
				Poke(forceRestart: false);
				return false;
			}
			SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(ActiveBlockValue));
			for (int i = 0; i < blockBehaviors.Length; i++)
			{
				if (blockBehaviors[i].OnUse(ray, this))
				{
					Poke(forceRestart: false);
					return true;
				}
			}
			return false;
		}

		public bool Interact(TerrainRaycastResult raycastResult)
		{
			SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(raycastResult.Value));
			for (int i = 0; i < blockBehaviors.Length; i++)
			{
				if (blockBehaviors[i].OnInteract(raycastResult, this))
				{
					if (ComponentCreature.PlayerStats != null)
					{
						ComponentCreature.PlayerStats.BlocksInteracted++;
					}
					Poke(forceRestart: false);
					return true;
				}
			}
			return false;
		}
		public bool Interact(MovingBlocksRaycastResult raycastResult)
		{
			if(raycastResult.MovingBlock == null) return false;
			SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(raycastResult.MovingBlock.Value));
			for(int i = 0; i < blockBehaviors.Length; i++)
			{
				if(blockBehaviors[i].OnInteract(raycastResult,this))
				{
					if(ComponentCreature.PlayerStats != null)
					{
						ComponentCreature.PlayerStats.BlocksInteracted++;
					}
					Poke(forceRestart: false);
					return true;
				}
			}
			return false;
		}

		public void Hit(ComponentBody componentBody, Vector3 hitPoint, Vector3 hitDirection)
		{
			if (!(m_subsystemTime.GameTime - m_lastHitTime > HitInterval))
			{
				return;
			}
			m_lastHitTime = m_subsystemTime.GameTime;
			Block block = BlocksManager.Blocks[Terrain.ExtractContents(ActiveBlockValue)];
			if (!IsLevelSufficientForTool(ActiveBlockValue))
			{
				ComponentPlayer?.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(fName, 1), block.PlayerLevelRequired, block.GetDisplayName(m_subsystemTerrain, ActiveBlockValue)), Color.White, blinking: true, playNotificationSound: true);
				Poke(forceRestart: false);
				return;
			}
			float num = 0f;//伤害
			float num2 = 1f;//玩家命中率
			float num3 = 1f;//生物命中率
			if (ActiveBlockValue != 0)
			{
				num = block.GetMeleePower(ActiveBlockValue) * AttackPower * m_random.Float(0.8f, 1.2f);
				num2 = block.GetMeleeHitProbability(ActiveBlockValue);
			}
			else
			{
				num = AttackPower * m_random.Float(0.8f, 1.2f);
				num2 = 0.66f;
			}
			num2 *= ((componentBody.Velocity.Length() < 0.05f) ? 2f : 1f);
			bool flag;

            ModsManager.HookAction("OnMinerHit", modLoader =>
			{
				modLoader.OnMinerHit(this, componentBody, hitPoint, hitDirection, ref num, ref num2, ref num3, out bool Hitted);
				return Hitted;
			});

			if (ComponentPlayer != null)
			{
				m_subsystemAudio.PlaySound("Audio/Swoosh", 1f, m_random.Float(-0.2f, 0.2f), componentBody.Position, 3f, autoDelay: false);
				flag = m_random.Bool(num2);
			}
			else
			{
				flag = m_random.Bool(num3);
            }
            num *= StrengthFactor;
            if (flag)
            {
                int durabilityReduction = 1;
                Attackment attackment = new MeleeAttackment(componentBody, Entity, hitPoint, hitDirection, num);
                ModsManager.HookAction("OnMinerHit2", loader =>
                {
                    loader.OnMinerHit2(this, componentBody, hitPoint, hitDirection, ref durabilityReduction, ref attackment);
                    return false;
                });
                AttackBody(attackment);
				DamageActiveTool(durabilityReduction);
			}
			else if (ComponentCreature is ComponentPlayer)
			{
				HitValueParticleSystem particleSystem = new(hitPoint + (0.75f * hitDirection), (1f * hitDirection) + ComponentCreature.ComponentBody.Velocity, Color.White, LanguageControl.Get(fName, 2));
				ModsManager.HookAction("SetHitValueParticleSystem", modLoader =>
				{
					modLoader.SetHitValueParticleSystem(particleSystem, null);
					return false;
				});
				Project.FindSubsystem<SubsystemParticles>(throwOnError: true).AddParticleSystem(particleSystem);
			}
			if (ComponentCreature.PlayerStats != null)
			{
				ComponentCreature.PlayerStats.MeleeAttacks++;
				if (flag)
				{
					ComponentCreature.PlayerStats.MeleeHits++;
				}
			}

			Poke(forceRestart: false);
		}

		public bool Aim(Ray3 aim, AimState state)
		{
			int num = Terrain.ExtractContents(ActiveBlockValue);
			Block block = BlocksManager.Blocks[num];
			if (block.IsAimable_(ActiveBlockValue))
			{
				if (!IsLevelSufficientForTool(ActiveBlockValue))
				{
					ComponentPlayer?.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(fName, 1), block.GetPlayerLevelRequired(ActiveBlockValue), block.GetDisplayName(m_subsystemTerrain, ActiveBlockValue)), Color.White, blinking: true, playNotificationSound: true);
					Poke(forceRestart: false);
					return true;
				}
				SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(ActiveBlockValue));
				for (int i = 0; i < blockBehaviors.Length; i++)
				{
					if (blockBehaviors[i].OnAim(aim, this, state))
					{
						return true;
					}
				}
			}
			return false;
		}

		public virtual object Raycast(Ray3 ray, RaycastMode mode, bool raycastTerrain = true, bool raycastBodies = true, bool raycastMovingBlocks = true, float? Reach = null)
		{
			float reach = (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative) ? SettingsManager.CreativeReach : 5f;
			if(Reach.HasValue) reach = Reach.Value;
			Vector3 creaturePosition = ComponentCreature.ComponentCreatureModel.EyePosition;
			Vector3 start = ray.Position;
			var direction = Vector3.Normalize(ray.Direction);
			Vector3 end = ray.Position + (direction * 15f);
			Point3 startCell = Terrain.ToCell(start);
			BodyRaycastResult? bodyRaycastResult = null;
			if(raycastBodies) bodyRaycastResult = m_subsystemBodies.Raycast(start, end, 0.35f, (ComponentBody body, float distance) => Vector3.DistanceSquared(start + (distance * direction), creaturePosition) <= reach * reach && body.Entity != Entity && !body.IsChildOfBody(ComponentCreature.ComponentBody) && !ComponentCreature.ComponentBody.IsChildOfBody(body) && Vector3.Dot(Vector3.Normalize(body.BoundingBox.Center() - start), direction) > 0.7f);
			MovingBlocksRaycastResult? movingBlocksRaycastResult = null;
			if(raycastMovingBlocks) movingBlocksRaycastResult = m_subsystemMovingBlocks.Raycast(start, end, extendToFillCells: true);
			TerrainRaycastResult? terrainRaycastResult = null;
			if(raycastTerrain) terrainRaycastResult = m_subsystemTerrain.Raycast(start, end, useInteractionBoxes: true, skipAirBlocks: true, delegate (int value, float distance)
			{
				if (Vector3.DistanceSquared(start + (distance * direction), creaturePosition) <= reach * reach)
				{
					Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
					if (distance == 0f && block is CrossBlock && Vector3.Dot(direction, new Vector3(startCell) + new Vector3(0.5f) - start) < 0f)
					{
						return false;
					}
					if (mode == RaycastMode.Digging)
					{
						return !block.IsDiggingTransparent;
					}
					if (mode == RaycastMode.Interaction)
					{
						if (block.IsPlacementTransparent_(value))
						{
							return block.IsInteractive(m_subsystemTerrain, value);
						}
						return true;
					}
					if (mode == RaycastMode.Gathering)
					{
						return block.IsGatherable_(value);
					}
				}
				return false;
			});

            if (!raycastBodies) bodyRaycastResult = null;
            if (!raycastTerrain) terrainRaycastResult = null;
            if (!raycastMovingBlocks) movingBlocksRaycastResult = null;

            float num = bodyRaycastResult.HasValue ? bodyRaycastResult.Value.Distance : float.PositiveInfinity;
			float num2 = movingBlocksRaycastResult.HasValue ? movingBlocksRaycastResult.Value.Distance : float.PositiveInfinity;
			float num3 = terrainRaycastResult.HasValue ? terrainRaycastResult.Value.Distance : float.PositiveInfinity;
			if (num < num2 && num < num3)
			{
				return bodyRaycastResult.Value;
			}
			if (num2 < num && num2 < num3)
			{
				return movingBlocksRaycastResult.Value;
			}
			if (num3 < num && num3 < num2)
			{
				return terrainRaycastResult.Value;
			}
			return new Ray3(start, direction);
		}

		public T? Raycast<T>(Ray3 ray, RaycastMode mode, bool raycastTerrain = true, bool raycastBodies = true, bool raycastMovingBlocks = true, float? reach = null) where T : struct
		{
			object obj = Raycast(ray, mode, raycastTerrain, raycastBodies, raycastMovingBlocks, reach);
			if (!(obj is T))
			{
				return null;
			}
			return (T)obj;
		}

		public virtual void RemoveActiveTool(int removeCount)
		{
			if (Inventory != null)
			{
				Inventory.RemoveSlotItems(Inventory.ActiveSlotIndex, removeCount);
			}
		}

		public virtual void DamageActiveTool(int damageCount)
		{
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative || Inventory == null)
			{
				return;
			}
			int num = BlocksManager.DamageItem(ActiveBlockValue, damageCount, Entity);
			if (num != 0)
			{
				int slotCount = Inventory.GetSlotCount(Inventory.ActiveSlotIndex);
				Inventory.RemoveSlotItems(Inventory.ActiveSlotIndex, slotCount);
				if (Inventory.GetSlotCount(Inventory.ActiveSlotIndex) == 0)
				{
					Inventory.AddSlotItems(Inventory.ActiveSlotIndex, num, slotCount);
				}
			}
			else
			{
				Inventory.RemoveSlotItems(Inventory.ActiveSlotIndex, 1);
			}
		}

		public static void AttackBody(Attackment attackment)
		{
			try
			{
				attackment.ProcessAttackment();
			}
			catch (Exception e)
			{
				Log.Error("Attack execute error: " + e);
			}
		}
        public static void AttackBody(ComponentBody target, ComponentCreature attacker, Vector3 hitPoint, Vector3 hitDirection, float attackPower, bool isMeleeAttack)
        {
			if (isMeleeAttack) AttackBody(new MeleeAttackment(target?.Entity, attacker?.Entity, hitPoint, hitDirection, attackPower));
			else AttackBody(new ProjectileAttackment(target?.Entity, attacker?.Entity, hitPoint, hitDirection, attackPower, null));
        }

		[Obsolete("Use AddHitValueParticleSystem() in Attackment instead.", true)]
		public static void AddHitValueParticleSystem(float damage, Entity attacker, Entity attacked, Vector3 hitPoint, Vector3 hitDirection)
		{
			ComponentBody attackerBody = attacker?.FindComponent<ComponentBody>();
			ComponentPlayer attackerComponentPlayer = attacker?.FindComponent<ComponentPlayer>();
			ComponentHealth attackedComponentHealth = attacked?.FindComponent<ComponentHealth>();
            string text2 = (0f - damage).ToString("0", CultureInfo.InvariantCulture);
            Vector3 hitValueParticleVelocity = Vector3.Zero;
            if (attackerBody != null) hitValueParticleVelocity = attackerBody.Velocity;
            Color color = (attackerComponentPlayer != null && damage > 0f && attackedComponentHealth != null) ? Color.White : Color.Transparent;
            HitValueParticleSystem particleSystem = new(hitPoint + (0.75f * hitDirection), (1f * hitDirection) + hitValueParticleVelocity, color, text2);
            ModsManager.HookAction("SetHitValueParticleSystem", modLoader =>
            {
                modLoader.SetHitValueParticleSystem(particleSystem, null);
                return false;
            });
            attacked?.Project.FindSubsystem<SubsystemParticles>(throwOnError: true).AddParticleSystem(particleSystem);
        }

        public void Update(float dt)
		{
			float num = (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative) ? (0.5f / SettingsManager.CreativeDigTime) : 4f;
			m_lastPokingPhase = PokingPhase;
			if (DigCellFace.HasValue || PokingPhase > 0f)
			{
				PokingPhase += num * m_subsystemTime.GameTimeDelta;
				if (PokingPhase > 1f)
				{
					PokingPhase = DigCellFace.HasValue ? MathUtils.Remainder(PokingPhase, 1f) : 0f;
				}
			}
			if (DigCellFace.HasValue && Time.FrameIndex - m_lastDigFrameIndex > 1)
			{
				DigCellFace = null;
			}
			if ((m_componentHealth != null && !(m_componentHealth.Health > 0f)) || !(AutoInteractRate > 0f) || !m_random.Bool(AutoInteractRate) || !m_subsystemTime.PeriodicGameTimeEvent(1.0, (float)(GetHashCode() % 100) / 100f))
			{
				return;
			}
			ComponentCreatureModel componentCreatureModel = ComponentCreature.ComponentCreatureModel;
			Vector3 eyePosition = componentCreatureModel.EyePosition;
			Vector3 forwardVector = componentCreatureModel.EyeRotation.GetForwardVector();
			for (int i = 0; i < 10; i++)
			{
				TerrainRaycastResult? terrainRaycastResult = Raycast<TerrainRaycastResult>(new Ray3(eyePosition, forwardVector + m_random.Vector3(0.75f)), RaycastMode.Interaction);
				if (terrainRaycastResult.HasValue && terrainRaycastResult.Value.Distance < 1.5f && Terrain.ExtractContents(terrainRaycastResult.Value.Value) != 57 && Interact(terrainRaycastResult.Value))
				{
					break;
				}
			}
		}

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemBodies = Project.FindSubsystem<SubsystemBodies>(throwOnError: true);
			m_subsystemMovingBlocks = Project.FindSubsystem<SubsystemMovingBlocks>(throwOnError: true);
			m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_subsystemSoundMaterials = Project.FindSubsystem<SubsystemSoundMaterials>(throwOnError: true);
			m_subsystemBlockBehaviors = Project.FindSubsystem<SubsystemBlockBehaviors>(throwOnError: true);
			ComponentCreature = Entity.FindComponent<ComponentCreature>(throwOnError: true);
			ComponentPlayer = Entity.FindComponent<ComponentPlayer>();
			m_componentHealth = base.Entity.FindComponent<ComponentHealth>();
			ComponentFactors = Entity.FindComponent<ComponentFactors>(throwOnError: true);
			Inventory = m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && ComponentPlayer != null
				? Entity.FindComponent<ComponentCreativeInventory>()
				: (IInventory)Entity.FindComponent<ComponentInventory>();
			AttackPower = valuesDictionary.GetValue<float>("AttackPower");
			HitInterval = valuesDictionary.GetValue<float>("HitInterval");
			AutoInteractRate = valuesDictionary.GetValue<float>("AutoInteractRate");
			if (string.CompareOrdinal(m_subsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.4") < 0 || m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless || m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Survival)
			{
				AutoInteractRate = 0f;
			}
		}
		public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
		{
			valuesDictionary.SetValue("AttackPower", AttackPower);
		}
		public static bool IsBlockPlacingAllowed(ComponentBody componentBody)
		{
			if (componentBody.StandingOnBody != null || componentBody.StandingOnValue.HasValue)
			{
				return true;
			}
			if (componentBody.ImmersionFactor > 0.01f)
			{
				return true;
			}
			if (componentBody.ParentBody != null && IsBlockPlacingAllowed(componentBody.ParentBody))
			{
				return true;
			}
			ComponentLocomotion componentLocomotion = componentBody.Entity.FindComponent<ComponentLocomotion>();
			if (componentLocomotion != null && componentLocomotion.LadderValue.HasValue)
			{
				return true;
			}
			return false;
		}

		public virtual float CalculateDigTime(int digValue, int toolValue)
		{
			Block block = BlocksManager.Blocks[Terrain.ExtractContents(toolValue)];
			Block block2 = BlocksManager.Blocks[Terrain.ExtractContents(digValue)];
			float digResilience = block2.GetDigResilience(digValue);
			BlockDigMethod digBlockMethod = block2.GetBlockDigMethod(digValue);
			float ShovelPower = block.GetShovelPower(toolValue);
			float QuarryPower = block.GetQuarryPower(toolValue);
			float HackPower = block.GetHackPower(toolValue);

			if (ComponentPlayer != null && m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative)
			{
				if (digResilience < float.PositiveInfinity)
				{
					return 0f;
				}
				return float.PositiveInfinity;
			}
			if (ComponentPlayer != null && m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Adventure)
			{
				float num = 0f;
				if (digBlockMethod == BlockDigMethod.Shovel && ShovelPower >= 2f)
				{
					num = ShovelPower;
				}
				else if (digBlockMethod == BlockDigMethod.Quarry && QuarryPower >= 2f)
				{
					num = QuarryPower;
				}
				else if (digBlockMethod == BlockDigMethod.Hack && HackPower >= 2f)
				{
					num = HackPower;
				}
				num *= StrengthFactor;
				if (!(num > 0f))
				{
					return float.PositiveInfinity;
				}
				return MathUtils.Max(digResilience / num, 0f);
			}
			float num2 = 1f;
			if (digBlockMethod == BlockDigMethod.Shovel)
			{
				num2 = ShovelPower;
			}
			else if (digBlockMethod == BlockDigMethod.Quarry)
			{
				num2 = QuarryPower;
			}
			else if (digBlockMethod == BlockDigMethod.Hack)
			{
				num2 = HackPower;
			}
			num2 *= StrengthFactor;
			if (!(num2 > 0f))
			{
				return float.PositiveInfinity;
			}
			return MathUtils.Max(digResilience / num2, 0f);
		}

		public virtual bool IsLevelSufficientForTool(int toolValue)
		{
			if (m_subsystemGameInfo.WorldSettings.GameMode != 0 && m_subsystemGameInfo.WorldSettings.AreAdventureSurvivalMechanicsEnabled)
			{
				Block block = BlocksManager.Blocks[Terrain.ExtractContents(toolValue)];
				if (ComponentPlayer != null && ComponentPlayer.PlayerData.Level < block.GetPlayerLevelRequired(toolValue))
				{
					return false;
				}
			}
			return true;
		}

		public virtual int FindBestInventoryToolForDigging(int digValue)
		{
			int result = 0;
			float num = CalculateDigTime(digValue, 0);
			foreach (IInventory item in base.Entity.FindComponents<IInventory>())
			{
				if (item is ComponentCreativeInventory)
				{
					continue;
				}
				for (int i = 0; i < item.SlotsCount; i++)
				{
					int slotValue = item.GetSlotValue(i);
					if (IsLevelSufficientForTool(slotValue))
					{
						float num2 = CalculateDigTime(digValue, slotValue);
						if (num2 < num)
						{
							num = num2;
							result = slotValue;
						}
					}
				}
			}
			return result;
		}
	}
}
using System;
using System.Collections.Generic;

namespace TemplatesDatabase
{
	public class DatabaseObject
	{
        public class StringBin
		{
			private int m_mask;

			private List<string> m_list = [];

			public bool Contains(string s)
			{
				int num = Hash(s) & 0x1F;
				int num2 = 1 << num;
				if ((m_mask & num2) != 0)
				{
					return m_list.Contains(s);
				}
				return false;
			}

			public void Add(string s)
			{
				int num = Hash(s) & 0x1F;
				int num2 = 1 << num;
				m_mask |= num2;
				m_list.Add(s);
			}

			private static int Hash(string s)
			{
				int length = s.Length;
				return s[0] + s[length >> 1] + s[length - 1];
			}
		}

		internal Database m_database;

		private DatabaseObjectType m_databaseObjectType;

		private Guid m_guid;

		private string m_name;

		private object m_value;

		private string m_description = string.Empty;

		private bool m_readOnly;

		private DatabaseObject m_explicitInheritanceParent;

		private DatabaseObject m_nestingParent;

		private List<DatabaseObject> m_nestingChildren;

		public Database Database => m_database;

		public DatabaseObjectType Type => m_databaseObjectType;

		public Guid Guid => m_guid;

		public string Name
		{
			get
			{
				return m_name;
			}
			set
			{
				if (m_readOnly)
				{
					throw new InvalidOperationException("Cannot change name of a read-only database object.");
				}
				if (value != m_name)
				{
					if (value.Length > Type.NameLengthLimit)
					{
						throw new InvalidOperationException($"Name \"{value}\" is too long, maximum name length for database object of type \"{Type.Name}\" is {Type.NameLengthLimit}.");
					}
					if (NestingParent != null)
					{
						foreach (DatabaseObject explicitNestingChild in NestingParent.GetExplicitNestingChildren(null, directChildrenOnly: true))
						{
							if (explicitNestingChild.Name == value)
							{
								throw new InvalidOperationException($"Database object \"{explicitNestingChild.Name}\" is already nested in parent database object \"{NestingParent.Name}\".");
							}
						}
					}
					m_name = value;
				}
			}
		}

		public string Description
		{
			get
			{
				return m_description;
			}
			set
			{
				if (m_readOnly)
				{
					throw new InvalidOperationException("Cannot change description of a read-only database object.");
				}
				if (value == null)
				{
					throw new ArgumentNullException("value", "Description cannot be null.");
				}
				m_description = value;
			}
		}

		public object Value
		{
			get
			{
				return m_value;
			}
			set
			{
				if (m_readOnly)
				{
					throw new InvalidOperationException("Cannot change value of a read-only database object.");
				}
				if (!Type.SupportsValue)
				{
					throw new InvalidOperationException($"Database objects of type \"{Type.Name}\" do not support values.");
				}
				if (value == null)
				{
					throw new ArgumentNullException("value", "Value cannot be null.");
				}
				m_value = value;
			}
		}

		public bool ReadOnly => m_readOnly;

		public DatabaseObject NestingParent
		{
			get
			{
				return m_nestingParent;
			}
			set
			{
				if (m_readOnly)
				{
					throw new InvalidOperationException("Cannot change nesting parent of a read-only database object.");
				}
				if (value == m_nestingParent)
				{
					return;
				}
				if (value != null)
				{
					if (m_database != null && m_database.Root == this)
					{
						throw new InvalidOperationException("Root database object cannot be nested.");
					}
					if (!Type.AllowedNestingParents.Contains(value.Type))
					{
						throw new InvalidOperationException($"Database object of type {Type.Name} cannot be nested in {value.Type.Name}.");
					}
					if (value == this || value.EffectivelyInheritsFrom(this) || EffectivelyInheritsFrom(value) || value.IsNestedIn(this))
					{
						throw new InvalidOperationException("Cannot set nesting parent of database object \"" + Name + "\" to database object \"" + value.Name + "\" because it would create recursive nesting/inheritance.");
					}
					if (value.FindExplicitNestedChild(Name, null, directChildrenOnly: true, throwIfNotFound: false) != null)
					{
						throw new InvalidOperationException("Another database object with name \"" + Name + "\" is already nested in database object \"" + value.Name + "\".");
					}
				}
				if (m_nestingParent != null)
				{
					if (!m_nestingParent.InternalNestingChildren.Remove(this))
					{
						throw new InvalidOperationException("DatabaseObject internal error: nested DatabaseObject not found in container.");
					}
					m_nestingParent = null;
					if (m_database != null)
					{
						m_database.RemoveDatabaseObject(this);
					}
				}
				if (value != null)
				{
					if (value.m_database != null)
					{
						value.m_database.AddDatabaseObject(this, checkThatGuidsAreUnique: true);
					}
					m_nestingParent = value;
					m_nestingParent.InternalNestingChildren.Add(this);
				}
			}
		}

		public DatabaseObject NestingRoot
		{
			get
			{
				if (m_nestingParent == null)
				{
					return this;
				}
				return m_nestingParent.NestingRoot;
			}
		}

		public DatabaseObject ExplicitInheritanceParent
		{
			get
			{
				return m_explicitInheritanceParent;
			}
			set
			{
				if (m_readOnly)
				{
					throw new InvalidOperationException("Cannot change inheritance parent of a read-only database object.");
				}
				if (value == m_explicitInheritanceParent)
				{
					return;
				}
				if (value != null)
				{
					if (value == this || value.EffectivelyInheritsFrom(this) || value.IsNestedIn(this) || IsNestedIn(value))
					{
						throw new InvalidOperationException("Cannot set inheritance parent of database object \"" + Name + "\" to database object \"" + value.Name + "\" because it would create recursive nesting/inheritance.");
					}
					if (!Type.AllowedInheritanceParents.Contains(value.Type))
					{
						throw new InvalidOperationException($"Database object of type {Type.Name} cannot inherit from {value.Type.Name}.");
					}
				}
				m_explicitInheritanceParent = value;
			}
		}

		public DatabaseObject ExplicitInheritanceRoot
		{
			get
			{
				if (m_explicitInheritanceParent == null)
				{
					return this;
				}
				return m_explicitInheritanceParent.ExplicitInheritanceRoot;
			}
		}

		public DatabaseObject ImplicitInheritanceParent
		{
			get
			{
				if (NestingParent != null)
				{
					return NestingParent.EffectiveInheritanceParent?.FindEffectiveNestedChild(Name, null, directChildrenOnly: true, throwIfNotFound: false);
				}
				return null;
			}
		}

		public DatabaseObject ImplicitInheritanceRoot
		{
			get
			{
				DatabaseObject implicitInheritanceParent = ImplicitInheritanceParent;
				if (implicitInheritanceParent == null)
				{
					return this;
				}
				return implicitInheritanceParent.ImplicitInheritanceRoot;
			}
		}

		public DatabaseObject EffectiveInheritanceParent
		{
			get
			{
				if (m_explicitInheritanceParent == null)
				{
					return ImplicitInheritanceParent;
				}
				return m_explicitInheritanceParent;
			}
		}

		public DatabaseObject EffectiveInheritanceRoot
		{
			get
			{
				DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
				if (effectiveInheritanceParent == null)
				{
					return this;
				}
				return effectiveInheritanceParent.EffectiveInheritanceRoot;
			}
		}

		private List<DatabaseObject> InternalNestingChildren
		{
			get
			{
				if (m_nestingChildren == null)
				{
					m_nestingChildren = [];
				}
				return m_nestingChildren;
			}
		}

		public DatabaseObject(DatabaseObjectType databaseObjectType, Guid guid, string name, object value)
		{
			if (!databaseObjectType.IsInitialized)
			{
				throw new InvalidOperationException($"InitializeRelations of DatabaseObjectType \"{databaseObjectType.Name}\" not called.");
			}
			m_databaseObjectType = databaseObjectType;
			m_guid = guid;
			Name = name;
			if (value != null)
			{
				Value = value;
			}
		}

		public DatabaseObject(DatabaseObjectType databaseObjectType, string name, object value)
			: this(databaseObjectType, Guid.NewGuid(), name, value)
		{
		}

		public DatabaseObject(DatabaseObjectType databaseObjectType, string name)
			: this(databaseObjectType, Guid.NewGuid(), name, null)
		{
		}

		public bool IsNestedIn(DatabaseObject databaseObject)
		{
			if (NestingParent == null)
			{
				return false;
			}
			if (NestingParent != databaseObject)
			{
				return NestingParent.IsNestedIn(databaseObject);
			}
			return true;
		}

		public IEnumerable<DatabaseObject> GetExplicitNestingChildren(DatabaseObjectType type, bool directChildrenOnly)
		{
			foreach (DatabaseObject databaseObject in InternalNestingChildren)
			{
				if (type == null || databaseObject.Type == type)
				{
					yield return databaseObject;
				}
				if (!directChildrenOnly)
				{
					foreach (DatabaseObject explicitNestingChild in databaseObject.GetExplicitNestingChildren(type, directChildrenOnly: false))
					{
						yield return explicitNestingChild;
					}
				}
			}
		}

		public DatabaseObject FindExplicitNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound)
		{
			foreach (DatabaseObject explicitNestingChild in GetExplicitNestingChildren(type, directChildrenOnly))
			{
				if (explicitNestingChild.Name == name)
				{
					return explicitNestingChild;
				}
			}
			if (throwIfNotFound)
			{
				throw new InvalidOperationException($"Required database object \"{name}\" not found in database object \"{Name}\"");
			}
			return null;
		}

		public bool ExplicitlyInheritsFrom(DatabaseObject databaseObject)
		{
			DatabaseObject explicitInheritanceParent = ExplicitInheritanceParent;
			if (explicitInheritanceParent != null)
			{
				if (explicitInheritanceParent != databaseObject)
				{
					return explicitInheritanceParent.ExplicitlyInheritsFrom(databaseObject);
				}
				return true;
			}
			return false;
		}

		public bool ImplicitlyInheritsFrom(DatabaseObject databaseObject)
		{
			DatabaseObject implicitInheritanceParent = ImplicitInheritanceParent;
			if (implicitInheritanceParent != null)
			{
				if (implicitInheritanceParent != databaseObject)
				{
					return implicitInheritanceParent.ImplicitlyInheritsFrom(databaseObject);
				}
				return true;
			}
			return false;
		}

		public bool EffectivelyInheritsFrom(DatabaseObject databaseObject)
		{
			DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
			if (effectiveInheritanceParent != null)
			{
				if (effectiveInheritanceParent != databaseObject)
				{
					return effectiveInheritanceParent.EffectivelyInheritsFrom(databaseObject);
				}
				return true;
			}
			return false;
		}

		public IEnumerable<DatabaseObject> GetEffectiveNestingChildren(DatabaseObjectType type, bool directChildrenOnly)
		{
			if (directChildrenOnly)
			{
				foreach (DatabaseObject item in InternalGetEffectiveNestingChildren(new StringBin(), type))
				{
					if (type == null || item.Type == type)
					{
						yield return item;
					}
				}
			}
			else
			{
				foreach (DatabaseObject databaseObject in GetEffectiveNestingChildren(null, directChildrenOnly: true))
				{
					if (type == null || databaseObject.Type == type)
					{
						yield return databaseObject;
					}
					foreach (DatabaseObject effectiveNestingChild in databaseObject.GetEffectiveNestingChildren(type, directChildrenOnly: false))
					{
						yield return effectiveNestingChild;
					}
				}
			}
		}

		public DatabaseObject FindEffectiveNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound)
		{
			foreach (DatabaseObject effectiveNestingChild in GetEffectiveNestingChildren(type, directChildrenOnly))
			{
				if (effectiveNestingChild.Name == name)
				{
					return effectiveNestingChild;
				}
			}
			if (throwIfNotFound)
			{
				throw new InvalidOperationException($"Required database object \"{name}\" not found in database object \"{Name}\"");
			}
			return null;
		}

		public T GetNestedValue<T>(string name)
		{
			DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, directChildrenOnly: true, throwIfNotFound: true);
			return CastValue<T>(databaseObject);
		}

		public T GetNestedValue<T>(string name, T defaultValue)
		{
			DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, directChildrenOnly: true, throwIfNotFound: false);
			if (databaseObject == null)
			{
				return defaultValue;
			}
			return CastValue<T>(databaseObject);
		}

		public void SetNestedValue<T>(string name, T value)
		{
			DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, directChildrenOnly: true, throwIfNotFound: false);
			if (databaseObject == null || databaseObject.NestingParent != this)
			{
				new DatabaseObject(Type.NestedValueType, Guid.Empty, name, value).NestingParent = this;
			}
			else
			{
				databaseObject.Value = value;
			}
		}

		public override string ToString()
		{
			if (NestingParent != null)
			{
				return $"{Name} in {NestingParent.ToString()}";
			}
			return $"{Name}";
		}

		private T CastValue<T>(DatabaseObject databaseObject)
		{
			if (databaseObject.Value != null && !(databaseObject.Value is T))
			{
				throw new Exception($"Database object \"{databaseObject.Name}\" has invalid type \"{databaseObject.Value.GetType().FullName}\", required type is \"{typeof(T).FullName}\".");
			}
			return (T)databaseObject.Value;
		}

		private IEnumerable<DatabaseObject> InternalGetEffectiveNestingChildren(StringBin names, DatabaseObjectType type)
		{
			if (Type.AllowedNestingChildren.Count != 0)
			{
				foreach (DatabaseObject explicitNestingChild in GetExplicitNestingChildren(type, directChildrenOnly: true))
				{
					if (!names.Contains(explicitNestingChild.Name))
					{
						names.Add(explicitNestingChild.Name);
						yield return explicitNestingChild;
					}
				}
				DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
				if (effectiveInheritanceParent != null)
				{
					foreach (DatabaseObject item in effectiveInheritanceParent.InternalGetEffectiveNestingChildren(names, type))
					{
						yield return item;
					}
				}
			}
		}
	}
}

using Engine;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TemplatesDatabase
{
	public class Database
	{
		private DatabaseObject m_root;

		private ReadOnlyList<DatabaseObjectType> m_databaseObjectTypes;

        public Dictionary<Guid, DatabaseObject> m_databaseObjectsByGuid = [];

		public IList<DatabaseObjectType> DatabaseObjectTypes => m_databaseObjectTypes;

		public DatabaseObject Root => m_root;

		public Database(DatabaseObject root, IEnumerable<DatabaseObjectType> databaseObjectTypes)
		{
			if (!databaseObjectTypes.Contains(root.Type))
			{
				throw new Exception("Database root has invalid database object type.");
			}
			if (root.NestingParent != null)
			{
				throw new Exception("Database root cannot be nested.");
			}
			m_databaseObjectTypes = new ReadOnlyList<DatabaseObjectType>(new List<DatabaseObjectType>(databaseObjectTypes));
			m_root = root;
			m_root.m_database = this;
		}

		public DatabaseObjectType FindDatabaseObjectType(string name, bool throwIfNotFound)
		{
			foreach (DatabaseObjectType databaseObjectType in m_databaseObjectTypes)
			{
				if (databaseObjectType.Name == name)
				{
					return databaseObjectType;
				}
			}
			if (throwIfNotFound)
			{
				throw new Exception($"Required database object type \"{name}\" not found.");
			}
			return null;
		}

		public DatabaseObject FindDatabaseObject(Guid guid, DatabaseObjectType type, bool throwIfNotFound)
		{
			m_databaseObjectsByGuid.TryGetValue(guid, out DatabaseObject value);
			if (value != null)
			{
				if (type != null && value.Type != type)
				{
					throw new InvalidOperationException($"Database object {guid} has invalid type. Expected {type.Name}, found {value.Type.Name}.");
				}
			}
			else if (throwIfNotFound)
			{
				throw new InvalidOperationException($"Required database object {guid} not found.");
			}
			return value;
		}

		public DatabaseObject FindDatabaseObject(string name, DatabaseObjectType type, bool throwIfNotFound)
		{
			return Root.FindExplicitNestedChild(name, type, directChildrenOnly: false, throwIfNotFound);
		}

		public void FindUsedValueTypes(List<Type> typesList)
		{
			foreach (DatabaseObject explicitNestingChild in Root.GetExplicitNestingChildren(null, directChildrenOnly: false))
			{
				if (explicitNestingChild.Value != null && !typesList.Contains(explicitNestingChild.Value.GetType()))
				{
					typesList.Add(explicitNestingChild.Value.GetType());
				}
			}
		}

		internal void AddDatabaseObject(DatabaseObject databaseObject, bool checkThatGuidsAreUnique)
		{
			if (databaseObject.m_database != null)
			{
				throw new InvalidOperationException("Internal error: database object is already in a database.");
			}
			if (!m_databaseObjectTypes.Contains(databaseObject.Type))
			{
				throw new InvalidOperationException($"Database object type \"{databaseObject.Type.Name}\" is not supported by the database.");
			}
			if (checkThatGuidsAreUnique)
			{
				if (databaseObject.Guid != Guid.Empty && m_databaseObjectsByGuid.ContainsKey(databaseObject.Guid))
				{
					throw new InvalidOperationException($"Database object {databaseObject.Guid} is already present in the database.");
				}
				foreach (DatabaseObject explicitNestingChild in databaseObject.GetExplicitNestingChildren(null, directChildrenOnly: false))
				{
					if (explicitNestingChild.Guid != Guid.Empty && m_databaseObjectsByGuid.ContainsKey(explicitNestingChild.Guid))
					{
						throw new InvalidOperationException($"Database object {explicitNestingChild.Guid} is already present in the database.");
					}
				}
			}
			databaseObject.m_database = this;
			if (databaseObject.Guid != Guid.Empty)
			{
				m_databaseObjectsByGuid.Add(databaseObject.Guid, databaseObject);
			}
			foreach (DatabaseObject explicitNestingChild2 in databaseObject.GetExplicitNestingChildren(null, directChildrenOnly: true))
			{
				AddDatabaseObject(explicitNestingChild2, checkThatGuidsAreUnique: false);
			}
		}

		internal void RemoveDatabaseObject(DatabaseObject databaseObject)
		{
			if (databaseObject.m_database != this)
			{
				throw new InvalidOperationException("Internal error: database object is not in the database.");
			}
			databaseObject.m_database = null;
			if (databaseObject.Guid != Guid.Empty && !m_databaseObjectsByGuid.Remove(databaseObject.Guid))
			{
				throw new InvalidOperationException("Internal error: database object not in dictionary.");
			}
			foreach (DatabaseObject explicitNestingChild in databaseObject.GetExplicitNestingChildren(null, directChildrenOnly: true))
			{
				RemoveDatabaseObject(explicitNestingChild);
			}
		}
	}
}
using Engine.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using XmlUtilities;

namespace TemplatesDatabase
{
	public class ValuesDictionary : IEnumerable<KeyValuePair<string, object>>, IEnumerable
	{
		private Dictionary<string, object> m_dictionary = [];

		private DatabaseObject m_databaseObject;

		public int Count => m_dictionary.Count;

		public IEnumerable<string> Keys => m_dictionary.Keys;

		public IEnumerable<object> Values => m_dictionary.Values;

		public DatabaseObject DatabaseObject
		{
			get
			{
				return m_databaseObject;
			}
			set
			{
				m_databaseObject = value;
			}
		}

		public object this[string key]
		{
			get
			{
				return GetValue<object>(key);
			}
			set
			{
				SetValue(key, value);
			}
		}

		public bool ContainsKey(string key)
		{
			return m_dictionary.ContainsKey(key);
		}

		public T GetValue<T>(string key)
		{
			if (m_dictionary.TryGetValue(key, out object value))
			{
				return (T)value;
			}
			throw new InvalidOperationException($"Required value \"{key}\" not found in values dictionary");
		}

		public T GetValue<T>(string key, T defaultValue)
		{
			if (m_dictionary.TryGetValue(key, out object value))
			{
				return (T)value;
			}
			return defaultValue;
		}

		public void SetValue<T>(string key, T value)
		{
			m_dictionary[key] = value;
		}

		public void Add<T>(string key, T value)
		{
			m_dictionary.Add(key, value);
		}

		public void Clear()
		{
			m_dictionary.Clear();
		}

		public void Save(XElement node)
		{
			foreach (KeyValuePair<string, object> item in m_dictionary)
			{
				ValuesDictionary valuesDictionary = item.Value as ValuesDictionary;
				if (valuesDictionary != null)
				{
					XElement node2 = XmlUtils.AddElement(node, "Values");
					XmlUtils.SetAttributeValue(node2, "Name", item.Key);
					valuesDictionary.Save(node2);
				}
				else
				{
					XElement node3 = XmlUtils.AddElement(node, "Value");
					XmlUtils.SetAttributeValue(node3, "Name", item.Key);
					XmlUtils.SetAttributeValue(node3, "Type", TypeCache.GetShortTypeName(item.Value.GetType().FullName));
					XmlUtils.SetAttributeValue(node3, "Value", item.Value);
				}
			}
		}

		public void PopulateFromDatabaseObject(DatabaseObject databaseObject)
		{
			m_databaseObject = databaseObject;
			foreach (DatabaseObject effectiveNestingChild in databaseObject.GetEffectiveNestingChildren(null, directChildrenOnly: true))
			{
				if (effectiveNestingChild.Type.SupportsValue)
				{
					if (effectiveNestingChild.Value is ProceduralValue)
					{
						object value = ((ProceduralValue)effectiveNestingChild.Value).Parse(databaseObject);
						SetValue(effectiveNestingChild.Name, value);
					}
					else
					{
						SetValue(effectiveNestingChild.Name, effectiveNestingChild.Value);
					}
				}
				else
				{
					ValuesDictionary valuesDictionary = [];
					valuesDictionary.PopulateFromDatabaseObject(effectiveNestingChild);
					SetValue(effectiveNestingChild.Name, valuesDictionary);
				}
			}
		}

		public void ApplyOverrides(ValuesDictionary overridesValuesDictionary)
		{
			foreach (KeyValuePair<string, object> item in overridesValuesDictionary)
			{
				ValuesDictionary valuesDictionary = item.Value as ValuesDictionary;
				if (valuesDictionary != null)
				{
					ValuesDictionary valuesDictionary2 = GetValue<object>(item.Key, null) as ValuesDictionary;
					if (valuesDictionary2 == null)
					{
						valuesDictionary2 = [];
						SetValue(item.Key, valuesDictionary2);
					}
					valuesDictionary2.ApplyOverrides(valuesDictionary);
				}
				else
				{
					SetValue(item.Key, item.Value);
				}
			}
		}

		public void ApplyOverrides(XElement overridesNode)
		{
			foreach (XElement item in overridesNode.Elements())
			{
				if (item.Name == "Value")
				{
					string attributeValue = XmlUtils.GetAttributeValue<string>(item, "Name");
					string attributeValue2 = XmlUtils.GetAttributeValue<string>(item, "Type", null);
					Type type;
					if (attributeValue2 == null)
					{
						object value = GetValue<object>(attributeValue, null);
						if (value == null)
						{
							throw new InvalidOperationException($"Type of override \"{attributeValue}\" cannot be determined.");
						}
						type = value.GetType();
					}
					else
					{
						type = TypeCache.FindType(attributeValue2, skipSystemAssemblies: false, throwIfNotFound: true);
					}
					object attributeValue3 = XmlUtils.GetAttributeValue(item, "Value", type);
					SetValue(attributeValue, attributeValue3);
				}
				else
				{
					if (!(item.Name == "Values"))
					{
						throw new InvalidOperationException($"Unrecognized element \"{item.Name}\" in values dictionary overrides XML.");
					}
					string attributeValue4 = XmlUtils.GetAttributeValue<string>(item, "Name");
					ValuesDictionary valuesDictionary = GetValue<object>(attributeValue4, null) as ValuesDictionary;
					if (valuesDictionary == null)
					{
						valuesDictionary = [];
						SetValue(attributeValue4, valuesDictionary);
					}
					valuesDictionary.ApplyOverrides(item);
				}
			}
		}

		public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
		{
			return m_dictionary.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return m_dictionary.GetEnumerator();
		}
	}
}

using Engine;
using Engine.Graphics;
using Engine.Serialization;
using GameEntitySystem;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using TemplatesDatabase;

namespace Game
{
	public class SubsystemMovingBlocks : Subsystem, IUpdateable, IDrawable
	{
		public class MovingBlockSet : IMovingBlockSet, IDisposable
		{
			public string Id;

			public object Tag;

			public bool Stop;

			public int RemainCounter;

			public Vector3 Position;

			public Vector3 StartPosition;

			public Vector3 TargetPosition;

			public float Speed;

			public float Acceleration;

			public float Drag;

			public Vector2 Smoothness;

			public List<MovingBlock> Blocks;

			public Box Box;

			public Vector3 CurrentVelocity;

			public Vector3 GeometryOffset;

			public Point3 GeometryGenerationPosition = new(int.MaxValue);

			Vector3 IMovingBlockSet.Position => Position;

			string IMovingBlockSet.Id => Id;

			object IMovingBlockSet.Tag => Tag;

			Vector3 IMovingBlockSet.CurrentVelocity => CurrentVelocity;
			bool IMovingBlockSet.Stopped => Stop;
			List<MovingBlock> IMovingBlockSet.Blocks => Blocks;

			public TerrainGeometry Geometry;

			public MovingBlockSet()
			{
			}

			public void Dispose()
			{
				Geometry.ClearGeometry();
			}

			public void UpdateBox()
			{
				Point3? point = null;
				Point3? point2 = null;
				foreach (MovingBlock block in Blocks)
				{
					point = point.HasValue ? Point3.Min(point.Value, block.Offset) : block.Offset;
					point2 = point2.HasValue ? Point3.Max(point2.Value, block.Offset) : block.Offset;
				}
				if (point.HasValue)
				{
					Box = new Box(point.Value.X, point.Value.Y, point.Value.Z, point2.Value.X - point.Value.X + 1, point2.Value.Y - point.Value.Y + 1, point2.Value.Z - point.Value.Z + 1);
				}
				else
				{
					Box = default(Box);
				}
			}

			public BoundingBox BoundingBox(bool extendToFillCells)
			{
				Vector3 min = new(Position.X + (float)Box.Left, Position.Y + (float)Box.Top, Position.Z + (float)Box.Near);
				Vector3 max = new(Position.X + (float)Box.Right, Position.Y + (float)Box.Bottom, Position.Z + (float)Box.Far);
				if (extendToFillCells)
				{
					min.X = MathF.Floor(min.X);
					min.Y = MathF.Floor(min.Y);
					min.Z = MathF.Floor(min.Z);
					max.X = MathF.Ceiling(max.X);
					max.Y = MathF.Ceiling(max.Y);
					max.Z = MathF.Ceiling(max.Z);
				}
				return new BoundingBox(min, max);
			}

			void IMovingBlockSet.SetBlock(Point3 offset, int value)
			{
				Blocks.RemoveAll((MovingBlock b) => b.Offset == offset);
				if (value != 0)
				{
					Blocks.Add(new MovingBlock
					{
						Offset = offset,
						Value = value
					});
				}
				UpdateBox();
				GeometryGenerationPosition = new Point3(int.MaxValue);
			}

			void IMovingBlockSet.Stop()
			{
				Stop = true;
			}
		}

		public SubsystemTime m_subsystemTime;

		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemSky m_subsystemSky;

		public SubsystemAnimatedTextures m_subsystemAnimatedTextures;

		public List<MovingBlockSet> m_movingBlockSets = [];

		public List<MovingBlockSet> m_stopped = [];

		public List<MovingBlockSet> m_removing = [];
		
		public DynamicArray<TerrainChunkGeometry.Buffer> Buffers;
		
		public DynamicArray<IMovingBlockSet> m_result = [];
		public static DynamicArray<int> m_tmpIndices = [];
		public static DynamicArray<TerrainVertex> m_vertexList = [];
		public Shader m_shader;

		public BlockGeometryGenerator m_blockGeometryGenerator;

		public bool m_canGenerateGeometry;

		public static int[] m_drawOrders = new int[1] { 10 };

		public List<IMovingBlockSet> MovingBlockSets => new(m_movingBlockSets);

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public int[] DrawOrders => m_drawOrders;

		public event Action<IMovingBlockSet, Point3> CollidedWithTerrain;

		public event Action<IMovingBlockSet> Stopped;

		public bool m_noDropOnMovingBlockStopped = false;
		public IMovingBlockSet AddMovingBlockSet(Vector3 position, Vector3 targetPosition, float speed, float acceleration, float drag, Vector2 smoothness, IEnumerable<MovingBlock> blocks, string id, object tag, bool testCollision)
		{
			MovingBlockSet movingBlockSet = new()
			{
				Position = position,
				StartPosition = position,
				TargetPosition = targetPosition,
				Speed = speed,
				Acceleration = acceleration,
				Drag = drag,
				Smoothness = smoothness,
				Id = id,
				Tag = tag,
				Blocks = blocks.ToList(),
				Geometry = new TerrainGeometry(m_subsystemAnimatedTextures.AnimatedBlocksTexture)
			};
			for(int i = 0; i < movingBlockSet.Blocks.Count; i++)
			{
				movingBlockSet.Blocks[i].MovingBlockSet = movingBlockSet;
			}
			movingBlockSet.UpdateBox();
			bool canAdd = true;
            ModsManager.HookAction("OnMovingBlockSetAdded", loader =>
            {
				loader.OnMovingBlockSetAdded(ref movingBlockSet, this, ref testCollision, out bool doNotAdd);
				canAdd &= (!doNotAdd);
                return false;
            });
			if (!canAdd) return null;
			if (testCollision)
			{
				MovingBlocksCollision(movingBlockSet);
				if (movingBlockSet.Stop)
				{
					return null;
				}
			}
			if (m_canGenerateGeometry)
			{
				GenerateGeometry(movingBlockSet);
			}
			m_movingBlockSets.Add(movingBlockSet);
			return movingBlockSet;
		}

		public void RemoveMovingBlockSet(IMovingBlockSet movingBlockSet)
		{
			MovingBlockSet movingBlockSet2 = (MovingBlockSet)movingBlockSet;
			if (m_movingBlockSets.Remove(movingBlockSet2))
			{
				m_removing.Add(movingBlockSet2);
				ModsManager.HookAction("OnMovingBlockSetRemoved", loader =>
				{
					loader.OnMovingBlockSetRemoved(movingBlockSet2, this);
					return false;
				});
                movingBlockSet2.RemainCounter = 4;
			}
		}

		public void FindMovingBlocks(BoundingBox boundingBox, bool extendToFillCells, DynamicArray<IMovingBlockSet> result)
		{
			foreach (MovingBlockSet movingBlockSet in m_movingBlockSets)
			{
				if (!movingBlockSet.Stop && ExclusiveBoxIntersection(boundingBox, movingBlockSet.BoundingBox(extendToFillCells)))
				{
					result.Add(movingBlockSet);
				}
			}
		}

		public IMovingBlockSet FindMovingBlocks(string id, object tag)
		{
			foreach (MovingBlockSet movingBlockSet in m_movingBlockSets)
			{
				if (movingBlockSet.Id == id && object.Equals(movingBlockSet.Tag, tag))
				{
					return movingBlockSet;
				}
			}
			return null;
		}

		public MovingBlocksRaycastResult? Raycast(Vector3 start, Vector3 end, bool extendToFillCells, Func<int,float,bool> action = null)
		{
			Ray3 ray = new(start, Vector3.Normalize(end - start));
			BoundingBox boundingBox = new(Vector3.Min(start, end), Vector3.Max(start, end));
			m_result.Clear();
			FindMovingBlocks(boundingBox, extendToFillCells, m_result);
			float num = float.MaxValue;
			MovingBlockSet movingBlockSet = null;
			try
			{
				foreach(var item in m_result.Array)
				{
					MovingBlockSet item1 = item as MovingBlockSet;
					if(item1 == null || item1.Stop) continue;
					BoundingBox box = item.BoundingBox(extendToFillCells);
					float? num2 = ray.Intersection(box);
					if(num2.HasValue && num2.Value < num)
					{
						num = num2.Value;
						movingBlockSet = item1;
					}
				}
			}
			catch(Exception e)
			{
				Log.Error("Moving Blocks raycast error" + e);
			}
			if (movingBlockSet != null)
			{
				float distance = float.MaxValue;
				MovingBlock rightMovingBlock = null;
				int rightCollisionBoxIndex = -1;
				BoundingBox? rightNearestBox = null;
				foreach(MovingBlock movingBlock in movingBlockSet.Blocks)
				{
					int blockValue = movingBlock.Value;
					Block block = BlocksManager.Blocks[Terrain.ExtractContents(blockValue)];
					Ray3 equalRay = new Ray3(ray.Position - movingBlockSet.Position - new Vector3(movingBlock.Offset.X, movingBlock.Offset.Y, movingBlock.Offset.Z), ray.Direction);
					float? dist = block.Raycast(equalRay, m_subsystemTerrain, blockValue, true, out int collisionBoxIndex, out BoundingBox nearestBox);
					if(dist.HasValue && dist.Value < distance && (action == null || action(blockValue, dist.Value)))
					{
						distance = dist.Value;
						rightMovingBlock = movingBlock;
						rightCollisionBoxIndex = collisionBoxIndex;
						rightNearestBox = nearestBox;
					}
				}
				MovingBlocksRaycastResult value = default(MovingBlocksRaycastResult);
				value.Ray = ray;
				value.Distance = (distance == float.MaxValue ? num : distance);
				value.MovingBlockSet = movingBlockSet;
				value.MovingBlock = rightMovingBlock;
				value.CollisionBoxIndex = rightCollisionBoxIndex;
				value.BlockBoundingBox = rightNearestBox;
				return value;
			}
			return null;
		}

		public void Update(float dt)
		{
			m_canGenerateGeometry = true;
			foreach (MovingBlockSet movingBlockSet in m_movingBlockSets)
			{
                bool pass = false;
                ModsManager.HookAction("OnMovingBlockSetUpdate", loader =>
                {
                    loader.OnMovingBlockSetUpdate(movingBlockSet, this, pass, out bool skipVanilla);
                    pass |= skipVanilla;
                    return false;
                });
				if (pass) continue;
                TerrainChunk chunkAtCell = m_subsystemTerrain.Terrain.GetChunkAtCell(Terrain.ToCell(movingBlockSet.Position.X), Terrain.ToCell(movingBlockSet.Position.Z));
				if (chunkAtCell == null || chunkAtCell.State <= TerrainChunkState.InvalidContents4)
				{
					continue;
				}
				movingBlockSet.Speed += movingBlockSet.Acceleration * m_subsystemTime.GameTimeDelta;
				if (movingBlockSet.Drag != 0f)
				{
					movingBlockSet.Speed *= MathF.Pow(1f - movingBlockSet.Drag, m_subsystemTime.GameTimeDelta);
				}
				float x = Vector3.Distance(movingBlockSet.StartPosition, movingBlockSet.Position);
				float num = Vector3.Distance(movingBlockSet.TargetPosition, movingBlockSet.Position);
				float num2 = (movingBlockSet.Smoothness.X > 0f) ? MathUtils.Saturate((MathF.Sqrt(x) + 0.05f) / movingBlockSet.Smoothness.X) : 1f;
				float num3 = (movingBlockSet.Smoothness.Y > 0f) ? MathUtils.Saturate((num + 0.05f) / movingBlockSet.Smoothness.Y) : 1f;
				float num4 = num2 * num3;
				bool flag = false;
				Vector3 vector = (num > 0f) ? ((movingBlockSet.TargetPosition - movingBlockSet.Position) / num) : Vector3.Zero;
				float x2 = (m_subsystemTime.GameTimeDelta > 0f) ? (0.95f / m_subsystemTime.GameTimeDelta) : 0f;
				float num5 = MathUtils.Min(movingBlockSet.Speed * num4, x2);
				if (num5 * m_subsystemTime.GameTimeDelta >= num)
				{
					movingBlockSet.Position = movingBlockSet.TargetPosition;
					movingBlockSet.CurrentVelocity = Vector3.Zero;
					flag = true;
				}
				else
				{
					movingBlockSet.CurrentVelocity = num5 / num * (movingBlockSet.TargetPosition - movingBlockSet.Position);
					movingBlockSet.Position += movingBlockSet.CurrentVelocity * m_subsystemTime.GameTimeDelta;
				}
				movingBlockSet.Stop = false;
				MovingBlocksCollision(movingBlockSet);
				TerrainCollision(movingBlockSet);
				if (movingBlockSet.Stop)
				{
					if (vector.X < 0f)
					{
						movingBlockSet.Position.X = MathF.Ceiling(movingBlockSet.Position.X);
					}
					else if (vector.X > 0f)
					{
						movingBlockSet.Position.X = MathF.Floor(movingBlockSet.Position.X);
					}
					if (vector.Y < 0f)
					{
						movingBlockSet.Position.Y = MathF.Ceiling(movingBlockSet.Position.Y);
					}
					else if (vector.Y > 0f)
					{
						movingBlockSet.Position.Y = MathF.Floor(movingBlockSet.Position.Y);
					}
					if (vector.Z < 0f)
					{
						movingBlockSet.Position.Z = MathF.Ceiling(movingBlockSet.Position.Z);
					}
					else if (vector.Z > 0f)
					{
						movingBlockSet.Position.Z = MathF.Floor(movingBlockSet.Position.Z);
					}
				}
				if (movingBlockSet.Stop || flag)
				{
					m_stopped.Add(movingBlockSet);
				}
			}
			foreach (MovingBlockSet item in m_stopped)
			{
				this.Stopped?.Invoke(item);
			}
			m_stopped.Clear();
		}

		public void Draw(Camera camera, int drawOrder)
		{
			foreach (TerrainChunkGeometry.Buffer buffer in Buffers)
			{
				buffer.Dispose();
			}
			Buffers.Clear();
			foreach (MovingBlockSet movingBlockSet2 in m_movingBlockSets)
			{
				DrawMovingBlockSet(camera, movingBlockSet2);
			}
			int num = 0;
			while (num < m_removing.Count)
			{
				MovingBlockSet movingBlockSet = m_removing[num];
				if (movingBlockSet.RemainCounter-- > 0)
				{
					DrawMovingBlockSet(camera, movingBlockSet);
					num++;
				}
				else
				{
					m_removing.RemoveAt(num);
					movingBlockSet.Dispose();
				}
			}
			for(int i = 0; i < Buffers.Count; i++)
			{
				var buffer = Buffers[i];
				Vector3 viewPosition = camera.ViewPosition;
				Vector3 vector = new(MathF.Floor(viewPosition.X), 0f, MathF.Floor(viewPosition.Z));
				Matrix value = Matrix.CreateTranslation(vector - viewPosition) * camera.ViewMatrix.OrientationMatrix * camera.ProjectionMatrix;
				Display.BlendState = BlendState.AlphaBlend;
				Display.DepthStencilState = DepthStencilState.Default;
				Display.RasterizerState = RasterizerState.CullCounterClockwiseScissor;
				m_shader.GetParameter("u_origin").SetValue(vector.XZ);
				m_shader.GetParameter("u_viewProjectionMatrix").SetValue(value);
				m_shader.GetParameter("u_viewPosition").SetValue(camera.ViewPosition);
				m_shader.GetParameter("u_texture").SetValue(buffer.Texture);
				m_shader.GetParameter("u_samplerState").SetValue(SamplerState.PointClamp);
				m_shader.GetParameter("u_fogYMultiplier").SetValue(m_subsystemSky.VisibilityRangeYMultiplier);
				m_shader.GetParameter("u_fogColor").SetValue(new Vector3(m_subsystemSky.ViewFogColor));
				m_shader.GetParameter("u_fogBottomTopDensity").SetValue(new Vector3(m_subsystemSky.ViewFogBottom, m_subsystemSky.ViewFogTop, m_subsystemSky.ViewFogDensity));
				m_shader.GetParameter("u_hazeStartDensity").SetValue(new Vector2(m_subsystemSky.ViewHazeStart, m_subsystemSky.ViewHazeDensity));
				m_shader.GetParameter("u_alphaThreshold").SetValue(0.5f);
				Display.DrawIndexed(PrimitiveType.TriangleList, m_shader,buffer.VertexBuffer,  buffer.IndexBuffer, 0,buffer.IndexBuffer.IndicesCount);
			}
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemTime = base.Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemSky = base.Project.FindSubsystem<SubsystemSky>(throwOnError: true);
			m_subsystemAnimatedTextures = base.Project.FindSubsystem<SubsystemAnimatedTextures>(throwOnError: true);
			m_shader = ContentManager.Get<Shader>("Shaders/AlphaTested");
			Buffers = new DynamicArray<TerrainChunkGeometry.Buffer>();
			foreach (ValuesDictionary value9 in valuesDictionary.GetValue<ValuesDictionary>("MovingBlockSets").Values)
			{
				Vector3 value = value9.GetValue<Vector3>("Position");
				Vector3 value2 = value9.GetValue<Vector3>("TargetPosition");
				float value3 = value9.GetValue<float>("Speed");
				float value4 = value9.GetValue<float>("Acceleration");
				float value5 = value9.GetValue<float>("Drag");
				Vector2 value6 = value9.GetValue("Smoothness", Vector2.Zero);
				string value7 = value9.GetValue<string>("Id", null);
				object value8 = value9.GetValue<object>("Tag", null);
				List<MovingBlock> list = [];
				string[] array = value9.GetValue<string>("Blocks").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string obj2 in array)
				{
					MovingBlock item = new MovingBlock();
					string[] array2 = obj2.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
					item.Value = HumanReadableConverter.ConvertFromString<int>(array2[0]);
					item.Offset.X = HumanReadableConverter.ConvertFromString<int>(array2[1]);
					item.Offset.Y = HumanReadableConverter.ConvertFromString<int>(array2[2]);
					item.Offset.Z = HumanReadableConverter.ConvertFromString<int>(array2[3]);
					list.Add(item);
				}
				AddMovingBlockSet(value, value2, value3, value4, value5, value6, list, value7, value8, testCollision: false);
			}
		}

		public override void Save(ValuesDictionary valuesDictionary)
		{
			ValuesDictionary valuesDictionary2 = [];
			valuesDictionary.SetValue("MovingBlockSets", valuesDictionary2);
			int num = 0;
			foreach (MovingBlockSet movingBlockSet in m_movingBlockSets)
			{
				ValuesDictionary valuesDictionary3 = [];
				valuesDictionary2.SetValue(num.ToString(CultureInfo.InvariantCulture), valuesDictionary3);
				valuesDictionary3.SetValue("Position", movingBlockSet.Position);
				valuesDictionary3.SetValue("TargetPosition", movingBlockSet.TargetPosition);
				valuesDictionary3.SetValue("Speed", movingBlockSet.Speed);
				valuesDictionary3.SetValue("Acceleration", movingBlockSet.Acceleration);
				valuesDictionary3.SetValue("Drag", movingBlockSet.Drag);
				if (movingBlockSet.Smoothness != Vector2.Zero)
				{
					valuesDictionary3.SetValue("Smoothness", movingBlockSet.Smoothness);
				}
				if (movingBlockSet.Id != null)
				{
					valuesDictionary3.SetValue("Id", movingBlockSet.Id);
				}
				if (movingBlockSet.Tag != null)
				{
					valuesDictionary3.SetValue("Tag", movingBlockSet.Tag);
				}
				StringBuilder stringBuilder = new();
				foreach (MovingBlock block in movingBlockSet.Blocks)
				{
					stringBuilder.Append(HumanReadableConverter.ConvertToString(block.Value));
					stringBuilder.Append(',');
					stringBuilder.Append(HumanReadableConverter.ConvertToString(block.Offset.X));
					stringBuilder.Append(',');
					stringBuilder.Append(HumanReadableConverter.ConvertToString(block.Offset.Y));
					stringBuilder.Append(',');
					stringBuilder.Append(HumanReadableConverter.ConvertToString(block.Offset.Z));
					stringBuilder.Append(';');
				}
				valuesDictionary3.SetValue("Blocks", stringBuilder.ToString());
				num++;
			}
		}

		public override void Dispose()
		{
			if (m_blockGeometryGenerator != null && m_blockGeometryGenerator.Terrain != null)
			{
				m_blockGeometryGenerator.Terrain.Dispose();
			}
			foreach (MovingBlockSet movingBlockSet in m_movingBlockSets)
			{
				movingBlockSet.Dispose();
			}
			foreach (MovingBlockSet item in m_removing)
			{
				item.Dispose();
			}
		}

		public void MovingBlocksCollision(MovingBlockSet movingBlockSet)
		{
			BoundingBox boundingBox = movingBlockSet.BoundingBox(extendToFillCells: true);
			m_result.Clear();
			FindMovingBlocks(boundingBox, extendToFillCells: true, m_result);
			for (int i = 0; i < m_result.Count; i++)
			{
				if (m_result.Array[i] != movingBlockSet)
				{
					movingBlockSet.Stop = true;
					break;
				}
			}
		}

		public void TerrainCollision(MovingBlockSet movingBlockSet)
		{
			Point3 point = default(Point3);
			point.X = (int)MathF.Floor((float)movingBlockSet.Box.Left + movingBlockSet.Position.X);
			point.Y = (int)MathF.Floor((float)movingBlockSet.Box.Top + movingBlockSet.Position.Y);
			point.Z = (int)MathF.Floor((float)movingBlockSet.Box.Near + movingBlockSet.Position.Z);
			Point3 point2 = default(Point3);
			point2.X = (int)MathF.Ceiling((float)movingBlockSet.Box.Right + movingBlockSet.Position.X);
			point2.Y = (int)MathF.Ceiling((float)movingBlockSet.Box.Bottom + movingBlockSet.Position.Y);
			point2.Z = (int)MathF.Ceiling((float)movingBlockSet.Box.Far + movingBlockSet.Position.Z);
			for (int i = point.X; i < point2.X; i++)
			{
				for (int j = point.Z; j < point2.Z; j++)
				{
					for (int k = point.Y; k < point2.Y; k++)
					{
						if (Terrain.ExtractContents(m_subsystemTerrain.Terrain.GetCellValue(i, k, j)) != 0)
						{
							this.CollidedWithTerrain?.Invoke(movingBlockSet, new Point3(i, k, j));
						}
					}
				}
			}
		}

		public void GenerateGeometry(MovingBlockSet movingBlockSet)
		{
			Point3 point = default(Point3);
			point.X = (movingBlockSet.CurrentVelocity.X > 0f) ? ((int)MathF.Floor(movingBlockSet.Position.X)) : (point.X = (int)MathF.Ceiling(movingBlockSet.Position.X));
			point.Y = (movingBlockSet.CurrentVelocity.Y > 0f) ? ((int)MathF.Floor(movingBlockSet.Position.Y)) : (point.Y = (int)MathF.Ceiling(movingBlockSet.Position.Y));
			point.Z = (movingBlockSet.CurrentVelocity.Z > 0f) ? ((int)MathF.Floor(movingBlockSet.Position.Z)) : (point.Z = (int)MathF.Ceiling(movingBlockSet.Position.Z));
			if (!(point != movingBlockSet.GeometryGenerationPosition))
			{
				return;
			}
			Point3 p = new(movingBlockSet.Box.Left, movingBlockSet.Box.Top, movingBlockSet.Box.Near);
			Point3 point2 = new(movingBlockSet.Box.Width, movingBlockSet.Box.Height, movingBlockSet.Box.Depth);
			int num = point.Y + p.Y;
			point2.Y = MathUtils.Min(point2.Y, 254);
			if (m_blockGeometryGenerator == null)
			{
				int x = 2;
				x = (int)MathUtils.NextPowerOf2((uint)x);
				m_blockGeometryGenerator = new BlockGeometryGenerator(new Terrain(), m_subsystemTerrain, null, base.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>(throwOnError: true), null, base.Project.FindSubsystem<SubsystemPalette>(throwOnError: true));
				for (int i = 0; i < x; i++)
				{
					for (int j = 0; j < x; j++)
					{
						m_blockGeometryGenerator.Terrain.AllocateChunk(i, j);
					}
				}
			}
			Terrain terrain = m_subsystemTerrain.Terrain;
			for (int k = 0; k < point2.X + 2; k++)
			{
				for (int l = 0; l < point2.Z + 2; l++)
				{
					int x2 = k + p.X + point.X - 1;
					int z = l + p.Z + point.Z - 1;
					int shaftValue = terrain.GetShaftValue(x2, z);
					m_blockGeometryGenerator.Terrain.SetTemperature(k, l, Terrain.ExtractTemperature(shaftValue));
					m_blockGeometryGenerator.Terrain.SetHumidity(k, l, Terrain.ExtractHumidity(shaftValue));
					for (int m = 0; m < point2.Y + 2; m++)
					{
						if (m_blockGeometryGenerator.Terrain.IsCellValid(k, m + num, l))
						{
							int y = m + p.Y + point.Y - 1;
							int cellValue = terrain.GetCellValue(x2, y, z);
							int num2 = Terrain.ExtractContents(cellValue);
							int light = Terrain.ExtractLight(cellValue);
							int shadowStrength = BlocksManager.Blocks[num2].GetShadowStrength(cellValue);
							int value = Terrain.MakeBlockValue(257, light, ShadowBlock.SetShadowStrength(0, shadowStrength));
							m_blockGeometryGenerator.Terrain.SetCellValueFast(k, m + num, l, value);
						}
					}
				}
			}
			m_blockGeometryGenerator.Terrain.SeasonTemperature = terrain.SeasonTemperature;
			m_blockGeometryGenerator.Terrain.SeasonHumidity = terrain.SeasonHumidity;
			foreach (MovingBlock block in movingBlockSet.Blocks)
			{
				int x3 = block.Offset.X - p.X + 1;
				int num3 = block.Offset.Y - p.Y + 1;
				int z2 = block.Offset.Z - p.Z + 1;
				if (m_blockGeometryGenerator.Terrain.IsCellValid(x3, num3 + num, z2))
				{
					int cellLightFast = m_blockGeometryGenerator.Terrain.GetCellLightFast(x3, num3 + num, z2);
					int value2 = Terrain.ReplaceLight(block.Value, cellLightFast);
					m_blockGeometryGenerator.Terrain.SetCellValueFast(x3, num3 + num, z2, value2);
				}
			}
			m_blockGeometryGenerator.ResetCache();
			movingBlockSet.Geometry.ClearGeometry();
			for (int n = 1; n < point2.X + 1; n++)
			{
				for (int num4 = 1; num4 < point2.Y + 1; num4++)
				{
					for (int num5 = 1; num5 < point2.Z + 1; num5++)
					{
						if (num4 + num > 0 && num4 + num < 255)
						{
							int cellValueFast = m_blockGeometryGenerator.Terrain.GetCellValueFast(n, num4 + num, num5);
							int num6 = Terrain.ExtractContents(cellValueFast);
							if (num6 != 0)
							{
								BlocksManager.Blocks[num6].GenerateTerrainVertices(m_blockGeometryGenerator, movingBlockSet.Geometry, cellValueFast, n, num4 + num, num5);
							}
						}
					}
				}
			}
			movingBlockSet.GeometryOffset = new Vector3(p) + new Vector3(0f, -num, 0f) - new Vector3(1f);
			movingBlockSet.GeometryGenerationPosition = point;
		}

		public void DrawMovingBlockSet(Camera camera, MovingBlockSet movingBlockSet)
		{
			if (camera.ViewFrustum.Intersection(movingBlockSet.BoundingBox(extendToFillCells: false)))
			{
				GenerateGeometry(movingBlockSet);
				Vector3 vector = movingBlockSet.Position + movingBlockSet.GeometryOffset;
				TerrainRenderer.CompileDrawSubsets([movingBlockSet.Geometry],Buffers,item => {
					item.X += vector.X;
					item.Y += vector.Y;
					item.Z += vector.Z;
					return item;
				});
			}
		}

		public static bool ExclusiveBoxIntersection(BoundingBox b1, BoundingBox b2)
		{
			if (b1.Max.X > b2.Min.X && b1.Min.X < b2.Max.X && b1.Max.Y > b2.Min.Y && b1.Min.Y < b2.Max.Y && b1.Max.Z > b2.Min.Z)
			{
				return b1.Min.Z < b2.Max.Z;
			}
			return false;
		}

		public virtual void AddTerrainBlock(int x, int y, int z, int value, MovingBlock movingBlock)
		{
			try
			{
				if(movingBlock == null) throw new NullReferenceException("Moving Block Set cannot be null when stop block movement!");
				movingBlock?.MovingBlockSet?.Stop();
				m_subsystemTerrain.DestroyCell(0, x, y, z, value, noDrop: m_noDropOnMovingBlockStopped, noParticleSystem: false, movingBlock);
				//m_subsystemTerrain.ChangeCell(x,y,z,value,true,movingBlock);
			}
			catch(Exception ex)
			{
				Log.Error("Add terrain block when moving blocks stop error: " + ex);
			}
		}
	}
}
using GameEntitySystem;
using System.Collections.Generic;
using TemplatesDatabase;

namespace Game
{
	public class SubsystemGameInfo : Subsystem, IUpdateable
	{
		public double? m_lastTotalElapsedGameTime;

		public SubsystemTime m_subsystemTime;

		public SubsystemTimeOfDay m_subsystemTimeOfDay;
		public WorldSettings WorldSettings
		{
			get;
			set;
		}

		public string DirectoryName
		{
			get;
			set;
		}

		public double TotalElapsedGameTime
		{
			get;
			set;
		}

		public float TotalElapsedGameTimeDelta
		{
			get;
			set;
		}

		public int WorldSeed
		{
			get;
			set;
		}

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public IEnumerable<ActiveExternalContentInfo> GetActiveExternalContent()
		{
			string downloadedContentAddress = CommunityContentManager.GetDownloadedContentAddress(ExternalContentType.World, DirectoryName);
			if (!string.IsNullOrEmpty(downloadedContentAddress))
			{
				yield return new ActiveExternalContentInfo
				{
					Address = downloadedContentAddress,
					DisplayName = WorldSettings.Name,
					Type = ExternalContentType.World
				};
			}
			if (!BlocksTexturesManager.IsBuiltIn(WorldSettings.BlocksTextureName))
			{
				downloadedContentAddress = CommunityContentManager.GetDownloadedContentAddress(ExternalContentType.BlocksTexture, WorldSettings.BlocksTextureName);
				if (!string.IsNullOrEmpty(downloadedContentAddress))
				{
					yield return new ActiveExternalContentInfo
					{
						Address = downloadedContentAddress,
						DisplayName = BlocksTexturesManager.GetDisplayName(WorldSettings.BlocksTextureName),
						Type = ExternalContentType.BlocksTexture
					};
				}
			}
			SubsystemPlayers subsystemPlayers = Project.FindSubsystem<SubsystemPlayers>(throwOnError: true);
			foreach (PlayerData playersDatum in subsystemPlayers.PlayersData)
			{
				if (!CharacterSkinsManager.IsBuiltIn(playersDatum.CharacterSkinName))
				{
					downloadedContentAddress = CommunityContentManager.GetDownloadedContentAddress(ExternalContentType.CharacterSkin, playersDatum.CharacterSkinName);
					if (!string.IsNullOrEmpty(downloadedContentAddress))
					{
						yield return new ActiveExternalContentInfo
						{
							Address = downloadedContentAddress,
							DisplayName = CharacterSkinsManager.GetDisplayName(playersDatum.CharacterSkinName),
							Type = ExternalContentType.CharacterSkin
						};
					}
				}
			}
			SubsystemFurnitureBlockBehavior subsystemFurnitureBlockBehavior = Project.FindSubsystem<SubsystemFurnitureBlockBehavior>(throwOnError: true);
			foreach (FurnitureSet furnitureSet in subsystemFurnitureBlockBehavior.FurnitureSets)
			{
				if (furnitureSet.ImportedFrom != null)
				{
					downloadedContentAddress = CommunityContentManager.GetDownloadedContentAddress(ExternalContentType.FurniturePack, furnitureSet.ImportedFrom);
					if (!string.IsNullOrEmpty(downloadedContentAddress))
					{
						yield return new ActiveExternalContentInfo
						{
							Address = downloadedContentAddress,
							DisplayName = FurniturePacksManager.GetDisplayName(furnitureSet.ImportedFrom),
							Type = ExternalContentType.FurniturePack
						};
					}
				}
			}
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemTimeOfDay = Project.FindSubsystem<SubsystemTimeOfDay>(throwOnError: true);
			WorldSettings = new WorldSettings();
			WorldSettings.Load(valuesDictionary);
			DirectoryName = valuesDictionary.GetValue<string>("WorldDirectoryName");
			TotalElapsedGameTime = valuesDictionary.GetValue<double>("TotalElapsedGameTime");
			WorldSeed = valuesDictionary.GetValue<int>("WorldSeed");
		}

		public override void Save(ValuesDictionary valuesDictionary)
		{
			WorldSettings.Save(valuesDictionary, liveModifiableParametersOnly: false);
			valuesDictionary.SetValue("WorldSeed", WorldSeed);
			valuesDictionary.SetValue("TotalElapsedGameTime", TotalElapsedGameTime);
		}

		public void Update(float dt)
		{
			TotalElapsedGameTime += dt;
			TotalElapsedGameTimeDelta = m_lastTotalElapsedGameTime.HasValue ? ((float)(TotalElapsedGameTime - m_lastTotalElapsedGameTime.Value)) : 0f;
			m_lastTotalElapsedGameTime = TotalElapsedGameTime;
			if (WorldSettings.AreSeasonsChanging && m_subsystemTime.PeriodicGameTimeEvent(10.0, 5.0))
			{
				float num = WorldSettings.YearDays * m_subsystemTimeOfDay.DayDuration;
				WorldSettings.TimeOfYear = IntervalUtils.Normalize(WorldSettings.TimeOfYear + 10f / num);
			}
			if (m_subsystemTime.GameTime >= 600.0 && m_subsystemTime.GameTime - m_subsystemTime.GameTimeDelta < 600.0 && UserManager.ActiveUser != null)
			{
				foreach (ActiveExternalContentInfo item in GetActiveExternalContent())
				{
					CommunityContentManager.SendPlayTime(item.Address, UserManager.ActiveUser.UniqueId, m_subsystemTime.GameTime, null, delegate
					{
					}, delegate
					{
					});
				}
			}
		}
	}
}

using Engine;
using GameEntitySystem;
using System;
using TemplatesDatabase;

namespace Game
{
	public class ComponentGui : Component, IUpdateable, IDrawable
	{
		public class ModalPanelAnimationData
		{
			public Widget NewWidget;

			public Widget OldWidget;

			public float Factor;
		}

		public class Message
		{
			public string LargeText;

			public string SmallText;

			public double StartTime;

			public float Duration;
		}

		public static string fName = "ComponentGui";

		public SubsystemGameInfo m_subsystemGameInfo;

		public SubsystemAudio m_subsystemAudio;

		public SubsystemTimeOfDay m_subsystemTimeOfDay;

		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemSky m_subsystemSky;

		public SubsystemWeather m_subsystemWeather;

		public SubsystemBlockBehaviors m_subsystemBlockBehaviors;

		public ComponentPlayer m_componentPlayer;

		public ContainerWidget m_leftControlsContainerWidget;

		public ContainerWidget m_rightControlsContainerWidget;

		public ContainerWidget m_moveContainerWidget;

		public ContainerWidget m_lookContainerWidget;

		public RectangleWidget m_moveRectangleWidget;

		public RectangleWidget m_lookRectangleWidget;

		public ContainerWidget m_moveRectangleContainerWidget;

		public ContainerWidget m_lookRectangleContainerWidget;

		public ContainerWidget m_movePadContainerWidget;

		public ContainerWidget m_lookPadContainerWidget;

		public ContainerWidget m_moveButtonsContainerWidget;

		public ContainerWidget m_modalPanelContainerWidget;

		public ContainerWidget m_largeMessageWidget;

		public MessageWidget m_messageWidget;

		public ButtonWidget m_backButtonWidget;

		public ButtonWidget m_inventoryButtonWidget;

		public ButtonWidget m_clothingButtonWidget;

		public ButtonWidget m_moreButtonWidget;

		public Widget m_moreContentsWidget;

		public ButtonWidget m_lightningButtonWidget;

		private ButtonWidget m_precipitationButtonWidget;

		private ButtonWidget m_fogButtonWidget;

		public ButtonWidget m_photoButtonWidget;

		public ButtonWidget m_helpButtonWidget;

		public ButtonWidget m_timeOfDayButtonWidget;

		public ButtonWidget m_cameraButtonWidget;

		public ButtonWidget m_creativeFlyButtonWidget;

		public ButtonWidget m_crouchButtonWidget;

		public ButtonWidget m_mountButtonWidget;

		public ButtonWidget m_editItemButton;

		public float m_sidePanelsFactor;

		public ModalPanelAnimationData m_modalPanelAnimationData;

		public Message m_message;

		public KeyboardHelpDialog m_keyboardHelpDialog;

		public GamepadHelpDialog m_gamepadHelpDialog;

		public double m_lastMountableCreatureSearchTime;

		public bool m_keyboardHelpMessageShown;

		public bool m_gamepadHelpMessageShown;

		public static Func<Widget> OpenClothingWidget;


		public ContainerWidget ControlsContainerWidget
		{
			get;
			set;
		}

		public TouchInputWidget ViewWidget
		{
			get;
			set;
		}

		public TouchInputWidget MoveWidget
		{
			get;
			set;
		}

		public MoveRoseWidget MoveRoseWidget
		{
			get;
			set;
		}

		public TouchInputWidget LookWidget
		{
			get;
			set;
		}

		public ShortInventoryWidget ShortInventoryWidget
		{
			get;
			set;
		}

		public ValueBarWidget HealthBarWidget
		{
			get;
			set;
		}

		public ValueBarWidget FoodBarWidget
		{
			get;
			set;
		}

		public ValueBarWidget TemperatureBarWidget
		{
			get;
			set;
		}

		public LabelWidget LevelLabelWidget
		{
			get;
			set;
		}

		public Widget ModalPanelWidget
		{
			get
			{
				if (m_modalPanelContainerWidget.Children.Count <= 0)
				{
					return null;
				}
				return m_modalPanelContainerWidget.Children[0];
			}
			set
			{
				if (value != ModalPanelWidget)
				{
					if (m_modalPanelAnimationData != null)
					{
						EndModalPanelAnimation();
					}
					m_modalPanelAnimationData = new ModalPanelAnimationData
					{
						OldWidget = ModalPanelWidget,
						NewWidget = value
					};
					if (value != null)
					{
						value.HorizontalAlignment = WidgetAlignment.Center;
						m_modalPanelContainerWidget.Children.Insert(0, value);
					}
					UpdateModalPanelAnimation();
					m_componentPlayer.GameWidget.Input.Clear();
					m_componentPlayer.ComponentInput.SetSplitSourceInventoryAndSlot(null, -1);
					ModsManager.HookAction("OnModalPanelWidgetSet", loader => { loader.OnModalPanelWidgetSet(this, ModalPanelWidget, value); return false; });
				}
			}
		}

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public int[] DrawOrders => new int[] { 9 };

		public virtual void DisplayLargeMessage(string largeText, string smallText, float duration, float delay)
		{
			m_message = new Message
			{
				LargeText = largeText,
				SmallText = smallText,
				Duration = duration,
				StartTime = Time.RealTime + delay
			};
		}
		public virtual void DisplaySmallMessage(string text, Color color, bool blinking, bool playNotificationSound)
		{
			m_messageWidget.DisplayMessage(text, color, blinking);
			if (playNotificationSound)
			{
				m_subsystemAudio.PlaySound("Audio/UI/Message", 1f, 0f, 0f, 0f);
			}
		}

		public virtual bool IsGameMenuDialogVisible()
		{
			foreach (Dialog dialog in DialogsManager.Dialogs)
			{
				if (dialog.ParentWidget == m_componentPlayer.GuiWidget && dialog is GameMenuDialog)
				{
					return true;
				}
			}
			return false;
		}

		public void Update(float dt)
		{
			HandleInput();
			UpdateWidgets();
			ModsManager.HookAction("GuiUpdate", modLoader =>
			{
				modLoader.GuiUpdate(this);
				return false;
			});
		}

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_subsystemTimeOfDay = Project.FindSubsystem<SubsystemTimeOfDay>(throwOnError: true);
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemSky = base.Project.FindSubsystem<SubsystemSky>(throwOnError: true);
			m_subsystemWeather = base.Project.FindSubsystem<SubsystemWeather>(throwOnError: true);
			m_subsystemBlockBehaviors = Project.FindSubsystem<SubsystemBlockBehaviors>(throwOnError: true);
			m_componentPlayer = Entity.FindComponent<ComponentPlayer>(throwOnError: true);
			ContainerWidget guiWidget = m_componentPlayer.GuiWidget;
			m_backButtonWidget = guiWidget.Children.Find<ButtonWidget>("BackButton");
			m_inventoryButtonWidget = guiWidget.Children.Find<ButtonWidget>("InventoryButton");
			m_clothingButtonWidget = guiWidget.Children.Find<ButtonWidget>("ClothingButton");
			m_moreButtonWidget = guiWidget.Children.Find<ButtonWidget>("MoreButton");
			m_moreContentsWidget = guiWidget.Children.Find<Widget>("MoreContents");
			m_helpButtonWidget = guiWidget.Children.Find<ButtonWidget>("HelpButton");
			m_photoButtonWidget = guiWidget.Children.Find<ButtonWidget>("PhotoButton");
			m_lightningButtonWidget = guiWidget.Children.Find<ButtonWidget>("LightningButton");
			m_precipitationButtonWidget = guiWidget.Children.Find<ButtonWidget>("PrecipitationButton");
			m_fogButtonWidget = guiWidget.Children.Find<ButtonWidget>("FogButton");
			m_timeOfDayButtonWidget = guiWidget.Children.Find<ButtonWidget>("TimeOfDayButton");
			m_cameraButtonWidget = guiWidget.Children.Find<ButtonWidget>("CameraButton");
			m_creativeFlyButtonWidget = guiWidget.Children.Find<ButtonWidget>("CreativeFlyButton");
			m_crouchButtonWidget = guiWidget.Children.Find<ButtonWidget>("CrouchButton");
			m_mountButtonWidget = guiWidget.Children.Find<ButtonWidget>("MountButton");
			m_editItemButton = guiWidget.Children.Find<ButtonWidget>("EditItemButton");
			MoveWidget = guiWidget.Children.Find<TouchInputWidget>("Move");
			MoveRoseWidget = guiWidget.Children.Find<MoveRoseWidget>("MoveRose");
			LookWidget = guiWidget.Children.Find<TouchInputWidget>("Look");
			ViewWidget = m_componentPlayer.ViewWidget;
			HealthBarWidget = guiWidget.Children.Find<ValueBarWidget>("HealthBar");
			FoodBarWidget = guiWidget.Children.Find<ValueBarWidget>("FoodBar");
			TemperatureBarWidget = guiWidget.Children.Find<ValueBarWidget>("TemperatureBar");
			LevelLabelWidget = guiWidget.Children.Find<LabelWidget>("LevelLabel");
			m_modalPanelContainerWidget = guiWidget.Children.Find<ContainerWidget>("ModalPanelContainer");
			ControlsContainerWidget = guiWidget.Children.Find<ContainerWidget>("ControlsContainer");
			m_leftControlsContainerWidget = guiWidget.Children.Find<ContainerWidget>("LeftControlsContainer");
			m_rightControlsContainerWidget = guiWidget.Children.Find<ContainerWidget>("RightControlsContainer");
			m_moveContainerWidget = guiWidget.Children.Find<ContainerWidget>("MoveContainer");
			m_lookContainerWidget = guiWidget.Children.Find<ContainerWidget>("LookContainer");
			m_moveRectangleWidget = guiWidget.Children.Find<RectangleWidget>("MoveRectangle");
			m_lookRectangleWidget = guiWidget.Children.Find<RectangleWidget>("LookRectangle");
			m_moveRectangleContainerWidget = guiWidget.Children.Find<ContainerWidget>("MoveRectangleContainer");
			m_lookRectangleContainerWidget = guiWidget.Children.Find<ContainerWidget>("LookRectangleContainer");
			m_moveRectangleWidget = guiWidget.Children.Find<RectangleWidget>("MoveRectangle");
			m_lookRectangleWidget = guiWidget.Children.Find<RectangleWidget>("LookRectangle");
			m_movePadContainerWidget = guiWidget.Children.Find<ContainerWidget>("MovePadContainer");
			m_lookPadContainerWidget = guiWidget.Children.Find<ContainerWidget>("LookPadContainer");
			m_moveButtonsContainerWidget = guiWidget.Children.Find<ContainerWidget>("MoveButtonsContainer");
			ShortInventoryWidget = guiWidget.Children.Find<ShortInventoryWidget>("ShortInventory");
			m_largeMessageWidget = guiWidget.Children.Find<ContainerWidget>("LargeMessage");
			m_messageWidget = guiWidget.Children.Find<MessageWidget>("Message");
			m_keyboardHelpMessageShown = valuesDictionary.GetValue<bool>("KeyboardHelpMessageShown");
			m_gamepadHelpMessageShown = valuesDictionary.GetValue<bool>("GamepadHelpMessageShown");
		}

		public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
		{
			valuesDictionary.SetValue("KeyboardHelpMessageShown", m_keyboardHelpMessageShown);
			valuesDictionary.SetValue("GamepadHelpMessageShown", m_gamepadHelpMessageShown);
		}

		public override void OnEntityAdded()
		{
			ShortInventoryWidget.AssignComponents(m_componentPlayer.ComponentMiner.Inventory);
		}

		public override void OnEntityRemoved()
		{
			ShortInventoryWidget.AssignComponents(null);
			m_message = null;
		}

		public override void Dispose()
		{
			ModalPanelWidget = null;
			m_keyboardHelpDialog = null;
			if (ShortInventoryWidget != null)
			{
				ShortInventoryWidget.AssignComponents(null);
			}
		}

		public virtual void UpdateSidePanelsAnimation()
		{
			float num = MathUtils.Min(Time.FrameDuration, 0.1f);
			bool flag = ModalPanelWidget != null && (m_modalPanelAnimationData == null || m_modalPanelAnimationData.NewWidget != null);
			float num2 = (!(m_componentPlayer.ComponentInput.IsControlledByTouch | flag)) ? 1 : 0;
			float x = num2 - m_sidePanelsFactor;
			if (MathF.Abs(x) > 0.01f)
			{
				m_sidePanelsFactor += Math.Clamp(12f * MathUtils.PowSign(x, 0.75f) * num, 0f - MathF.Abs(x), MathF.Abs(x));
			}
			else
			{
				m_sidePanelsFactor = num2;
			}
			m_leftControlsContainerWidget.RenderTransform = Matrix.CreateTranslation(m_leftControlsContainerWidget.ActualSize.X * (0f - m_sidePanelsFactor), 0f, 0f);
			m_rightControlsContainerWidget.RenderTransform = Matrix.CreateTranslation(m_rightControlsContainerWidget.ActualSize.X * m_sidePanelsFactor, 0f, 0f);
		}

		public virtual void UpdateModalPanelAnimation()
		{
			m_modalPanelAnimationData.Factor += 6f * MathUtils.Min(Time.FrameDuration, 0.1f);
			if (m_modalPanelAnimationData.Factor < 1f)
			{
				float factor = m_modalPanelAnimationData.Factor;
				float num = 0.5f + (0.5f * MathF.Pow(1f - factor, 0.1f));
				float num2 = 0.5f + (0.5f * MathF.Pow(factor, 0.1f));
				float s = 1f - factor;
				float s2 = factor;
				if (m_modalPanelAnimationData.OldWidget != null)
				{
					Vector2 actualSize = m_modalPanelAnimationData.OldWidget.ActualSize;
					m_modalPanelAnimationData.OldWidget.ColorTransform = Color.White * s;
					m_modalPanelAnimationData.OldWidget.RenderTransform = Matrix.CreateTranslation((0f - actualSize.X) / 2f, (0f - actualSize.Y) / 2f, 0f) * Matrix.CreateScale(num, num, 1f) * Matrix.CreateTranslation(actualSize.X / 2f, actualSize.Y / 2f, 0f);
				}
				if (m_modalPanelAnimationData.NewWidget != null)
				{
					Vector2 actualSize2 = m_modalPanelAnimationData.NewWidget.ActualSize;
					m_modalPanelAnimationData.NewWidget.ColorTransform = Color.White * s2;
					m_modalPanelAnimationData.NewWidget.RenderTransform = Matrix.CreateTranslation((0f - actualSize2.X) / 2f, (0f - actualSize2.Y) / 2f, 0f) * Matrix.CreateScale(num2, num2, 1f) * Matrix.CreateTranslation(actualSize2.X / 2f, actualSize2.Y / 2f, 0f);
				}
			}
			else
			{
				EndModalPanelAnimation();
			}
		}

		public virtual void EndModalPanelAnimation()
		{
			if (m_modalPanelAnimationData.OldWidget != null)
			{
				m_modalPanelContainerWidget.Children.Remove(m_modalPanelAnimationData.OldWidget);
			}
			if (m_modalPanelAnimationData.NewWidget != null)
			{
				m_modalPanelAnimationData.NewWidget.ColorTransform = Color.White;
				m_modalPanelAnimationData.NewWidget.RenderTransform = Matrix.Identity;
			}
			m_modalPanelAnimationData = null;
		}

		public virtual void UpdateWidgets()
		{
			ComponentRider componentRider = m_componentPlayer.ComponentRider;
			ComponentSleep componentSleep = m_componentPlayer.ComponentSleep;
			ComponentInput componentInput = m_componentPlayer.ComponentInput;
			WorldSettings worldSettings = m_subsystemGameInfo.WorldSettings;
			GameMode gameMode = worldSettings.GameMode;
			UpdateSidePanelsAnimation();
			if (m_modalPanelAnimationData != null)
			{
				UpdateModalPanelAnimation();
			}
			if (m_message != null)
			{
				double realTime = Time.RealTime;
				m_largeMessageWidget.IsVisible = true;
				LabelWidget labelWidget = m_largeMessageWidget.Children.Find<LabelWidget>("LargeLabel");
				LabelWidget labelWidget2 = m_largeMessageWidget.Children.Find<LabelWidget>("SmallLabel");
				labelWidget.Text = m_message.LargeText;
				labelWidget2.Text = m_message.SmallText;
				labelWidget.IsVisible = !string.IsNullOrEmpty(m_message.LargeText);
				labelWidget2.IsVisible = !string.IsNullOrEmpty(m_message.SmallText);
				float num = (float)Math.Min(MathUtils.Saturate(2.0 * (realTime - m_message.StartTime)), MathUtils.Saturate(2.0 * (m_message.StartTime + m_message.Duration - realTime)));
				labelWidget.Color = new Color(num, num, num, num);
				labelWidget2.Color = new Color(num, num, num, num);
				if (Time.RealTime > m_message.StartTime + m_message.Duration)
				{
					m_message = null;
				}
			}
			else
			{
				m_largeMessageWidget.IsVisible = false;
			}
			ControlsContainerWidget.IsVisible = m_componentPlayer.PlayerData.IsReadyForPlaying && m_componentPlayer.GameWidget.ActiveCamera.IsEntityControlEnabled && componentSleep.SleepFactor <= 0f;
			m_moveRectangleContainerWidget.IsVisible = !SettingsManager.HideMoveLookPads && componentInput.IsControlledByTouch;
			bool flag = false;
			if (!SettingsManager.HideMoveLookPads && componentInput.IsControlledByTouch)
			{
				if (SettingsManager.MoveControlMode == MoveControlMode.Buttons && SettingsManager.LookControlMode == LookControlMode.Pad) flag = true;
				else if (SettingsManager.MoveControlMode == MoveControlMode.Pad) flag = true;
			}
			m_lookRectangleContainerWidget.IsVisible = flag;
			m_lookPadContainerWidget.IsVisible = !SettingsManager.HideMoveLookPads && componentInput.IsControlledByTouch;
			MoveRoseWidget.IsVisible = componentInput.IsControlledByTouch;
			m_moreContentsWidget.IsVisible = m_moreButtonWidget.IsChecked;
			HealthBarWidget.IsVisible = gameMode != GameMode.Creative;
			FoodBarWidget.IsVisible = gameMode != 0 && worldSettings.AreAdventureSurvivalMechanicsEnabled;
			TemperatureBarWidget.IsVisible = gameMode != 0 && worldSettings.AreAdventureSurvivalMechanicsEnabled;
			LevelLabelWidget.IsVisible = gameMode != 0 && worldSettings.AreAdventureSurvivalMechanicsEnabled;
			m_creativeFlyButtonWidget.IsVisible = gameMode == GameMode.Creative;
			m_timeOfDayButtonWidget.IsVisible = gameMode == GameMode.Creative;
			m_lightningButtonWidget.IsVisible = gameMode == GameMode.Creative;
			m_precipitationButtonWidget.IsVisible = gameMode == GameMode.Creative && worldSettings.AreWeatherEffectsEnabled;
			m_fogButtonWidget.IsVisible = gameMode == GameMode.Creative && worldSettings.AreWeatherEffectsEnabled;
			m_moveButtonsContainerWidget.IsVisible = SettingsManager.MoveControlMode == MoveControlMode.Buttons;
			m_movePadContainerWidget.IsVisible = SettingsManager.MoveControlMode == MoveControlMode.Pad;
			if (SettingsManager.LeftHandedLayout)
			{
				m_moveContainerWidget.HorizontalAlignment = WidgetAlignment.Far;
				m_lookContainerWidget.HorizontalAlignment = WidgetAlignment.Near;
				m_moveRectangleWidget.FlipHorizontal = true;
				m_lookRectangleWidget.FlipHorizontal = false;
			}
			else
			{
				m_moveContainerWidget.HorizontalAlignment = WidgetAlignment.Near;
				m_lookContainerWidget.HorizontalAlignment = WidgetAlignment.Far;
				m_moveRectangleWidget.FlipHorizontal = false;
				m_lookRectangleWidget.FlipHorizontal = true;
			}
			m_precipitationButtonWidget.IsChecked = m_subsystemWeather.IsPrecipitationStarted;
			m_fogButtonWidget.IsChecked = m_subsystemWeather.IsFogStarted;
			m_crouchButtonWidget.IsChecked = m_componentPlayer.ComponentBody.TargetCrouchFactor > 0f;
			m_creativeFlyButtonWidget.IsChecked = m_componentPlayer.ComponentLocomotion.IsCreativeFlyEnabled;
			m_inventoryButtonWidget.IsChecked = IsInventoryVisible();
			m_clothingButtonWidget.IsChecked = IsClothingVisible();
			if (IsActiveSlotEditable() || m_componentPlayer.ComponentBlockHighlight.NearbyEditableCell.HasValue)
			{
				m_crouchButtonWidget.IsVisible = false;
				m_mountButtonWidget.IsVisible = false;
				m_editItemButton.IsVisible = true;
			}
			else if (componentRider != null && componentRider.Mount != null)
			{
				m_crouchButtonWidget.IsVisible = false;
				m_mountButtonWidget.IsChecked = true;
				m_mountButtonWidget.IsVisible = true;
				m_editItemButton.IsVisible = false;
			}
			else
			{
				m_mountButtonWidget.IsChecked = false;
				if (componentRider != null && Time.FrameStartTime - m_lastMountableCreatureSearchTime > 0.5)
				{
					m_lastMountableCreatureSearchTime = Time.FrameStartTime;
					if (componentRider.FindNearestMount() != null)
					{
						m_crouchButtonWidget.IsVisible = false;
						m_mountButtonWidget.IsVisible = true;
						m_editItemButton.IsVisible = false;
					}
					else
					{
						m_crouchButtonWidget.IsVisible = true;
						m_mountButtonWidget.IsVisible = false;
						m_editItemButton.IsVisible = false;
					}
				}
			}
			if (!m_componentPlayer.IsAddedToProject || m_componentPlayer.ComponentHealth.Health == 0f || componentSleep.IsSleeping || m_componentPlayer.ComponentSickness.IsPuking)
			{
				ModalPanelWidget = null;
			}
			if (m_componentPlayer.ComponentSickness.IsSick)
			{
				m_componentPlayer.ComponentGui.HealthBarWidget.LitBarColor = new Color(166, 175, 103);
			}
			else
			{
				m_componentPlayer.ComponentGui.HealthBarWidget.LitBarColor = m_componentPlayer.ComponentFlu.HasFlu ? new Color(0, 48, 255) : new Color(224, 24, 0);
			}
		}

		public virtual void HandleInput()
		{
			WidgetInput input = m_componentPlayer.GameWidget.Input;
			PlayerInput playerInput = m_componentPlayer.ComponentInput.PlayerInput;
			ComponentRider componentRider = m_componentPlayer.ComponentRider;
			if (m_componentPlayer.GameWidget.ActiveCamera.IsEntityControlEnabled)
			{
				if (!m_keyboardHelpMessageShown && (m_componentPlayer.PlayerData.InputDevice & WidgetInputDevice.Keyboard) != 0 && Time.PeriodicEvent(7.0, 0.0))
				{
					m_keyboardHelpMessageShown = true;
					DisplaySmallMessage(LanguageControl.Get(fName, 1), Color.White, blinking: true, playNotificationSound: true);
				}
				else if (!m_gamepadHelpMessageShown && (m_componentPlayer.PlayerData.InputDevice & WidgetInputDevice.Gamepads) != 0 && Time.PeriodicEvent(7.0, 0.0))
				{
					m_gamepadHelpMessageShown = true;
					DisplaySmallMessage(LanguageControl.Get(fName, 2), Color.White, blinking: true, playNotificationSound: true);
				}
			}
			if (playerInput.KeyboardHelp)
			{
				if (m_keyboardHelpDialog == null)
				{
					m_keyboardHelpDialog = new KeyboardHelpDialog();
				}
				if (m_keyboardHelpDialog.ParentWidget != null)
				{
					DialogsManager.HideDialog(m_keyboardHelpDialog);
				}
				else
				{
					DialogsManager.ShowDialog(m_componentPlayer.GuiWidget, m_keyboardHelpDialog);
				}
			}
			if (playerInput.GamepadHelp)
			{
				if (m_gamepadHelpDialog == null)
				{
					m_gamepadHelpDialog = new GamepadHelpDialog();
				}
				if (m_gamepadHelpDialog.ParentWidget != null)
				{
					DialogsManager.HideDialog(m_gamepadHelpDialog);
				}
				else
				{
					DialogsManager.ShowDialog(m_componentPlayer.GuiWidget, m_gamepadHelpDialog);
				}
			}
			if (m_helpButtonWidget.IsClicked)
			{
				ScreensManager.SwitchScreen("Help");
			}
			if (playerInput.ToggleInventory || m_inventoryButtonWidget.IsClicked)
			{
				if (IsInventoryVisible())
				{
					ModalPanelWidget = null;
				}
				else
				{
					ModalPanelWidget = m_componentPlayer.ComponentMiner.Inventory is ComponentCreativeInventory
						? new CreativeInventoryWidget(m_componentPlayer.Entity)
						: (Widget)new FullInventoryWidget(m_componentPlayer.ComponentMiner.Inventory, m_componentPlayer.Entity.FindComponent<ComponentCraftingTable>(throwOnError: true));
				}
			}
			if (playerInput.ToggleClothing || m_clothingButtonWidget.IsClicked)
			{
				if (IsClothingVisible())
				{
					ModalPanelWidget = null;
				}
				else
				{
					var clothingWidget = new ClothingWidget(m_componentPlayer);
					ModsManager.HookAction("ClothingWidgetOpen", modLoader =>
					{
						modLoader.ClothingWidgetOpen(this, clothingWidget);
						return false;
					});
					ModalPanelWidget = clothingWidget;

				}
			}
			if (m_crouchButtonWidget.IsClicked || playerInput.ToggleCrouch)
			{
				if (m_componentPlayer.ComponentBody.TargetCrouchFactor == 0f)
				{
					if (m_componentPlayer.ComponentBody.StandingOnValue.HasValue)
					{
						m_componentPlayer.ComponentBody.TargetCrouchFactor = 1f;
						DisplaySmallMessage(LanguageControl.Get(fName, 3), Color.White, blinking: false, playNotificationSound: false);
					}
				}
				else
				{
					m_componentPlayer.ComponentBody.TargetCrouchFactor = 0f;
					DisplaySmallMessage(LanguageControl.Get(fName, 4), Color.White, blinking: false, playNotificationSound: false);
				}
			}
			if (componentRider != null && (m_mountButtonWidget.IsClicked || playerInput.ToggleMount))
			{
				bool flag = componentRider.Mount != null;
				if (flag)
				{
					componentRider.StartDismounting();
				}
				else
				{
					ComponentMount componentMount = componentRider.FindNearestMount();
					if (componentMount != null)
					{
						componentRider.StartMounting(componentMount);
					}
				}
				if (componentRider.Mount != null != flag)
				{
					if (componentRider.Mount != null)
					{
						DisplaySmallMessage(LanguageControl.Get(fName, 5), Color.White, blinking: false, playNotificationSound: false);
					}
					else
					{
						DisplaySmallMessage(LanguageControl.Get(fName, 6), Color.White, blinking: false, playNotificationSound: false);
					}
				}
			}
			if ((m_editItemButton.IsClicked || playerInput.EditItem) && m_componentPlayer.ComponentBlockHighlight.NearbyEditableCell.HasValue)
			{
				Point3 value = m_componentPlayer.ComponentBlockHighlight.NearbyEditableCell.Value;
				int cellValue = m_subsystemTerrain.Terrain.GetCellValue(value.X, value.Y, value.Z);
				SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(cellValue));
				for (int i = 0; i < blockBehaviors.Length && !blockBehaviors[i].OnEditBlock(value.X, value.Y, value.Z, cellValue, m_componentPlayer); i++)
				{
				}
			}
			else if ((m_editItemButton.IsClicked || playerInput.EditItem) && IsActiveSlotEditable())
			{
				IInventory inventory = m_componentPlayer.ComponentMiner.Inventory;
				if (inventory != null)
				{
					int activeSlotIndex = inventory.ActiveSlotIndex;
					int value = inventory.GetSlotValue(activeSlotIndex);
					int num = Terrain.ExtractContents(value);
					if (BlocksManager.Blocks[num].IsEditable_(value))
					{
						SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(num));
						for (int i = 0; i < blockBehaviors.Length && !blockBehaviors[i].OnEditInventoryItem(inventory, activeSlotIndex, m_componentPlayer); i++)
						{
						}
					}
				}
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && (m_creativeFlyButtonWidget.IsClicked || playerInput.ToggleCreativeFly) && componentRider.Mount == null)
			{
				bool isCreativeFlyEnabled = m_componentPlayer.ComponentLocomotion.IsCreativeFlyEnabled;
				m_componentPlayer.ComponentLocomotion.IsCreativeFlyEnabled = !isCreativeFlyEnabled;
				if (m_componentPlayer.ComponentLocomotion.IsCreativeFlyEnabled != isCreativeFlyEnabled)
				{
					if (m_componentPlayer.ComponentLocomotion.IsCreativeFlyEnabled)
					{
						m_componentPlayer.ComponentLocomotion.JumpOrder = 1f;
						DisplaySmallMessage(LanguageControl.Get(fName, 7), Color.White, blinking: false, playNotificationSound: false);
					}
					else
					{
						DisplaySmallMessage(LanguageControl.Get(fName, 8), Color.White, blinking: false, playNotificationSound: false);
					}
				}
			}
			if (m_cameraButtonWidget.IsClicked || playerInput.SwitchCameraMode /*|| input.IsKeyDownOnce(Engine.Input.Key.V) 这段会导致打字时点v触发相机*/|| input.IsPadButtonDownOnce(Engine.Input.GamePadButton.RightThumb) || input.IsPadButtonDownOnce(Engine.Input.GamePadButton.DPadDown))
			{
				ModsManager.HookAction("OnCameraChange", modLoader =>
				{
					modLoader.OnCameraChange(m_componentPlayer, this);
					return false;
				});
			}
			if (m_photoButtonWidget.IsClicked || playerInput.TakeScreenshot)
			{
				ScreenCaptureManager.CapturePhoto(delegate
				{
					DisplaySmallMessage(LanguageControl.Get(fName, 13), Color.White, blinking: false, playNotificationSound: false);
				}, delegate
				{
					DisplaySmallMessage(LanguageControl.Get(fName, 14), Color.White, blinking: false, playNotificationSound: false);
				});
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && (m_lightningButtonWidget.IsClicked || playerInput.Lighting))
			{
				var matrix = Matrix.CreateFromQuaternion(m_componentPlayer.ComponentCreatureModel.EyeRotation);
				m_subsystemWeather.ManualLightingStrike(m_componentPlayer.ComponentCreatureModel.EyePosition, matrix.Forward);
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && (m_precipitationButtonWidget.IsClicked || playerInput.Precipitation))
			{
				if (m_subsystemWeather.IsPrecipitationStarted)
				{
					m_subsystemWeather.ManualPrecipitationEnd();
					DisplaySmallMessage(LanguageControl.Get(fName, 20), Color.White, blinking: false, playNotificationSound: false);
				}
				else
				{
					m_subsystemWeather.ManualPrecipitationStart();
					DisplaySmallMessage(LanguageControl.Get(fName, 21), Color.White, blinking: false, playNotificationSound: false);
				}
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && (m_fogButtonWidget.IsClicked || playerInput.Fog))
			{
				if (m_subsystemWeather.IsFogStarted)
				{
					m_subsystemWeather.ManualFogEnd();
					DisplaySmallMessage(LanguageControl.Get(fName, 22), Color.White, blinking: false, playNotificationSound: false);
				}
				else
				{
					m_subsystemWeather.ManualFogStart();
					DisplaySmallMessage(LanguageControl.Get(fName, 23), Color.White, blinking: false, playNotificationSound: false);
				}
			}
			if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative && (m_timeOfDayButtonWidget.IsClicked || playerInput.TimeOfDay))
			{
				float num2 = IntervalUtils.Interval(m_subsystemTimeOfDay.TimeOfDay, m_subsystemTimeOfDay.Middawn);
				float num3 = IntervalUtils.Interval(m_subsystemTimeOfDay.TimeOfDay, m_subsystemTimeOfDay.Midday);
				float num4 = IntervalUtils.Interval(m_subsystemTimeOfDay.TimeOfDay, m_subsystemTimeOfDay.Middusk);
				float num5 = IntervalUtils.Interval(m_subsystemTimeOfDay.TimeOfDay, m_subsystemTimeOfDay.Midnight);
				float num6 = MathUtils.Min(num2, num3, num4, num5);
				if (num2 == num6)
				{
					m_subsystemTimeOfDay.TimeOfDayOffset += num2;
					DisplaySmallMessage(LanguageControl.Get(fName, 15), Color.White, blinking: false, playNotificationSound: false);
				}
				else if (num3 == num6)
				{
					m_subsystemTimeOfDay.TimeOfDayOffset += num3;
					DisplaySmallMessage(LanguageControl.Get(fName, 16), Color.White, blinking: false, playNotificationSound: false);
				}
				else if (num4 == num6)
				{
					m_subsystemTimeOfDay.TimeOfDayOffset += num4;
					DisplaySmallMessage(LanguageControl.Get(fName, 17), Color.White, blinking: false, playNotificationSound: false);
				}
				else if (num5 == num6)
				{
					m_subsystemTimeOfDay.TimeOfDayOffset += num5;
					DisplaySmallMessage(LanguageControl.Get(fName, 18), Color.White, blinking: false, playNotificationSound: false);
				}
			}
			if (ModalPanelWidget != null)
			{
				if (input.Cancel || input.Back || m_backButtonWidget.IsClicked)
				{
					ModalPanelWidget = null;
				}
			}
			else if (input.Back || m_backButtonWidget.IsClicked)
			{
				DialogsManager.ShowDialog(m_componentPlayer.GuiWidget, new GameMenuDialog(m_componentPlayer));
			}
		}

		public virtual bool IsClothingVisible()
		{
			return ModalPanelWidget is ClothingWidget;
		}

		public virtual bool IsInventoryVisible()
		{
			if (ModalPanelWidget != null)
			{
				return !IsClothingVisible();
			}
			return false;
		}

		public virtual bool IsActiveSlotEditable()
		{
			IInventory inventory = m_componentPlayer.ComponentMiner.Inventory;
			if (inventory != null)
			{
				int activeSlotIndex = inventory.ActiveSlotIndex;
				int value = inventory.GetSlotValue(activeSlotIndex);
				int num = Terrain.ExtractContents(value);
				if (BlocksManager.Blocks[num].IsEditable_(value))
				{
					return true;
				}
			}
			return false;
		}

		public void Draw(Camera camera, int drawOrder)
		{
			ModsManager.HookAction("GuiDraw", (modloader) => { modloader.GuiDraw(this, camera, drawOrder); return false; });
		}
	}
}

using Engine;
using GameEntitySystem;
using TemplatesDatabase;

namespace Game
{
	public class SubsystemSoundMaterials : Subsystem
	{
		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemAudio m_subsystemAudio;

		public Random m_random = new();

		public ValuesDictionary m_impactsSoundsValuesDictionary;

		public ValuesDictionary m_footstepSoundsValuesDictionary;

		public void PlayImpactSound(int value, Vector3 position, float loudnessMultiplier)
		{
			int num = Terrain.ExtractContents(value);
			string soundMaterialName = BlocksManager.Blocks[num].GetSoundMaterialName(m_subsystemTerrain, value);
			if (!string.IsNullOrEmpty(soundMaterialName))
			{
				string value2 = m_impactsSoundsValuesDictionary.GetValue<string>(soundMaterialName, null);
				if (!string.IsNullOrEmpty(value2))
				{
					float pitch = m_random.Float(-0.2f, 0.2f);
					m_subsystemAudio.PlayRandomSound(value2, 0.5f * loudnessMultiplier, pitch, position, 5f * loudnessMultiplier, autoDelay: true);
				}
			}
		}

		public bool PlayFootstepSound(ComponentCreature componentCreature, float loudnessMultiplier)
		{
			string footstepSoundMaterialName = GetFootstepSoundMaterialName(componentCreature);
			if (!string.IsNullOrEmpty(footstepSoundMaterialName))
			{
				string value = componentCreature.ComponentCreatureSounds.ValuesDictionary.GetValue<ValuesDictionary>("CustomFootstepSounds").GetValue<string>(footstepSoundMaterialName, null);
				if (string.IsNullOrEmpty(value))
				{
					value = m_footstepSoundsValuesDictionary.GetValue<string>(footstepSoundMaterialName, null);
				}
				if (!string.IsNullOrEmpty(value))
				{
					float pitch = m_random.Float(-0.2f, 0.2f);
					m_subsystemAudio.PlayRandomSound(value, 0.75f * loudnessMultiplier, pitch, componentCreature.ComponentBody.Position, 2f * loudnessMultiplier, autoDelay: true);
					var componentPlayer = componentCreature as ComponentPlayer;
					if (componentPlayer != null && componentPlayer.ComponentVitalStats.Wetness > 0f)
					{
						string value2 = m_footstepSoundsValuesDictionary.GetValue<string>("Squishy", null);
						if (!string.IsNullOrEmpty(value2))
						{
							float volume = 0.7f * loudnessMultiplier * MathF.Pow(componentPlayer.ComponentVitalStats.Wetness, 4f);
							m_subsystemAudio.PlayRandomSound(value2, volume, pitch, componentCreature.ComponentBody.Position, 2f * loudnessMultiplier, autoDelay: true);
						}
					}
					return true;
				}
			}
			return false;
		}

		public string GetFootstepSoundMaterialName(ComponentCreature componentCreature)
		{
			Vector3 position = componentCreature.ComponentBody.Position;
			if (componentCreature.ComponentBody.ImmersionDepth > 0.2f && componentCreature.ComponentBody.ImmersionFluidBlock is WaterBlock)
			{
				return "Water";
			}
			if (componentCreature.ComponentLocomotion.LadderValue.HasValue)
			{
				if (Terrain.ExtractContents(componentCreature.ComponentLocomotion.LadderValue.Value) == 59)
				{
					return "WoodenLadder";
				}
				return "MetalLadder";
			}
			int cellValue = m_subsystemTerrain.Terrain.GetCellValue(Terrain.ToCell(position.X), Terrain.ToCell(position.Y + 0.1f), Terrain.ToCell(position.Z));
			int num = Terrain.ExtractContents(cellValue);
			string soundMaterialName = BlocksManager.Blocks[num].GetSoundMaterialName(m_subsystemTerrain, cellValue);
			if (string.IsNullOrEmpty(soundMaterialName) && componentCreature.ComponentBody.StandingOnValue.HasValue)
			{
				soundMaterialName = BlocksManager.Blocks[Terrain.ExtractContents(componentCreature.ComponentBody.StandingOnValue.Value)].GetSoundMaterialName(m_subsystemTerrain, componentCreature.ComponentBody.StandingOnValue.Value);
			}
			if (!string.IsNullOrEmpty(soundMaterialName))
			{
				return soundMaterialName;
			}
			return string.Empty;
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_impactsSoundsValuesDictionary = valuesDictionary.GetValue<ValuesDictionary>("ImpactSounds");
			m_footstepSoundsValuesDictionary = valuesDictionary.GetValue<ValuesDictionary>("FootstepSounds");
		}
	}
}

using Engine;
using Engine.Graphics;
using GameEntitySystem;
using System.Collections.Generic;
using System.Xml.Linq;
using TemplatesDatabase;

namespace Game
{
    public abstract class ModLoader
    {
        public ModEntity Entity;

        /// <summary>
        /// 当ModLoader类被实例化时执行
        /// </summary>
        public virtual void __ModInitialize()
        {
        }

		/// <summary>
		/// 在加载本模组的资源时触发。
		/// 注意：模组的dll只能由原版逻辑加载
		/// </summary>
		/// <param name="extension">准备调用的文件的扩展名</param>
		/// <param name="action">执行的操作</param>
		/// <param name="skip">跳过SC本体对模组获取文件的执行。由于该方法只会在调用你的模组的资源时触发，所以不必担心兼容性问题。</param>
		public virtual void GetModFiles(string extension, Action<string,Stream> action, out bool skip)
		{
			skip = false;
		}

		/// <summary>
		/// 在系统读取本模组的文件时触发
		/// 注意：modinfo文件、mod图标只能由原版逻辑加载。如果需要修改调整，请自己在模组中重新写一遍加载逻辑
		/// </summary>
		/// <param name="filename">获取模组文件的名称或前缀</param>
		/// <param name="stream">文件流</param>
		/// <param name="skip">跳过SC本体对模组获取文件的执行。由于该方法只会在调用你的模组的资源时触发，所以不必担心兼容性问题。</param>
		/// <param name="fileFound">在skip过后，返回是否得到文件</param>
		public virtual void GetModFile(string filename, Action<Stream> stream, out bool skip, out bool fileFound)
		{
			skip = false;
			fileFound = false;
		}

        /// <summary>
        /// Mod被卸载时执行
        /// </summary>
        public virtual void ModDispose()
        {
        }
        /// <summary>
        /// 视图雾颜色调整
        /// </summary>
        /// <param name="ViewUnderWaterDepth">大于0则表示在水下</param>
        /// <param name="ViewUnderMagmaDepth">大于0则表示在岩浆中</param>
        /// <param name="viewFogColor">视图雾颜色</param>
        public virtual void ViewFogColor(float ViewUnderWaterDepth, float ViewUnderMagmaDepth, ref Color viewFogColor)
        {

        }
        /// <summary>
        /// 方块亮度
        /// （黑暗区域亮度）
        /// </summary>
        /// <param name="brightness">亮度值</param>
        public virtual void CalculateLighting(ref float brightness)
        {

        }
        /// <param name="attackPower">伤害值</param>
        /// <param name="playerProbability">玩家命中率</param>
        /// <param name="creatureProbability">生物命中率</param>
        public virtual void OnMinerHit(ComponentMiner miner, ComponentBody componentBody, Vector3 hitPoint, Vector3 hitDirection, ref float attackPower, ref float playerProbability, ref float creatureProbability, out bool Hitted)
        {
            Hitted = false;
        }

        public virtual void OnMinerHit2(ComponentMiner componentMiner, ComponentBody componentBody, Vector3 hitPoint, Vector3 hitDirection, ref int durabilityReduction, ref Attackment attackment)
        {

        }

        /// <summary>
        /// 当人物挖掘时执行
        /// </summary>
        /// <param name="miner"></param>
        /// <param name="raycastResult"></param>
        /// <returns></returns>
        public virtual void OnMinerDig(ComponentMiner miner, TerrainRaycastResult raycastResult, ref float DigProgress, out bool Digged)
        {
            Digged = false;
        }

        /// <summary>
        /// 当人物放置时执行，若Placed为true则不执行原放置操作
        /// </summary>
        /// <param name="miner"></param>
        /// <param name="raycastResult"></param>
        /// <returns></returns>
        public virtual void OnMinerPlace(ComponentMiner miner, TerrainRaycastResult raycastResult, int x, int y, int z, int value, out bool Placed)
        {
            Placed = false;
        }

        /// <summary>
        /// 设置雨和雪的颜色
        /// </summary>
        /// <param name="rainColor"></param>
        /// <param name="snowColor"></param>
        /// <returns></returns>
        public virtual bool SetRainAndSnowColor(ref Color rainColor, ref Color snowColor)
        {
            return false;
        }

        /// <summary>
        /// 设置家具的颜色
        /// </summary>
        public virtual void SetFurnitureDesignColor(FurnitureDesign design, Block block, int value, ref int FaceTextureSlot, ref Color Color)
        {
        }

        /// <summary>
        /// 更改击退和晕眩效果
        /// </summary>
        /// <param name="target">目标</param>
        /// <param name="attacker">攻击者</param>
        /// <param name="hitPoint">伤害位置</param>
        /// <param name="impulseFactor">击退效果</param>
        /// <param name="stunTimeFactor">眩晕时间</param>
        /// <param name="recalculate">是否重写眩晕？</param>
        [Obsolete("该方法已过时，请使用ProcessAttackment修改Attackment的击退和击晕属性")]
        public virtual void AttackPowerParameter(ComponentBody target, ComponentCreature attacker, Vector3 hitPoint, Vector3 hitDirection, ref float impulseFactor, ref float stunTimeFactor, ref bool recalculate)
        {
        }
        /// <summary>
        /// 当人物吃东西时执行
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="block"></param>
        /// <param name="value"></param>
        /// <param name="count"></param>
        // <param name="processCount"></param>
        // <param name="processedValue"></param>
        // <param name="processedCount"></param>
        /// <returns>如果为 true：不移交到下一个 mod 处理</returns>
        public virtual bool ClothingProcessSlotItems(ComponentPlayer componentPlayer, Block block, int slotIndex, int value, int count)
        {
            return false;
        }
        public virtual void SetClothes(ComponentClothing componentClothing, ClothingSlot slot, IEnumerable<int> clothes)
        {

        }

        /// <summary>
        /// 动物吃掉落物时执行
        /// </summary>
        public virtual void OnEatPickable(ComponentEatPickableBehavior eatPickableBehavior, Pickable EatPickable, out bool Dealed)
        {
            Dealed = false;
        }

        /// <summary>
        /// 人物出生时执行
        /// </summary>
        public virtual bool OnPlayerSpawned(PlayerData.SpawnMode spawnMode, ComponentPlayer componentPlayer, Vector3 position)
        {
            return false;
        }

		/// <summary>
		/// 当人物死亡时执行。在玩家进入世界且玩家处于死亡状态时也会执行
		/// 可以通过playerData.m_stateMachine.PreviousState == "Playing"，来判断是刚死的，还是加载世界的时候就已经死了。并规避由于退出重进世界造成的“反复死亡判断”bug
		/// </summary>
		/// <param name="playerData"></param>
		public virtual void OnPlayerDead(PlayerData playerData)
        {
        }

        /// <summary>
        /// 当Miner执行AttackBody方法时执行
        /// </summary>
        /// <param name="target"></param>
        /// <param name="attacker"></param>
        /// <param name="hitPoint"></param>
        /// <param name="hitDirection"></param>
        /// <param name="attackPower"></param>
        /// <param name="isMeleeAttack"></param>
        /// <returns>false移交到下一个Mod处理,true不移交</returns>
        [Obsolete("该方法已弃用，请使用ProcessAttackment", true)]
        public virtual bool AttackBody(ComponentBody target, ComponentCreature attacker, Vector3 hitPoint, Vector3 hitDirection, ref float attackPower, bool isMeleeAttack)
        {
            return false;
        }

        /// <summary>
        /// 在攻击时执行
        /// </summary>
        /// <param name="attackment"></param>
        public virtual void ProcessAttackment(Attackment attackment)
        {

        }

        /// <summary>
        /// 当模型对象进行模型设值时执行
        /// </summary>
        public virtual void OnSetModel(ComponentModel componentModel, Model model, out bool IsSet)
        {
            IsSet = false;
        }

        /// <summary>
        /// 当动物模型对象作出动画时执行
        /// Skip为是否跳过原动画代码
        /// </summary>
        public virtual void OnModelAnimate(ComponentCreatureModel componentCreatureModel, out bool Skip)
        {
            Skip = false;
        }

        /// <summary>
        /// 计算护甲免伤时执行
        /// </summary>
        /// <param name="componentClothing"></param>
        /// <param name="attackPower">未计算免伤前的伤害</param>
        /// <returns>免伤后的伤害，当多个mod都有免伤计算时，取最小值</returns>
        public virtual float ApplyArmorProtection(ComponentClothing componentClothing, float attackPower, bool appliedByOtherMods, out bool Applied)
        {
            Applied = false;
            return attackPower;
        }

        /// <summary>
        /// 等级组件更新时执行
        /// </summary>
        /// <param name="level"></param>
        public virtual void OnLevelUpdate(ComponentLevel level)
        {
        }

        /// <summary>
        /// 因素控制力量、抗性、速度、饥饿速率组件更新时执行
        /// </summary>
        /// <param name="componentFactors"></param>
        public virtual void OnFactorsUpdate(ComponentFactors componentFactors, float dt)
        {
        }

        /// <summary>
        /// Gui组件帧更新时执行
        /// </summary>
        /// <param name="componentGui"></param>
        public virtual void GuiUpdate(ComponentGui componentGui)
        {
        }

        /// <summary>
        /// Gui组件绘制时执行
        /// </summary>
        /// <param name="componentGui"></param>
        /// <param name="camera"></param>
        /// <param name="drawOrder"></param>
        public virtual void GuiDraw(ComponentGui componentGui, Camera camera, int drawOrder)
        {
        }

        /// <summary>
        /// 更新输入时执行
        /// </summary>
        /// <param name="componentInput"></param>
        public virtual void UpdateInput(ComponentInput componentInput, WidgetInput widgetInput)
        {
        }

        /// <summary>
        /// ViewWidget绘制屏幕时执行
        /// </summary>
        public virtual void DrawToScreen(ViewWidget viewWidget, Widget.DrawContext dc)
        {
        }

        /// <summary>
        /// 衣物背包界面被打开时执行
        /// </summary>
        /// <param name="componentGui"></param>
        /// <param name="clothingWidget"></param>
        public virtual void ClothingWidgetOpen(ComponentGui componentGui, ClothingWidget clothingWidget)
        {
        }

        /// <summary>
        /// 当方块被炸掉时执行
        /// </summary>
        public virtual void OnBlockExploded(SubsystemTerrain subsystemTerrain, int x, int y, int z, int value)
        {
        }

        /// <summary>
        /// 当实体被添加时执行
        /// </summary>
        public virtual void OnEntityAdd(Entity entity)
        {
        }

        /// <summary>
        /// 当实体被移除时执行
        /// </summary>
        public virtual void OnEntityRemove(Entity entity)
        {
        }

        /// <summary>
        /// 自然生成生物列表初始化时执行
        /// </summary>
        /// <param name="spawn"></param>
        /// <param name="creatureTypes"></param>
        public virtual void InitializeCreatureTypes(SubsystemCreatureSpawn spawn, List<SubsystemCreatureSpawn.CreatureType> creatureTypes)
        {
        }

        /// <summary>
        /// 生物出生时执行
        /// </summary>
        /// <param name="spawn"></param>
        /// <param name="entity"></param>
        /// <param name="spawnEntityData"></param>
        public virtual void SpawnEntity(SubsystemSpawn spawn, Entity entity, SpawnEntityData spawnEntityData, out bool Spawned)
        {
            Spawned = false;
        }

        /// <summary>
        /// 当生物消失时执行
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="componentSpawn"></param>
        public virtual void OnDespawned(Entity entity, ComponentSpawn componentSpawn)
        {
        }

        public virtual void CalculateExplosionPower(SubsystemExplosions subsystemExplosions, ref float explosionPower)
        {

        }
        
        public virtual void OnComponentBodyExploded(ComponentBody componentBody, ref Injury explosionInjury, ref Vector3 Impulse, ref bool SetOnFire, ref float Fluctuation)
        {

        }

        /// <summary>
        /// 死亡前瞬间执行
        /// </summary>
        public virtual void DeadBeforeDrops(ComponentHealth componentHealth, ref KillParticleSystem killParticleSystem, ref bool dropAllItems)
        {
        }

        /// <summary>
        /// 重定义方块更改方法，Skip为true则不执行原ChangeCell代码
        /// </summary>
        public virtual void TerrainChangeCell(SubsystemTerrain subsystemTerrain, int x, int y, int z, int value, out bool Skip)
        {
            Skip = false;
        }

        /// <summary>
        /// 重定义生物受伤方法，Skip为true则不执行原Injure代码
        /// </summary>
        [Obsolete("该方法已被弃用，请使用CalculateCreatureInjuryAmount, OnCreatureDying, OnCreatureDied代替", true)]
        public virtual void OnCreatureInjure(ComponentHealth componentHealth, float amount, ComponentCreature attacker, bool ignoreInvulnerability, string cause, out bool Skip)
        {
            Skip = false;
        }

        /// <summary>
        /// 计算生物收到伤害的量
        /// </summary>
        public virtual void CalculateCreatureInjuryAmount(Injury injury)
        {

        }

        /// <summary>
        /// 如果动物受到Injure且生命值小于0时，执行操作。
		/// 如果在函数执行完毕后Health > 0，则取消死亡判定。
		/// 通常用于各种模组的“不死图腾”机制
        /// </summary>
        /// <param name="componentHealth"></param>
        public virtual void OnCreatureDying(ComponentHealth componentHealth, Injury injury)
        {

        }

        /// <summary>
        /// 在动物收到Injure()且生命值低于0时，执行操作。
        /// </summary>
        /// <param name="componentHealth"></param>
        public virtual void OnCreatureDied(ComponentHealth componentHealth, Injury injury, ref int experienceOrbDrop, ref bool CalculateInKill)
        {

        }

		/// <summary>
		/// 每帧更新的时候，调整血量带来的视觉效果
		/// </summary>
		/// <param name="componentHealth"></param>
		/// <param name="lastHealth">在扣血之前的生命值</param>
		/// <param name="redScreenFactor">玩家的红屏效果</param>
		/// <param name="playPainSound">是否播放受伤音效</param>
		/// <param name="healthBarFlashCount">玩家血条闪烁次数</param>
		/// <param name="creatureModelRedFactor">生物模型变红，为0时不变红，为1时完全红色</param>
        public virtual void ChangeVisualEffectOnInjury(ComponentHealth componentHealth, float lastHealth, ref float redScreenFactor, ref bool playPainSound, ref int healthBarFlashCount, ref float creatureModelRedFactor)
        {

        }

        public virtual void OnCreatureSpiked(ComponentHealth componentHealth, SubsystemBlockBehavior spikeBlockBehavior, CellFace cellFace, float velocity, ref Injury blockInjury)
        {

        }

        /// <summary>
        /// 更改天空颜色
        /// </summary>
        public virtual Color ChangeSkyColor(Color oldColor, Vector3 direction, float timeOfDay, int temperature)
        {
            return oldColor;
        }

        /// <summary>
        /// 设置着色器参数
        /// </summary>
        /// <param name="shader"></param>
        /// <param name="camera"></param>
        public virtual void SetShaderParameter(Shader shader, Camera camera)
        {
        }

        /// <summary>
        /// 更改模型着色器参数的值
        /// </summary>
        public virtual void ModelShaderParameter(Shader shader, Camera camera, List<SubsystemModelsRenderer.ModelData> modelsData, float? alphaThreshold)
        {
        }

        /// <summary>
        /// 天空额外绘制
        /// </summary>
        public virtual void SkyDrawExtra(SubsystemSky subsystemSky, Camera camera)
        {
        }

        /// <summary>
        /// 设置生物最大组件数，多个Mod时取最大
        /// </summary>
        /// <returns></returns>
        public virtual int GetMaxInstancesCount()
        {
            return 7;
        }

        /// <summary>
        /// 绘制额外模型数据的方法，如人物头顶的名字
        /// </summary>
        /// <param name="modelsRenderer"></param>
        /// <param name="modelData">正在绘制的模型</param>
        /// <param name="camera"></param>
        /// <param name="alphaThreshold"></param>
        public virtual void OnModelRendererDrawExtra(SubsystemModelsRenderer modelsRenderer, SubsystemModelsRenderer.ModelData modelData, Camera camera, float? alphaThreshold)
        {
        }

        /// <summary>
        /// 设定伤害粒子参数
        /// </summary>
        /// <param name="hitValueParticleSystem">粒子</param>
        /// <param name="attackment">产生该攻击粒子的攻击，为null表示攻击没有命中</param>
        public virtual void SetHitValueParticleSystem(HitValueParticleSystem hitValueParticleSystem, Attackment attackment)
        {
        }
        /// <summary>
        /// 当储存生物数据时
        /// </summary>
        /// <param name="spawn"></param>
        /// <param name="spawnEntityData"></param>
        public virtual void OnSaveSpawnData(ComponentSpawn spawn, SpawnEntityData spawnEntityData)
        {


        }
        /// <summary>
        /// 当读取生物数据时
        /// </summary>
        public virtual void OnReadSpawnData(Entity entity, SpawnEntityData spawnEntityData)
        {
        }

        /// <summary>
        /// 区块地形生成时
        /// 注意此方法运行在子线程中
        /// </summary>
        /// <param name="chunk"></param>
        public virtual void OnTerrainContentsGenerated(TerrainChunk chunk)
        {
        }

        /// <summary>
        /// 当区块即将被释放时
        /// KeepWorking为True时该区块会继续保持运作，不被释放
        /// </summary>
        public virtual void ToFreeChunks(TerrainUpdater terrainUpdater, TerrainChunk chunk, out bool KeepWorking)
        {
            KeepWorking = false;
        }

        /// <summary>
        /// 加载指定区块,如有区块数变动返回 true，否则返回 false
        /// </summary>
        // <param name="chunk"></param>
        public virtual bool ToAllocateChunks(TerrainUpdater terrainUpdater, TerrainUpdater.UpdateLocation[] locations)
        {
            return false;
        }

        /// <summary>
        /// 子系统帧更新时执行
        /// </summary>
        public virtual void SubsystemUpdate(float dt)
        {
        }

        /// <summary>
        /// 当Project被加载时执行
        /// </summary>
        /// <param name="project"></param>
        public virtual void OnProjectLoaded(Project project)
        {
        }

        /// <summary>
        /// 当Project被释放时执行
        /// </summary>
        public virtual void OnProjectDisposed()
        {
        }

        /// <summary>
        /// 方块初始化完成时执行
        /// </summary>
        public virtual void BlocksInitalized()
        {
        }

        /// <summary>
        /// 存档开始加载前执行
        /// </summary>
        public virtual object BeforeGameLoading(PlayScreen playScreen, object item)
        {
            return item;
        }
        /// <summary>
        /// 加载任务开始时执行
        /// 在BlocksManager初始化之前
        /// </summary>
        public virtual void OnLoadingStart(List<System.Action> actions)
        {

        }

        /// <summary>
        /// 加载任务结束时执行
        /// 在BlocksManager初始化之后
        /// </summary>
        /// <param name="actions"></param>
        public virtual void OnLoadingFinished(List<System.Action> actions)
        {
        }

        /// <summary>
        /// 游戏设置数据保存时执行
        /// </summary>
        /// <param name="xElement"></param>
        public virtual void SaveSettings(XElement xElement)
        {
        }

        /// <summary>
        /// 游戏设置数据加载时执行
        /// </summary>
        /// <param name="xElement"></param>
        public virtual void LoadSettings(XElement xElement)
        {
        }

        /// <summary>
        /// Xdb文件加载时执行
        /// </summary>
        /// <param name="xElement"></param>
        public virtual void OnXdbLoad(XElement xElement)
        {
        }

        /// <summary>
        /// Project.xml加载时执行
        /// </summary>
        /// <param name="xElement"></param>
        public virtual void ProjectXmlLoad(XElement xElement)
        {
        }

        /// <summary>
        /// Project.xml保存时执行
        /// </summary>
        /// <param name="xElement"></param>
        public virtual void ProjectXmlSave(XElement xElement)
        {
        }

        /// <summary>
        /// 配方解码时执行
        /// </summary>
        /// <param name="element">配方的Xelement</param>
        /// <param name="Decoded">是否解码成功，不成功交由下一个Mod处理</param>
        public virtual void OnCraftingRecipeDecode(List<CraftingRecipe> m_recipes, XElement element, out bool Decoded)
        {
            Decoded = false;
        }

        /// <summary>
        /// 配方匹配时执行
        /// </summary>
        /// <param name="requiredIngredients"></param>
        /// <param name="actualIngredient"></param>
        /// <param name="Matched">是否匹配成功，不成功交由下一个Mod处理</param>
        public virtual bool MatchRecipe(string[] requiredIngredients, string[] actualIngredient, out bool Matched)
        {
            Matched = false;
            return false;
        }

        /// <summary>
        /// 获得解码结果时执行
        /// </summary>
        /// <param name="result">结果字符串</param>
        /// <param name="Decoded">是否解码成功，不成功交由下一个Mod处理</param>
        /// <returns></returns>
        public virtual int DecodeResult(string result, out bool Decoded)
        {
            Decoded = false;
            return 0;
        }

        /// <summary>
        /// 解码配方
        /// </summary>
        /// <param name="ingredient"></param>
        /// <param name="craftingId"></param>
        /// <param name="data"></param>
        /// <param name="Decoded">是否解码成功，不成功交由下一个Mod处理</param>
        public virtual void DecodeIngredient(string ingredient, out string craftingId, out int? data, out bool Decoded)
        {
            Decoded = false;
            craftingId = string.Empty;
            data = null;
        }

        /// <summary>
        /// 改变相机模式时执行
        /// </summary>
        /// <param name="m_componentPlayer"></param>
        /// <param name="componentGui"></param>
        public virtual void OnCameraChange(ComponentPlayer m_componentPlayer, ComponentGui componentGui)
        {
        }

        /// <summary>
        /// 屏幕截图时执行
        /// </summary>
        public virtual void OnCapture()
        {
        }

        /// <summary>
        /// 更改主页背景音乐
        /// </summary>
        public virtual void MenuPlayMusic(out string ContentMusicPath)
        {
            ContentMusicPath = string.Empty;
        }

        /// <summary>
        /// 摇人行为
        /// </summary>
        /// <param name="herdBehavior"></param>
        /// <param name="target"></param>
        /// <param name="maxRange"></param>
        /// <param name="maxChaseTime"></param>
        /// <param name="isPersistent"></param>
        public virtual void CallNearbyCreaturesHelp(ComponentHerdBehavior herdBehavior, ComponentCreature target, float maxRange, float maxChaseTime, bool isPersistent)
        {
        }

        /// <summary>
        /// 挖掘触发宝物生成时，注意这里能获取到上个Mod生成宝物的情况
        /// </summary>
        /// <param name="BlockValue">宝物的方块值</param>
        /// <param name="Count">宝物数量</param>
        /// <param name="IsGenerate">是否继续让其它Mod处理</param>
        public virtual void OnTreasureGenerate(SubsystemTerrain subsystemTerrain, int x, int y, int z, int neighborX, int neighborY, int neighborZ, ref int BlockValue, ref int Count, out bool IsGenerate)
        {
            IsGenerate = false;
        }
        /// <summary>
        /// 当界面被创建时
        /// </summary>
        /// <param name="widget"></param>
        public virtual void OnWidgetConstruct(ref Widget widget)
        {

        }

        /// <summary>
        /// 在 DrawItem 被绘制前。
        /// </summary>
        /// <param name="drawItem">被绘制的 DrawItem。</param>
        /// <param name="skipVanillaDraw">是否跳过原版绘制代码。</param>
        /// <param name="afterWidgetDraw">原版绘制完成后的回调。</param>
        /// <param name="scissorRectangle">绘制时的 ScissorRectangle。</param>
        /// <param name="drawContext">绘制上下文。</param>
        public virtual void BeforeWidgetDrawItemRender(Widget.DrawItem drawItem, out bool skipVanillaDraw,
                                             out Action afterWidgetDraw, ref Rectangle scissorRectangle,
                                             Widget.DrawContext drawContext)
        {
            skipVanillaDraw = false;
            afterWidgetDraw = null;
        }

        /// <summary>
        /// 在 DrawItem 排序后。
        /// </summary>
        /// <param name="drawContext">绘制上下文。</param>
        public virtual void OnDrawItemAssigned(Widget.DrawContext drawContext)
        {

        }

        /// <summary>
        /// 当ModalPanelWidget被设置时执行
        /// </summary>
        /// <param name="Old"></param>
        /// <param name="New"></param>
        public virtual void OnModalPanelWidgetSet(ComponentGui gui, Widget Old, Widget New)
        {

        }

        /// <summary>
        /// 生成地形顶点时使用
        /// </summary>
        /// <param name="chunk"></param>
        public virtual void GenerateChunkVertices(TerrainChunk chunk, bool even)
        {

        }
        /// <summary>
        /// 生成光源数据
        /// </summary>
        /// <param name="lightSources">光源</param>
        /// <param name="chunk">区块</param>
        public virtual void GenerateChunkLightSources(DynamicArray<TerrainUpdater.LightSource> lightSources, TerrainChunk chunk)
        {

        }
        /// <summary>
        /// 计算动物模型光照
        /// </summary>
        /// <param name="subsystemTerrain"></param>
        /// <param name="p">动物位置</param>
        /// <param name="num">原版计算出来的强度</param>
        public virtual void CalculateSmoothLight(SubsystemTerrain subsystemTerrain, Vector3 p, ref float num)
        {

        }

        /// <summary>
        /// 当窗口模式改变时执行。
        /// </summary>
        public virtual void WindowModeChanged(WindowMode mode)
        {
        }
        /// <summary>
        /// 在执行DamageItem得到方块掉耐久后，得到的新方块值时执行
        /// </summary>
        /// <param name="block"></param>
        /// <param name="oldValue">方块的旧值</param>
        /// <param name="damageCount">损害的耐久量</param>
        /// <param name="owner">方块的拥有者</param>
        /// <param name="skipVanilla">跳过原版执行逻辑</param>
        /// <returns></returns>
        public virtual int DamageItem(Block block, int oldValue, int damageCount, Entity owner, out bool skipVanilla)
        {
            skipVanilla = false;
            return 0;
        }
        /// <summary>
        /// 当射弹击中方块时执行
        /// </summary>
        /// <param name="projectile">射弹</param>
        /// <param name="terrainRaycastResult">地形映射结果</param>
        /// <param name="triggerBlocksBehavior">是否执行被命中的方块行为</param>
        /// <param name="destroyCell">是否破坏被击中的方块</param>
        /// <param name="impactSoundLoudness">发出的声音大小</param>
        /// <param name="projectileGetStuck">射弹是否会被卡在方块里面</param>
        /// <param name="velocityAfterHit">在击中方块后，射弹的速度</param>
        /// <param name="angularVelocityAfterHit">在击中方块后，射弹的角速度</param>
        public virtual void OnProjectileHitTerrain(Projectile projectile, TerrainRaycastResult terrainRaycastResult, ref bool triggerBlocksBehavior, ref bool destroyCell, ref float impactSoundLoudness, ref bool projectileGetStuck, ref Vector3 velocityAfterHit, ref Vector3 angularVelocityAfterHit)
        {

        }
        /// <summary>
        /// 当射弹击中生物、船只等实体时执行
        /// </summary>
        /// <param name="projectile">射弹</param>
        /// <param name="bodyRaycastResult">实体映射结果</param>
        /// <param name="attackment">该射弹命中实体时，执行的攻击。可以调整attackment的攻击力等数据</param>
        /// <param name="velocityAfterAttack">在击中方块后，射弹的速度</param>
        /// <param name="angularVelocityAfterAttack">在击中方块后，射弹的角速度</param>
        /// <param name="ignoreBody">射弹行进直接穿过该生物。射弹后续的更新会忽略该生物，速度和角速度保持原状。攻击照常执行。</param>
        public virtual void OnProjectileHitBody(Projectile projectile, BodyRaycastResult bodyRaycastResult, ref Attackment attackment, ref Vector3 velocityAfterAttack, ref Vector3 angularVelocityAfterAttack, ref bool ignoreBody)
        {

        }

        /// <summary>
        /// 绘制射弹的时候执行
        /// </summary>
        /// <param name="projectile">射弹</param>
        /// <param name="subsystemProjectiles">该子系统，可以从中获取项目和其他子系统</param>
        /// <param name="camera"></param>
        /// <param name="drawOrder"></param>
        /// <param name="shouldDrawBlock">是否执行原版绘制方块的方法</param>
        /// <param name="drawBlockSize">绘制方块大小</param>
        /// <param name="drawBlockColor">绘制方块颜色</param>
        public virtual void OnProjectileDraw(Projectile projectile, SubsystemProjectiles subsystemProjectiles, Camera camera, int drawOrder, ref bool shouldDrawBlock, ref float drawBlockSize, ref Color drawBlockColor)
        {
        }

        /// <summary>
        /// 射弹离开加载区块的时候执行
        /// </summary>
        /// <param name="projectile"></param>
        public virtual void OnProjectileFlyOutOfLoadedChunks(Projectile projectile)
        {

        }

        /// <summary>
        /// 绘制掉落物的时候执行
        /// </summary>
        /// <param name="pickable"></param>
        /// <param name="subsystemPickables"></param>
        /// <param name="camera"></param>
        /// <param name="drawOrder"></param>
        /// <param name="shouldDrawBlock">是否执行原版绘制方块的方法</param>
        /// <param name="drawBlockSize"></param>
        /// <param name="drawBlockColor"></param>
        public virtual void OnPickableDraw(Pickable pickable, SubsystemPickables subsystemPickables, Camera camera, int drawOrder, ref bool shouldDrawBlock, ref float drawBlockSize, ref Color drawBlockColor)
        {
        }

        /// <summary>
        /// 执行动物的Update操作。为防止多次覆盖更新，当多个mod试图执行的时候，只有一个mod能够执行，其他mod会返回Exception。
        /// </summary>
        /// <param name="componentBody"></param>
        /// <param name="dt">动物位置</param>
        /// <param name="skipVanilla">跳过原版的更新操作</param>
		/// <param name="skippedByOtherMods">前面的mod已经执行了带skip操作的Update</param>
        public virtual void UpdateComponentBody(ComponentBody componentBody, float dt, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
            return;
        }

        /// <summary>
        /// 计算动物在Raycast下的表现。输出null表示这个body不计入Raycast结果；输出一个具体的数值表示Raycast计算出来的距离。
        /// </summary>
        /// <param name="componentBody"></param>
        /// <param name="ray">动物位置</param>
        /// <param name="skip">原版计算出来的强度</param>
        public virtual float? BodyCountInRaycast(ComponentBody componentBody, Ray3 ray, out bool skip)
        {
            skip = false;
            return null;
        }

        /// <summary>
        /// 在添加移动方块时触发
        /// </summary>
        /// <param name="movingBlockSet"></param>
		/// <param name="subsystemMovingBlocks"></param>
		/// <param name="testCollision">对应原方法的TestCollision部分</param>
		/// <param name="doNotAdd">取消添加移动方块</param>
        public virtual void OnMovingBlockSetAdded(ref SubsystemMovingBlocks.MovingBlockSet movingBlockSet, SubsystemMovingBlocks subsystemMovingBlocks, ref bool testCollision, out bool doNotAdd)
        {
            doNotAdd = false;
        }

        /// <summary>
        /// 移除移动方块时触发
        /// </summary>
        /// <param name="movingBlockSet"></param>
        /// <param name="subsystemMovingBlocks"></param>
        public virtual void OnMovingBlockSetRemoved(IMovingBlockSet movingBlockSet, SubsystemMovingBlocks subsystemMovingBlocks)
        {

        }

        /// <summary>
        /// 在移动方块更新时触发
        /// </summary>
        /// <param name="movingBlockSet"></param>
        /// <param name="subsystemMovingBlocks"></param>
        /// <param name="skippedByOtherMods">是否已被其他模组抢先执行更新</param>
        /// <param name="skipVanilla">是否跳过原版执行更新（抢先更新）</param>
        public virtual void OnMovingBlockSetUpdate(IMovingBlockSet movingBlockSet, SubsystemMovingBlocks subsystemMovingBlocks, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 游戏中添加射弹时触发
        /// </summary>
        /// <param name="subsystemProjectiles"></param>
        /// <param name="projectile"></param>
        /// <param name="loadValuesDictionary">如果是加载世界过程中首次添加，那么会提供该射弹的相关ValuesDictionary；如果是游戏进行过程中添加，则为null</param>
        public virtual void OnProjectileAdded(SubsystemProjectiles subsystemProjectiles, ref Projectile projectile, ValuesDictionary loadValuesDictionary)
        {

        }

        /// <summary>
        /// 游戏中添加掉落物时触发
        /// </summary>
        /// <param name="subsystemPickables"></param>
        /// <param name="pickable"></param>
        /// <param name="loadValuesDictionary">如果是加载世界过程中首次添加，那么会提供该射弹的相关ValuesDictionary；如果是游戏进行过程中添加，则为null</param>
        public virtual void OnPickableAdded(SubsystemPickables subsystemPickables, ref Pickable pickable, ValuesDictionary loadValuesDictionary)
        {

        }

        /// <summary>
        /// 保存世界时，存储射弹信息
        /// </summary>
        /// <param name="subsystemProjectiles"></param>
        /// <param name="projectile"></param>
        /// <param name="valuesDictionary">存储射弹信息的ValuesDictionaey</param>
        /// <exception cref="NotImplementedException"></exception>
        public virtual void SaveProjectile(SubsystemProjectiles subsystemProjectiles, Projectile projectile, ref ValuesDictionary valuesDictionary)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 保存世界时，存储掉落物信息
        /// </summary>
        /// <param name="subsystemPickables"></param>
        /// <param name="pickable"></param>
        /// <param name="valuesDictionary">存储掉落物信息的ValuesDictionary</param>
        /// <exception cref="NotImplementedException"></exception>
        public virtual void SavePickable(SubsystemPickables subsystemPickables, Pickable pickable, ref ValuesDictionary valuesDictionary)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 在方块被挖掘完毕时执行
        /// </summary>
        /// <param name="componentMiner"></param>
        /// <param name="digValue"></param>
        /// <param name="DurabilityReduction">挖掘方块所消耗工具的耐久</param>
        /// <param name="mute">挖掘方块是否取消播放音效</param>
        /// <param name="PlayerDataDugAdd">是否增加玩家统计信息的挖掘方块计数</param>
        public virtual void OnBlockDug(ComponentMiner componentMiner, BlockPlacementData digValue, int cellValue, ref int DurabilityReduction, ref bool mute, ref int PlayerDataDugAdd)
        {
            mute = false;
        }

        /// <summary>
        /// 改变SubsystemTime的时间推移速度，偏向底层，一般开发者不必了解
        /// </summary>
        /// <param name="subsystemTime"></param>
        /// <param name="dt"></param>
        public virtual void ChangeGameTimeDelta(SubsystemTime subsystemTime, ref float dt)
        {

        }

        /// <summary>
        /// 在IUpdateable添加或删除时执行，用于模组接管IUpdateable的更新行为
        /// （如恒泰模组将动物放在多线程中进行更新，降低怪物数量多导致的卡顿）
        /// </summary>
        /// <param name="subsystemUpdate"></param>
        /// <param name="updateable"></param>
        /// <param name="ToAdd1OrRemove0">这个IUpdateable是准备添加的，该变量为1；这个IUpdateable是准备移除的，该变量为0</param>
        /// <param name="skippedByOtherMods">是否已经被其他模组接管</param>
        /// <param name="skip">宣布接管，则不会被原版的SubsystemUpdate执行Update()</param>
        public virtual void OnIUpdateableAddOrRemove(SubsystemUpdate subsystemUpdate, IUpdateable updateable, bool ToAdd1OrRemove0, bool skippedByOtherMods, out bool skip)
        {
            skip = false;
        }
        /// <summary>
        /// 在IDrawable添加或删除时执行，用于模组接管IDrawable的绘制行为
        /// </summary>
        /// <param name="subsystemDrawing"></param>
        /// <param name="drawable"></param>
        /// <param name="skippedByOtherMods">是否已经被其他模组接管</param>
        /// <param name="skip">宣布接管，该IDrawable不会放入SubsystemDrawing.m_drawbles</param>
        public virtual void OnIDrawableAdded(SubsystemDrawing subsystemDrawing, IDrawable drawable, bool skippedByOtherMods, out bool skip)
        {
            skip = false;
        }
        /// <summary>
        /// 在创建家具时执行
        /// </summary>
        /// <param name="furnitureDesign"></param>
        /// <param name="designedFromExistingFurniture">是否从已有家具方块创建，通常用于mod禁止家具复制</param>
        /// <param name="pickableCount">产生的掉落物数量</param>
        /// <param name="destroyDesignBlocks">是否移除搭建的建筑原型</param>
        /// <param name="toolDamageCount">家具锤消耗的耐久量，如果家具锤剩余耐久不足以支持消耗量，则玩家无法创建家具并弹出提示</param>
        public virtual void OnFurnitureDesigned(FurnitureDesign furnitureDesign, bool designedFromExistingFurniture, ref int pickableCount, ref bool destroyDesignBlocks, ref int toolDamageCount)
        {
        }


        /// <summary>
        /// 在创建InventorySlotWidget时执行，可以增加元素
        /// </summary>
        /// <param name="inventorySlotWidget"></param>
        /// <param name="childrenWidgetsToAdd">创建InventorySlotWidget时，返回增加的子Widget</param>
        public virtual void OnInventorySlotWidgetDefined(InventorySlotWidget inventorySlotWidget, out List<Widget> childrenWidgetsToAdd)
        {
            childrenWidgetsToAdd = null;
        }

        /// <summary>
        /// 绘制物品格子的耐久条、食物条等元素
        /// </summary>
        /// <param name="inventorySlotWidget"></param>
        /// <param name="parentAvailableSize">其父widget的大小</param>
        public virtual void InventorySlotWidgetMeasureOverride(InventorySlotWidget inventorySlotWidget, Vector2 parentAvailableSize)
        {

        }

        /// <summary>
        /// 当移动物品时执行。从sourceInventory的第sourceSlotIndex个格子，移动count个物品，到targetInventory的第targetSlotIndex个格子
        /// </summary>
        /// <param name="inventorySlotWidget"></param>
        /// <param name="count">留给后面模组和原版处理物品的数量</param>
        /// <param name="moved">是否完成移动操作，注意这个不影响跳过原版处理</param>
        public virtual void HandleMoveInventoryItem(InventorySlotWidget inventorySlotWidget, IInventory sourceInventory, int sourceSlotIndex, IInventory targetInventory, int targetSlotIndex, ref int count, out bool moved)
        {
            moved = false;
        }

        /// <summary>
        /// 在InventorySlotWidget.HandleDragDrop时执行，先执行物品的修改操作
        /// （比如原版火药拖到枪身上时执行上膛操作）
        /// </summary>
        /// <param name="inventorySlotWidget">目标格子的InventorySlotWidget</param>
        /// <param name="sourceInventory"></param>
        /// <param name="sourceSlotIndex"></param>
        /// <param name="targetInventory"></param>
        /// <param name="targetSlotIndex"></param>
        /// <param name="ProcessCapacity">目标格子接受物品的数量。设置为不大于0的数相当于跳过原版逻辑</param>
        public virtual void HandleInventoryDragProcess(InventorySlotWidget inventorySlotWidget, IInventory sourceInventory, int sourceSlotIndex, IInventory targetInventory, int targetSlotIndex, ref int ProcessCapacity)
        {
        }

        /// <summary>
        /// 在InventorySlotWidget.HandleDragDrop时执行，如果物品没有修改操作，则执行移动物品操作
        /// </summary>
        /// <param name="inventorySlotWidget">目标格子的InventorySlotWidget</param>
        /// <param name="sourceInventory"></param>
        /// <param name="sourceSlotIndex"></param>
        /// <param name="targetInventory"></param>
        /// <param name="targetSlotIndex"></param>
        /// <param name="skippedByOtherMods">执行逻辑是否已经被其他模组跳过</param>
        /// <param name="skip">跳过原版的执行逻辑</param>
        public virtual void HandleInventoryDragMove(InventorySlotWidget inventorySlotWidget, IInventory sourceInventory, int sourceSlotIndex, IInventory targetInventory, int targetSlotIndex, bool skippedByOtherMods, out bool skip)
        {
            skip = false;
        }

        /// <summary>
        /// 在玩家骑上坐骑时每帧执行，用于调整玩家骑行动物时的控制逻辑
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作</param>
        public virtual void OnPlayerControlSteed(ComponentPlayer componentPlayer, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在玩家乘坐船时每帧执行，用于调整玩家乘船时的控制逻辑
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作</param>
        public virtual void OnPlayerControlBoat(ComponentPlayer componentPlayer, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在玩家乘坐船、动物以外的物体时每帧执行，用于控制玩家骑模组坐骑的控制魔力
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过其他模组执行操作</param>
        public virtual void OnPlayerControlOtherMount(ComponentPlayer componentPlayer, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 当玩家既不在坐骑上，也不在船上时执行，用于控制玩家行走的控制逻辑
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作</param>
        public virtual void OnPlayerControlWalk(ComponentPlayer componentPlayer, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }
        /// <summary>
        /// 当玩家输入交互逻辑时执行的操作
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="playerOperated">为true则停止之后的挖掘、攻击等操作</param>
        /// <param name="timeIntervalLastActionTime">距离上一次触发该操作距离的时长</param>
        /// <param name="priorityUse">控制使用优先级，使用优先级小于等于0则禁止玩家使用手中物品</param>
        /// <param name="priorityInteract">控制交互优先级，交互优先级小于等于0则禁止玩家交互方块</param>
        /// <param name="priorityPlace">控制放置优先级，放置优先级小于等于0则禁止玩家放置方块</param>
        public virtual void OnPlayerInputInteract(ComponentPlayer componentPlayer, ref bool playerOperated, ref double timeIntervalLastActionTime, ref int priorityUse, ref int priorityInteract, ref int priorityPlace)
        {

        }

        /// <summary>
        /// 在玩家正在瞄准时执行
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="aiming">是否正在瞄准</param>
        /// <param name="playerOperated">为true则停止之后的挖掘、攻击等操作</param>
        /// <param name="timeIntervalAim">和上一次执行瞄准操作，要求的最小时间间隔</param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作（为了模组间兼容性，建议只在手持自己模组方块时这样做）</param>
        public virtual void UpdatePlayerInputAim(ComponentPlayer componentPlayer, bool aiming, ref bool playerOperated, ref float timeIntervalAim, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在玩家执行“攻击”动作时执行，比如恒泰左键放箭，工业左键点击船
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="playerOperated">为true则停止之后的挖掘操作</param>
        /// <param name="timeIntervalHit">和上一次输入攻击操作，要求的最小时间间隔，小于该间隔时输入无效。（注意和ComponentMiner.HitInterval作区分）</param>
        /// <param name="meleeAttackRange">近战攻击距离，小于等于0时表示不进行近战操作（比如手持弓时近战距离改为0，就不会拿着弓拍敌人）</param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作（为了模组间兼容性，建议只在手持自己模组方块时这样做）</param>
        public virtual void OnPlayerInputHit(ComponentPlayer componentPlayer, ref bool playerOperated, ref double timeIntervalHit, ref float meleeAttackRange, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在玩家执行“挖掘”动作时执行
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="digging">玩家是否正在挖掘</param>
        /// <param name="playerOperated">为true则停止之后的创造模式中键选择物品等操作</param>
        /// <param name="timeIntervalDig">和上一次执行挖掘操作，要求的最小时间间隔。将该值降低可以像恒泰那样极速挖掘</param>
        /// <param name="skippedByOtherMods">是否已经被其他模组跳过逻辑</param>
        /// <param name="skipVanilla">跳过原版执行操作（为了模组间兼容性，建议只在手持自己模组方块时这样做）</param>
        public virtual void UpdatePlayerInputDig(ComponentPlayer componentPlayer, bool digging, ref bool playerOperated, ref double timeIntervalDig, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在玩家电脑上“按Q释放剑弃”时执行
        /// </summary>
        /// <param name="componentPlayer"></param>
        /// <param name="skippedByOtherMods"></param>
        /// <param name="skipVanilla"></param>
        public virtual void OnPlayerInputDrop(ComponentPlayer componentPlayer, bool skippedByOtherMods, out bool skipVanilla)
        {
            skipVanilla = false;
        }

        /// <summary>
        /// 在闪电劈下时执行
        /// </summary>
        /// <param name="subsystemSky"></param>
        /// <param name="targetPosition">闪电劈下的位置</param>
        /// <param name="strike">是否能成功执行</param>
        /// <param name="explosionPressure">闪电的爆炸威力</param>
        /// <param name="setBodyOnFire">是否点燃目标</param>
        public virtual void OnLightningStrike(SubsystemSky subsystemSky, ref Vector3 targetPosition, ref bool strike, ref float explosionPressure, ref bool setBodyOnFire)
        {

        }

        /// <summary>
        /// 用于调整原版已有矿物、水域、植物等地形地貌的生成，例如减少原版矿物生成量
        /// </summary>
        public virtual void OnTerrainBrushesCreated()
        {

        }

        /// <summary>
        /// 在创建世界时寻找玩家的初步生成大致位置
        /// </summary>
        /// <param name="spawnPosition">玩家初步生成大致位置</param>
        public virtual void FindCoarseSpawnPosition(ITerrainContentsGenerator terrainContentsGenerator, ref Vector3 spawnPosition)
        {

        }

        /// <summary>
        /// 在动物执行近战攻击命中目标时执行
        /// </summary>
        /// <param name="componentChaseBehavior"></param>
        /// <param name="chaseTimeBefore">在攻击之前的剩余追逐时间</param>
        /// <param name="chaseTime">在攻击之后的剩余追逐时间</param>
        /// <param name="hitBody">是否能够攻击</param>
        /// <param name="playAttackSound">是否发出攻击音效</param>
        public virtual void OnChaseBehaviorAttacked(ComponentChaseBehavior componentChaseBehavior, float chaseTimeBefore, ref float chaseTime, ref bool hitBody, ref bool playAttackSound)
        {

        }

        /// <summary>
        /// 在动物执行近战攻击没有命中目标时执行
        /// </summary>
        /// <param name="componentChaseBehavior"></param>
        /// <param name="chaseTime">在攻击之后的剩余追逐时间</param>
        public virtual void OnChaseBehaviorAttackFailed(ComponentChaseBehavior componentChaseBehavior, ref float chaseTime)
        {

        }

        /// <summary>
        /// 计算动物的坠落伤害
        /// </summary>
        /// <param name="componentHealth">生物的ComponentHealth，至于坠落速度等信息则从ComponentHealth出发寻找</param>
        /// <param name="damage">坠落伤害</param>
        public virtual void CalculateFallDamage(ComponentHealth componentHealth, ref float damage)
        {
        }

        /// <summary>
        /// 在动物晕眩或死亡时执行移动
        /// </summary>
        /// <param name="componentLocomotion"></param>
        /// <param name="fallsOnDeathOrStun">在晕眩或死亡时是否坠落</param>
        public virtual void OnLocomotionStopped(ComponentLocomotion componentLocomotion, ref bool fallsOnDeathOrStun)
        {

        }

        /// <summary>
        /// 在ComponentLocomotion加载时执行
        /// </summary>
        /// <param name="componentLocomotion"></param>
        /// <param name="mobWalkSpeedFactor">非玩家生物的移速乘数</param>
        /// <param name="mobFlySpeedFactor">非玩家生物的飞行速度乘数</param>
        /// <param name="mobSwimSpeedFactor">非玩家生物的游泳速度乘数</param>
        /// <param name="disableCreativeFlyInSurvivalMode">是否在生存模式中停止创造飞行（通常发生在创造模式切换到生存模式中）</param>
        public virtual void OnComponentLocomotionLoaded(ComponentLocomotion componentLocomotion, ref float mobWalkSpeedFactor, ref float mobFlySpeedFactor, ref float mobSwimSpeedFactor, ref bool disableCreativeFlyInSurvivalMode)
        {

        }

        /// <summary>
        /// 在发射器投掷物品时执行
        /// </summary>
        /// <param name="componentDispenser">该发射器的Component</param>
        /// <param name="pickable">要发射的掉落物</param>
        /// <param name="RemoveSlotCount">移除发射器物品栏中物品数量</param>
        public virtual void OnDispenserDispense(ComponentDispenser componentDispenser, ref Pickable pickable, ref int RemoveSlotCount)
        {

        }

        /// <summary>
        /// 在发射器弹射物品时执行
        /// </summary>
        /// <param name="componentDispenser">该发射器的Component</param>
        /// <param name="projectile">要发射的弹射物</param>
        /// <param name="canDispensePickable">发射失败时，是否以掉落物的方式发射（即使不发射也会消耗）</param>
        /// <param name="RemoveSlotCount">移除发射器物品栏中物品数量</param>
        public virtual void OnDispenserShoot(ComponentDispenser componentDispenser, ref Projectile projectile, ref bool canDispensePickable, ref int RemoveSlotCount)
        {

        }

        /// <summary>
        /// 发射器选择消耗哪一个物品进行发射
        /// </summary>
        /// <param name="componentDispenser"></param>
        /// <param name="slot">选择消耗哪一个格子的物品</param>
        /// <param name="value">选择发射什么物品</param>
        /// <param name="chosen">是否已经选择。若已经选择，则会跳过后面模组中执行。为了兼容性，仅推荐发射器在有自己模组方块的时候才执行</param>
        public virtual void DispenserChooseItemToDispense(ComponentDispenser componentDispenser, ref int slot, ref int value, out bool chosen)
        {
            chosen = false;
        }

        /// <summary>
        /// 在世界选择列表时，调整存档的外观
        /// </summary>
        /// <param name="worldInfo">世界信息</param>
        /// <param name="savedWorldItemNode">存储世界信息的XElement</param>
        /// <param name="worldInfoWidget">要修改的Widget</param>
        public virtual void LoadWorldInfoWidget(WorldInfo worldInfo, XElement savedWorldItemNode, ref ContainerWidget worldInfoWidget)
        {

        }

        /// <summary>
        /// 在方块介绍页面中，增加或减少方块的属性字段
        /// </summary>
        /// <param name="blockProperties"></param>
        public virtual void EditBlockDescriptionScreen(Dictionary<string, string> blockProperties)
        {

        }

        /// <summary>
        /// 在合成表页面时每帧更新时，编辑该页面
        /// </summary>
        /// <param name="screen"></param>
        public virtual void EditRecipeScreenWidget(RecipaediaRecipesScreen screen)
        {

        }

        /// <summary>
        /// 在生物图鉴页面每帧更新时，编辑该页面
        /// </summary>
        /// <param name="bestiaryDescriptionScreen"></param>
        /// <param name="bestiaryCreatureInfo">该生物的基础信息</param>
        /// <param name="entityValuesDictionary">该生物在Database中的ValuesDictionary</param>
        public virtual void UpdateCreaturePropertiesInBestiaryDescriptionScreen(BestiaryDescriptionScreen bestiaryDescriptionScreen, BestiaryCreatureInfo bestiaryCreatureInfo, ValuesDictionary entityValuesDictionary)
        {

        }

        /// <summary>
        /// 在生物图鉴目录列表更新该条目时，编辑该条目
        /// </summary>
        /// <param name="bestiaryScreen"></param>
        /// <param name="creatureInfoWidget">可以更改的生物信息Widget</param>
        /// <param name="bestiaryCreatureInfo">该生物的基础信息</param>
        /// <param name="entityValuesDictionary">该生物在Database中的ValuesDictioanry</param>
        public virtual void LoadCreatureInfoInBestiaryScreen(BestiaryScreen bestiaryScreen, ContainerWidget creatureInfoWidget, BestiaryCreatureInfo bestiaryCreatureInfo, ValuesDictionary entityValuesDictionary)
        {

        }

        /// <summary>
        /// 在进行世界设置时，如果不是创造模式，则会修改设定
        /// </summary>
        /// <param name="worldSettings">要修改的世界设置</param>
        /// <param name="environmentBehaviorModeBefore"></param>
        /// <param name="timeOfDayModeBefore"></param>
        /// <param name="areWeatherEffectsEnabledBefore"></param>
        /// <param name="areSurvivalMechanicsEnabledBefore"></param>
        public virtual void ResetOptionsForNonCreativeMode(WorldSettings worldSettings, EnvironmentBehaviorMode environmentBehaviorModeBefore, TimeOfDayMode timeOfDayModeBefore, bool areWeatherEffectsEnabledBefore, bool areSurvivalMechanicsEnabledBefore)
        {

        }

        /// <summary>
        /// 在配方表加载的时候执行，用于删除原版配方
        /// </summary>
        /// <param name="recipes">已经加载的配方</param>
        /// <param name="sort">是否在删除后重新排序</param>
        public virtual void CraftingRecipesManagerInitialize(List<CraftingRecipe> recipes, ref bool sort)
        {

        }

        /// <summary>
        /// 在游戏游玩过程中时放音乐
        /// </summary>
        public virtual void PlayInGameMusic()
        {

        }
		[Obsolete("Use TerrainContentsGenerator24Initialize")]
		public virtual void TerrainContentsGenerator23Initialize(ITerrainContentsGenerator terrainContentsGenerator,SubsystemTerrain subsystemTerrain)
		{

		}
		public virtual void TerrainContentsGenerator24Initialize(ITerrainContentsGenerator terrainContentsGenerator, SubsystemTerrain subsystemTerrain)
        {
        }

        public virtual void PrepareModels(SubsystemModelsRenderer subsystemModelsRenderer, Camera camera, bool skippedByOtherMods, out bool skip)
        {
            skip = false;
        }

        public virtual void RenderModels(SubsystemModelsRenderer subsystemModelsRenderer, Camera camera, int drawOrder, bool skippedByOtherMods, out bool skip)
        {
            skip = false;
        }

		/// <summary>
		/// 在更新玩家死亡界面时执行
		/// </summary>
		/// <param name="playerData">具体死者</param>
		/// <param name="disableVanillaTapToRespawnAction">是否阻止原版点击任意键就执行复活等下一步的操作</param>
		/// <param name="respawn">是否复活</param>

		public virtual void UpdateDeathCameraWidget(PlayerData playerData, ref bool disableVanillaTapToRespawnAction, ref bool respawn)
		{

		}

		/// <summary>
		/// 在爆炸开始，计算动物摇晃程度时执行。
		/// 为了尽可能确保兼容性，建议只对属于自己模组的生物进行接管编辑
		/// </summary>
		/// <param name="componentBody">将要摇晃的动物</param>
		/// <param name="explosionCenter">爆炸中心地点</param>
		/// <param name="explosionPressure">爆炸强度</param>
		/// <param name="shakeStrength">动物摇晃的强度</param>
		public virtual void OnComponentBodyExplodedStart(ComponentBody componentBody, Vector3 explosionCenter, float explosionPressure, ref float shakeStrength)
		{

		}

		/// <summary>
		/// 在游戏执行植物生长判定时执行，为保证良好兼容性，建议只在处理属于自己模组的方块时改变控制
		/// </summary>
		/// <param name="subsystemPlantBlockBehavior">子系统，便于定位SubsystemTerrain等必要组件</param>
		/// <param name="x">植物的坐标x</param>
		/// <param name="y">植物的坐标y</param>
		/// <param name="z">植物的坐标z</param>
		/// <param name="pollPass">用途不确定</param>
		/// <param name="skipVanilla">是否跳过原版的执行进程，注意本接口不能跳过其他模组的执行进程</param>
		public virtual void GrowPlant(SubsystemPlantBlockBehavior subsystemPlantBlockBehavior, int x, int y,int z, int pollPass, out bool skipVanilla)
		{
			skipVanilla = false;
		}

		/// <summary>
		/// 射弹转化为掉落物时执行
		/// </summary>
		/// <param name="projectile">即将被转化并删除的射弹</param>
		/// <param name="pickable">即将加入的掉落物</param>
		public virtual void OnProjectileTurnIntoPickable(Projectile projectile, ref Pickable pickable)
		{

		}

		/// <summary>
		/// 在实体创建时执行，可用于移除实体的特定组件
		/// </summary>
		/// <param name="entity">被创建的实体</param>
		/// <param name="componentList">这个实体将会拥有的Component，KeyValuePair的第一个表示Component的加载顺序编号，第二个表示实体的Component</param>
		public virtual void EntityComponentsInitialized(Entity entity, List<KeyValuePair<int,Component>> componentList)
		{

		}

		/// <summary>
		/// 游戏Project创建时执行，可用于移除Subsystem、Entity、Entity.Component
		/// </summary>
		/// <param name="project"></param>
		public virtual void ProjectBeforeSubsystemsAndEntitiesLoad(Project project)
		{

		}

		/// <summary>
		/// 进入Screen时执行
		/// </summary>
		/// <param name="screen">进入的Screen</param>
		/// <param name="screenParameters">进入Screen时传入的参数</param>
		public virtual void OnScreenEntered(Screen screen,object[] screenParameters)
		{

		}

		/// <summary>
		/// 离开Screen时执行
		/// </summary>
		/// <param name="screen">离开的Screen</param>
		public virtual void OnScreenLeaved(Screen screen) 
		{
		}
	}
}

using Engine;

namespace Game
{
	public class FppCamera : BasePerspectiveCamera
	{
		public override bool UsesMovementControls => false;

		public override bool IsEntityControlEnabled => true;

		public FppCamera(GameWidget gameWidget)
			: base(gameWidget)
		{
		}

		public override void Activate(Camera previousCamera)
		{
			SetupPerspectiveCamera(previousCamera.ViewPosition, previousCamera.ViewDirection, previousCamera.ViewUp);
		}

		public override void Update(float dt)
		{
			if (GameWidget.Target != null)
			{
				var matrix = Matrix.CreateFromQuaternion(GameWidget.Target.ComponentCreatureModel.EyeRotation);
				matrix.Translation = GameWidget.Target.ComponentCreatureModel.EyePosition;
				SetupPerspectiveCamera(matrix.Translation, matrix.Forward, matrix.Up);
			}
		}
	}
}

using Engine;
using Engine.Graphics;
using GameEntitySystem;
using System;
using TemplatesDatabase;

namespace Game
{
	public class ComponentHumanModel : ComponentCreatureModel
	{
		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemModelsRenderer m_subsystemModelsRenderer;

		public SubsystemNoise m_subsystemNoise;

		public SubsystemAudio m_subsystemAudio;

		public ComponentMiner m_componentMiner;

		public ComponentRider m_componentRider;

		public ComponentSleep m_componentSleep;

		public ComponentPlayer m_componentPlayer;

		public DrawBlockEnvironmentData m_drawBlockEnvironmentData = new();

		public ModelBone m_bodyBone;

		public ModelBone m_headBone;

		public ModelBone m_leg1Bone;

		public ModelBone m_leg2Bone;

		public ModelBone m_hand1Bone;

		public ModelBone m_hand2Bone;

		public float m_sneakFactor;
		public float m_lieDownFactorEye;

		public float m_lieDownFactorModel;

		public float m_walkAnimationSpeed;

		public float m_walkLegsAngle;

		public float m_walkBobHeight;

		public float m_headingOffset;

		public float m_punchFactor;

		public float m_punchPhase;

		public int m_punchCounter;

		public float m_footstepsPhase;

		public bool m_rowLeft;

		public bool m_rowRight;

		public float m_aimHandAngle;

		public Vector3 m_inHandItemOffset;

		public Vector3 m_inHandItemRotation;

		public Vector2 m_headAngles;

		public Vector2 m_handAngles1;

		public Vector2 m_handAngles2;

		public Vector2 m_legAngles1;

		public Vector2 m_legAngles2;

		public override void Update(float dt)
		{
			m_sneakFactor = m_componentCreature.ComponentBody.IsCrouching
				? MathUtils.Min(m_sneakFactor + (2f * dt), 1f)
				: MathUtils.Max(m_sneakFactor - (2f * dt), 0f);

			if ((m_componentSleep != null && m_componentSleep.IsSleeping) || m_componentCreature.ComponentHealth.Health <= 0f)
			{
				m_lieDownFactorEye = MathUtils.Min(m_lieDownFactorEye + (1f * dt), 1f);
				m_lieDownFactorModel = MathUtils.Min(m_lieDownFactorModel + (3f * dt), 1f);
			}
			else
			{
				m_lieDownFactorEye = MathUtils.Max(m_lieDownFactorEye - (1f * dt), 0f);
				m_lieDownFactorModel = MathUtils.Max(m_lieDownFactorModel - (3f * dt), 0f);
			}
			bool flag = true;
			bool flag2 = true;
			float footstepsPhase = m_footstepsPhase;
			if (m_componentCreature.ComponentLocomotion.LadderValue.HasValue)
			{
				m_footstepsPhase += 1.5f * m_walkAnimationSpeed * m_componentCreature.ComponentBody.Velocity.Length() * dt;
				flag2 = false;
			}
			else if (!m_componentCreature.ComponentLocomotion.IsCreativeFlyEnabled)
			{
				float num = m_componentCreature.ComponentLocomotion.SlipSpeed ?? (m_componentCreature.ComponentBody.Velocity.XZ - m_componentCreature.ComponentBody.StandingOnVelocity.XZ).Length();
				if (num > 0.5f)
				{
					MovementAnimationPhase += num * dt * m_walkAnimationSpeed;
					m_footstepsPhase += 1f * m_walkAnimationSpeed * num * dt;
					flag = false;
					flag2 = false;
				}
			}
			if (flag)
			{
				float num2 = 0.5f * MathF.Floor(2f * MovementAnimationPhase);
				if (MovementAnimationPhase != num2)
				{
					MovementAnimationPhase = MovementAnimationPhase - num2 > 0.25f
						? MathUtils.Min(MovementAnimationPhase + (2f * dt), num2 + 0.5f)
						: MathUtils.Max(MovementAnimationPhase - (2f * dt), num2);
				}
			}
			if (flag2)
			{
				m_footstepsPhase = 0f;
			}
			float num3 = 0f;
			ComponentMount componentMount = (m_componentRider != null) ? m_componentRider.Mount : null;
			if (componentMount != null)
			{
				ComponentCreatureModel componentCreatureModel = componentMount.Entity.FindComponent<ComponentCreatureModel>();
				if (componentCreatureModel != null)
				{
					Bob = componentCreatureModel.Bob;
					num3 = Bob;
				}
				m_headingOffset = 0f;
			}
			else
			{
				float x = MathF.Sin((float)Math.PI * 2f * MovementAnimationPhase);
				num3 = m_walkBobHeight * MathUtils.Sqr(x);
				float num4 = 0f;
				if (m_componentCreature.ComponentLocomotion.LastWalkOrder.HasValue && m_componentCreature.ComponentLocomotion.LastWalkOrder != Vector2.Zero)
				{
					num4 = Vector2.Angle(Vector2.UnitY, m_componentCreature.ComponentLocomotion.LastWalkOrder.Value);
				}
				m_headingOffset += MathUtils.NormalizeAngle(num4 - m_headingOffset) * MathUtils.Saturate(8f * m_subsystemTime.GameTimeDelta);
				m_headingOffset = MathUtils.NormalizeAngle(m_headingOffset);
			}
			float num5 = MathUtils.Min(12f * m_subsystemTime.GameTimeDelta, 1f);
			Bob += num5 * (num3 - Bob);
			IsAttackHitMoment = false;
			if (AttackOrder)
			{
				m_punchFactor = MathUtils.Min(m_punchFactor + (4f * dt), 1f);
				float punchPhase = m_punchPhase;
				m_punchPhase = MathUtils.Remainder(m_punchPhase + (dt * 2f), 1f);
				if (punchPhase < 0.5f && m_punchPhase >= 0.5f)
				{
					IsAttackHitMoment = true;
					m_punchCounter++;
				}
			}
			else
			{
				m_punchFactor = MathUtils.Max(m_punchFactor - (4f * dt), 0f);
				if (m_punchPhase != 0f)
				{
					if (m_punchPhase > 0.5f)
					{
						m_punchPhase = MathUtils.Remainder(MathUtils.Min(m_punchPhase + (dt * 2f), 1f), 1f);
					}
					else if (m_punchPhase > 0f)
					{
						m_punchPhase = MathUtils.Max(m_punchPhase - (dt * m_punchPhase), 0f);
					}
				}
			}
			m_rowLeft = RowLeftOrder;
			m_rowRight = RowRightOrder;
			if ((m_rowLeft || m_rowRight) && componentMount != null && componentMount.ComponentBody.ImmersionFactor > 0f && Math.Floor(1.1000000238418579 * m_subsystemTime.GameTime) != Math.Floor(1.1000000238418579 * (m_subsystemTime.GameTime - m_subsystemTime.GameTimeDelta)))
			{
				m_subsystemAudio.PlayRandomSound("Audio/Rowing", m_random.Float(0.4f, 0.6f), m_random.Float(-0.3f, 0.2f), m_componentCreature.ComponentBody.Position, 3f, autoDelay: true);
			}
			float num6 = MathF.Floor(m_footstepsPhase);
			if (m_footstepsPhase > num6 && footstepsPhase <= num6)
			{
				if (m_componentCreature.ComponentBody.CrouchFactor < 1f)
				{
					m_subsystemNoise.MakeNoise(m_componentCreature.ComponentBody, 0.25f, 8f);
				}
				if (!m_componentCreature.ComponentCreatureSounds.PlayFootstepSound(1f))
				{
					m_footstepsPhase = 0f;
				}
			}
			m_aimHandAngle = AimHandAngleOrder;
			m_inHandItemOffset = Vector3.Lerp(m_inHandItemOffset, InHandItemOffsetOrder, 10f * dt);
			m_inHandItemRotation = Vector3.Lerp(m_inHandItemRotation, InHandItemRotationOrder, 10f * dt);
			AttackOrder = false;
			RowLeftOrder = false;
			RowRightOrder = false;
			AimHandAngleOrder = 0f;
			InHandItemOffsetOrder = Vector3.Zero;
			InHandItemRotationOrder = Vector3.Zero;
			base.Update(dt);
		}

		public override void AnimateCreature()
		{
			bool flag = false;
			bool skip = false;
			ModsManager.HookAction("OnModelAnimate", loader =>
			{
				loader.OnModelAnimate(this, out skip);
				flag = flag | skip;
				return false;
			});
			if (flag)
			{
				return;
			}
			Vector3 position = m_componentCreature.ComponentBody.Position;
			Vector3 vector = m_componentCreature.ComponentBody.Rotation.ToYawPitchRoll();
			if (OnAnimate != null && OnAnimate()) return;
			if (m_lieDownFactorModel == 0f)
			{
				ComponentMount componentMount = (m_componentRider != null) ? m_componentRider.Mount : null;
				float num = MathF.Sin((float)Math.PI * 2f * MovementAnimationPhase);
				position.Y += Bob;
				vector.X += m_headingOffset;
				float num2 = (float)MathUtils.Remainder((0.75 * m_subsystemGameInfo.TotalElapsedGameTime) + (GetHashCode() & 0xFFFF), 10000.0);
				float x = Math.Clamp(MathUtils.Lerp(-0.3f, 0.3f, SimplexNoise.Noise((1.02f * num2) - 100f)) + m_componentCreature.ComponentLocomotion.LookAngles.X + (1f * m_componentCreature.ComponentLocomotion.LastTurnOrder.X) + m_headingOffset, 0f - MathUtils.DegToRad(80f), MathUtils.DegToRad(80f));
				float y = Math.Clamp(MathUtils.Lerp(-0.3f, 0.3f, SimplexNoise.Noise((0.96f * num2) - 200f)) + m_componentCreature.ComponentLocomotion.LookAngles.Y, 0f - MathUtils.DegToRad(45f), MathUtils.DegToRad(45f));
				float num3 = 0f;
				float y2 = 0f;
				float x2 = 0f;
				float y3 = 0f;
				float num4 = 0f;
				float num5 = 0f;
				float num6 = 0f;
				float num7 = 0f;
				if (componentMount != null)
				{
					if (componentMount.Entity.ValuesDictionary.DatabaseObject.Name == "Boat")
					{
						position.Y -= 0.2f;
						vector.X += (float)Math.PI;
						num4 = 0.4f;
						num6 = 0.4f;
						num5 = 0.2f;
						num7 = -0.2f;
						num3 = 1.1f;
						x2 = 1.1f;
						y2 = 0.2f;
						y3 = -0.2f;
					}
					else
					{
						num4 = 0.5f;
						num6 = 0.5f;
						num5 = 0.15f;
						num7 = -0.15f;
						y2 = 0.55f;
						y3 = -0.55f;
					}
				}
				else if (m_componentCreature.ComponentLocomotion.IsCreativeFlyEnabled)
				{
					float num8 = m_componentCreature.ComponentLocomotion.LastWalkOrder.HasValue ? MathUtils.Min(0.03f * m_componentCreature.ComponentBody.Velocity.XZ.LengthSquared(), 0.5f) : 0f;
					num3 = -0.1f - num8;
					x2 = num3;
					y2 = MathUtils.Lerp(0f, 0.25f, SimplexNoise.Noise((1.07f * num2) + 400f));
					y3 = 0f - MathUtils.Lerp(0f, 0.25f, SimplexNoise.Noise((0.93f * num2) + 500f));
				}
				else if (MovementAnimationPhase != 0f)
				{
					num4 = -0.5f * num;
					num6 = 0.5f * num;
					num3 = m_walkLegsAngle * num;
					x2 = 0f - num3;
				}
				float num9 = 0f;
				if (m_componentMiner != null)
				{
					float num10 = MathF.Sin(MathF.Sqrt(m_componentMiner.PokingPhase) * (float)Math.PI);
					num9 = (m_componentMiner.ActiveBlockValue == 0) ? (1f * num10) : (0.3f + (1f * num10));
				}
				float num11 = (m_punchPhase != 0f) ? ((0f - MathUtils.DegToRad(90f)) * MathF.Sin((float)Math.PI * 2f * MathUtils.Sigmoid(m_punchPhase, 4f))) : 0f;
				float num12 = ((m_punchCounter & 1) == 0) ? num11 : 0f;
				float num13 = ((m_punchCounter & 1) != 0) ? num11 : 0f;
				float num14 = 0f;
				float num15 = 0f;
				float num16 = 0f;
				float num17 = 0f;
				if (m_rowLeft || m_rowRight)
				{
					float num18 = 0.6f * (float)Math.Sin(6.91150426864624 * m_subsystemTime.GameTime);
					float num19 = 0.2f + (0.2f * (float)Math.Cos(6.91150426864624 * (m_subsystemTime.GameTime + 0.5)));
					if (m_rowLeft)
					{
						num14 = num18;
						num15 = num19;
					}
					if (m_rowRight)
					{
						num16 = num18;
						num17 = 0f - num19;
					}
				}
				float num20 = 0f;
				float num21 = 0f;
				float num22 = 0f;
				float num23 = 0f;
				if (m_aimHandAngle != 0f)
				{
					num20 = 1.5f;
					num21 = -0.7f;
					num22 = m_aimHandAngle * 1f;
					num23 = 0f;
				}
				float num24 = (!m_componentCreature.ComponentLocomotion.IsCreativeFlyEnabled) ? 1 : 4;
				num4 += MathUtils.Lerp(-0.1f, 0.1f, SimplexNoise.Noise(num2)) + num12 + num14 + num20;
				num5 += MathUtils.Lerp(0f, num24 * 0.15f, SimplexNoise.Noise((1.1f * num2) + 100f)) + num15 + num21;
				num6 += num9 + MathUtils.Lerp(-0.1f, 0.1f, SimplexNoise.Noise((0.9f * num2) + 200f)) + num13 + num16 + num22;
				num7 += 0f - MathUtils.Lerp(0f, num24 * 0.15f, SimplexNoise.Noise((1.05f * num2) + 300f)) + num17 + num23;
				float s = MathUtils.Min(12f * m_subsystemTime.GameTimeDelta, 1f);
				m_headAngles += s * (new Vector2(x, y) - m_headAngles);
				m_handAngles1 += s * (new Vector2(num4, num5) - m_handAngles1);
				m_handAngles2 += s * (new Vector2(num6, num7) - m_handAngles2);
				m_legAngles1 += s * (new Vector2(num3, y2) - m_legAngles1);
				m_legAngles2 += s * (new Vector2(x2, y3) - m_legAngles2);
				if (m_componentCreature.ComponentBody.CrouchFactor == 1)
				{
					m_legAngles1 *= 0.5f;
					m_legAngles2 *= 0.5f;
				}
				float f = MathUtils.Sigmoid(m_componentCreature.ComponentBody.CrouchFactor, 4f);
				Vector3 position2 = new(0f, MathUtils.Lerp(0f, 4f, f), MathUtils.Lerp(0f, -3.3f, f));
				Vector3 position3 = new(position.X, position.Y - MathUtils.Lerp(0f, 0.7f, f), position.Z);
				Vector3 position4 = new(0f, MathUtils.Lerp(0f, 7f, f), MathUtils.Lerp(0f, 28f, f));
				Vector3 scale = new(1f, 1f, MathUtils.Lerp(1f, 0.5f, f));
				SetBoneTransform(m_bodyBone.Index, Matrix.CreateRotationY(vector.X) * Matrix.CreateTranslation(position3));
				SetBoneTransform(m_headBone.Index, Matrix.CreateRotationX(m_headAngles.Y) * Matrix.CreateRotationZ(0f - m_headAngles.X));
				SetBoneTransform(m_hand1Bone.Index, Matrix.CreateRotationY(m_handAngles1.Y) * Matrix.CreateRotationX(m_handAngles1.X));
				SetBoneTransform(m_hand2Bone.Index, Matrix.CreateRotationY(m_handAngles2.Y) * Matrix.CreateRotationX(m_handAngles2.X));
				SetBoneTransform(m_leg1Bone.Index, Matrix.CreateRotationY(m_legAngles1.Y) * Matrix.CreateRotationX(m_legAngles1.X) * Matrix.CreateTranslation(position4) * Matrix.CreateScale(scale));
				SetBoneTransform(m_leg2Bone.Index, Matrix.CreateRotationY(m_legAngles2.Y) * Matrix.CreateRotationX(m_legAngles2.X) * Matrix.CreateTranslation(position4) * Matrix.CreateScale(scale));
			}
			else
			{
				float num25 = MathUtils.Max(DeathPhase, m_lieDownFactorModel);
				float num26 = 1f - num25;
				Vector3 position2 = position + (num25 * 0.5f * m_componentCreature.ComponentBody.BoxSize.Y * Vector3.Normalize(m_componentCreature.ComponentBody.Matrix.Forward * new Vector3(1f, 0f, 1f))) + (num25 * Vector3.UnitY * m_componentCreature.ComponentBody.BoxSize.Z * 0.1f);
				SetBoneTransform(m_bodyBone.Index, Matrix.CreateFromYawPitchRoll(vector.X, (float)Math.PI / 2f * num25, 0f) * Matrix.CreateTranslation(position2));
				SetBoneTransform(m_headBone.Index, Matrix.Identity);
				SetBoneTransform(m_hand1Bone.Index, Matrix.CreateRotationY(m_handAngles1.Y * num26) * Matrix.CreateRotationX(m_handAngles1.X * num26));
				SetBoneTransform(m_hand2Bone.Index, Matrix.CreateRotationY(m_handAngles2.Y * num26) * Matrix.CreateRotationX(m_handAngles2.X * num26));
				SetBoneTransform(m_leg1Bone.Index, Matrix.CreateRotationY(m_legAngles1.Y * num26) * Matrix.CreateRotationX(m_legAngles1.X * num26));
				SetBoneTransform(m_leg2Bone.Index, Matrix.CreateRotationY(m_legAngles2.Y * num26) * Matrix.CreateRotationX(m_legAngles2.X * num26));
			}
		}

		public override void DrawExtras(Camera camera)
		{
			if (m_componentCreature.ComponentHealth.Health > 0f && m_componentMiner != null && m_componentMiner.ActiveBlockValue != 0)
			{
				int num = Terrain.ExtractContents(m_componentMiner.ActiveBlockValue);
				Block block = BlocksManager.Blocks[num];
				Matrix m = AbsoluteBoneTransformsForCamera[m_hand2Bone.Index];
				m *= camera.InvertedViewMatrix;
				m.Right = Vector3.Normalize(m.Right);
				m.Up = Vector3.Normalize(m.Up);
				m.Forward = Vector3.Normalize(m.Forward);
				Vector3 InhandRotation = block.GetInHandRotation(m_componentMiner.ActiveBlockValue);
				Matrix matrix = Matrix.CreateRotationY(MathUtils.DegToRad(InhandRotation.Y) + m_inHandItemRotation.Y) * Matrix.CreateRotationZ(MathUtils.DegToRad(InhandRotation.Z) + m_inHandItemRotation.Z) * Matrix.CreateRotationX(MathUtils.DegToRad(InhandRotation.X) + m_inHandItemRotation.X) * Matrix.CreateTranslation(block.GetInHandOffset(m_componentMiner.ActiveBlockValue) + m_inHandItemOffset) * Matrix.CreateTranslation(new Vector3(0.05f, 0.05f, -0.56f) * (m_componentCreature.ComponentBody.BoxSize.Y / 1.77f)) * m;
				int x = Terrain.ToCell(matrix.Translation.X);
				int y = Terrain.ToCell(matrix.Translation.Y);
				int z = Terrain.ToCell(matrix.Translation.Z);
				m_drawBlockEnvironmentData.DrawBlockMode = DrawBlockMode.ThirdPerson;
				m_drawBlockEnvironmentData.InWorldMatrix = matrix;
				m_drawBlockEnvironmentData.Humidity = m_subsystemTerrain.Terrain.GetSeasonalHumidity(x, z);
				m_drawBlockEnvironmentData.Temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(x, z) + SubsystemWeather.GetTemperatureAdjustmentAtHeight(y);
				m_drawBlockEnvironmentData.Light = m_subsystemTerrain.Terrain.GetCellLight(x, y, z);
				m_drawBlockEnvironmentData.BillboardDirection = -Vector3.UnitZ;
				m_drawBlockEnvironmentData.SubsystemTerrain = m_subsystemTerrain;
				m_drawBlockEnvironmentData.Owner = m_entity;
				Matrix matrix2 = matrix * camera.ViewMatrix;
				block.DrawBlock(m_subsystemModelsRenderer.PrimitivesRenderer, m_componentMiner.ActiveBlockValue, Color.White, block.GetInHandScale(m_componentMiner.ActiveBlockValue), ref matrix2, m_drawBlockEnvironmentData);
			}

			base.DrawExtras(camera);
		}

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			base.Load(valuesDictionary, idToEntityMap);
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemModelsRenderer = Project.FindSubsystem<SubsystemModelsRenderer>(throwOnError: true);
			m_subsystemNoise = Project.FindSubsystem<SubsystemNoise>(throwOnError: true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_componentMiner = Entity.FindComponent<ComponentMiner>();
			m_componentRider = Entity.FindComponent<ComponentRider>();
			m_componentSleep = Entity.FindComponent<ComponentSleep>();
			m_componentPlayer = Entity.FindComponent<ComponentPlayer>();
			m_walkAnimationSpeed = valuesDictionary.GetValue<float>("WalkAnimationSpeed");
			m_walkBobHeight = valuesDictionary.GetValue<float>("WalkBobHeight");
			m_walkLegsAngle = valuesDictionary.GetValue<float>("WalkLegsAngle");
		}

		public override void SetModel(Model model)
		{
			base.SetModel(model);
			if (IsSet) return;
			if (Model != null)
			{
				m_bodyBone = Model.FindBone("Body");
				m_headBone = Model.FindBone("Head");
				m_leg1Bone = Model.FindBone("Leg1");
				m_leg2Bone = Model.FindBone("Leg2");
				m_hand1Bone = Model.FindBone("Hand1");
				m_hand2Bone = Model.FindBone("Hand2");
			}
			else
			{
				m_bodyBone = null;
				m_headBone = null;
				m_leg1Bone = null;
				m_leg2Bone = null;
				m_hand1Bone = null;
				m_hand2Bone = null;
			}
		}

		public override Vector3 CalculateEyePosition()
		{
			float f = MathUtils.Sigmoid(m_lieDownFactorEye, 1f);
			float num = MathUtils.Sigmoid(m_componentCreature.ComponentBody.CrouchFactor, 4f);
			float num2 = 0.875f * m_componentCreature.ComponentBody.BoxSize.Y;
			float num3 = MathUtils.Lerp(MathUtils.Lerp(num2, 0.45f * num2, num), 0.2f * num2, f);
			Matrix matrix = m_componentCreature.ComponentBody.Matrix;
			return m_componentCreature.ComponentBody.Position + (matrix.Up * (num3 + (2f * Bob))) + (matrix.Forward * -0.2f * num);
		}

		public override Quaternion CalculateEyeRotation()
		{
			float num = 0f;
			if (m_lieDownFactorEye != 0f)
			{
				num += MathUtils.DegToRad(80f) * MathUtils.Sigmoid(MathUtils.Max(m_lieDownFactorEye - 0.2f, 0f) / 0.8f, 4f);
			}
			return m_componentCreature.ComponentBody.Rotation * Quaternion.CreateFromYawPitchRoll(0f - m_componentCreature.ComponentLocomotion.LookAngles.X, m_componentCreature.ComponentLocomotion.LookAngles.Y, num);
		}
	}
}
using Engine;
using GameEntitySystem;

namespace Game
{
	public class DrawBlockEnvironmentData
	{
		public DrawBlockMode DrawBlockMode;

		public SubsystemTerrain SubsystemTerrain;

		public Matrix InWorldMatrix;

		public Matrix? ViewProjectionMatrix;

		public Vector3? BillboardDirection;

		public int Humidity;

		public int Temperature;

		public int Light;

		public Entity Owner;	//在绘制的时候，可以读取该方块的拥有者。在渲染InventorySlotWidget, ComponentFirstPersonModel, ComponentHumanModel中用到

		public float? EnvironmentTemperature;

		public DrawBlockEnvironmentData()
		{
			InWorldMatrix = Matrix.Identity;
			Humidity = 15;
			Temperature = 8;
			Light = 15;
		}
	}
}

using Engine;
using Engine.Graphics;
using GameEntitySystem;
using System;
using System.Collections.Generic;
using System.Globalization;
using TemplatesDatabase;
namespace Game
{
	public class SubsystemSky : Subsystem, IDrawable, IUpdateable
	{
		public struct SkyVertex
		{
			public Vector3 Position;

			public Color Color;
		}

		public class SkyDome : IDisposable
		{
			public const int VerticesCountX = 16;

			public const int VerticesCountY = 8;

			public float? LastUpdateTimeOfDay;

			public float? LastUpdatePrecipitationIntensity;

			public int? LastUpdateTemperature;

			public float? LastUpdateFogDensity;

			public float LastUpdateLightningStrikeBrightness;

			public SkyVertex[] Vertices = new SkyVertex[128];

			public ushort[] Indices = new ushort[714];

			public VertexBuffer VertexBuffer;

			public IndexBuffer IndexBuffer;

			public void Dispose()
			{
				Utilities.Dispose(ref VertexBuffer);
				Utilities.Dispose(ref IndexBuffer);
			}
		}

		public struct StarVertex
		{
			public Vector3 Position;

			public Vector2 TextureCoordinate;

			public Color Color;
		}

		public SubsystemTimeOfDay m_subsystemTimeOfDay;

		public SubsystemSeasons m_subsystemSeasons;

		public SubsystemTime m_subsystemTime;

		public SubsystemGameInfo m_subsystemGameInfo;

		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemWeather m_subsystemWeather;

		public SubsystemAudio m_subsystemAudio;

		public SubsystemBodies m_subsystemBodies;

		public SubsystemParticles m_subsystemParticles;

		public SubsystemFluidBlockBehavior m_subsystemFluidBlockBehavior;

		public PrimitivesRenderer2D m_primitivesRenderer2d = new();

		public PrimitivesRenderer3D m_primitivesRenderer3d = new();

		public Random m_random = new();

		public Random m_fogSeedRandom = new();

		public Color m_viewFogColor;

		public float m_viewFogBottom;

		public float m_viewFogTop;

		public float m_viewHazeStart;

		public float m_viewHazeDensity;

		public float m_viewFogDensity;

		public bool m_viewIsSkyVisible;

		public Texture2D m_sunTexture;

		public Texture2D m_glowTexture;

		public Texture2D m_cloudsTexture;

		public Texture2D[] m_moonTextures = new Texture2D[8];

		public static UnlitShader m_shaderFlat = new(useVertexColor: true, useTexture: false, useAdditiveColor: true, useAlphaThreshold: false);

		public static UnlitShader m_shaderTextured = new(useVertexColor: true, useTexture: true, useAdditiveColor: false, useAlphaThreshold: false);

		public VertexDeclaration m_skyVertexDeclaration = new(new VertexElement(0, VertexElementFormat.Vector3, VertexElementSemantic.Position), new VertexElement(12, VertexElementFormat.NormalizedByte4, VertexElementSemantic.Color));

		public Dictionary<GameWidget, SkyDome> m_skyDomes = [];

		public VertexBuffer m_starsVertexBuffer;

		public IndexBuffer m_starsIndexBuffer;

		public VertexDeclaration m_starsVertexDeclaration = new(new VertexElement(0, VertexElementFormat.Vector3, VertexElementSemantic.Position), new VertexElement(12, VertexElementFormat.Vector2, VertexElementSemantic.TextureCoordinate), new VertexElement(20, VertexElementFormat.NormalizedByte4, VertexElementSemantic.Color));

		public const int m_starsCount = 250;

		public Vector3? m_lightningStrikePosition;

		public float m_lightningStrikeBrightness;

		public double m_lastLightningStrikeTime;

		public bool DrawSkyEnabled = true;

		public bool DrawCloudsWireframe;

		public bool FogEnabled = true;

		public int[] m_drawOrders = new int[3]
		{
			-100,
			5,
			105
		};

		public float[] m_cloudsLayerRadii = new float[4]
		{
			0f,
			0.8f,
			0.95f,
			1f
		};

		public Color[] m_cloudsLayerColors = new Color[5];

		public static int[] m_lightValuesMoonless = new int[6]
		{
			0,
			3,
			6,
			9,
			12,
			15
		};

		public static int[] m_lightValuesNormal = new int[6]
		{
			3,
			5,
			8,
			10,
			13,
			15
		};

		public float SkyLightIntensity
		{
			get;
			set;
		}

		public int MoonPhase
		{
			get;
			set;
		}

		public int SkyLightValue
		{
			get;
			set;
		}

		public float VisibilityRange
		{
			get;
			set;
		}

		public float VisibilityRangeYMultiplier
		{
			get;
			set;
		}

		public float ViewUnderWaterDepth
		{
			get;
			set;
		}

		public float ViewUnderMagmaDepth
		{
			get;
			set;
		}

		public Color ViewFogColor => m_viewFogColor;

		public float ViewFogBottom => m_viewFogBottom;

		public float ViewFogTop => m_viewFogTop;

		public float ViewHazeStart => m_viewHazeStart;

		public float ViewHazeDensity => m_viewHazeDensity;

		public float ViewFogDensity => m_viewFogDensity;

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public int[] DrawOrders => m_drawOrders;

		public SkyPrimitiveRender m_primitiveRender;

		public static SkyShader Shader;

		public static SkyShader ShaderAlphaTest;

		public static bool DrawGalaxyEnabled = true;

		public void MakeLightningStrike(Vector3 targetPosition, bool manual)
        {
            float explosionPressure = (m_random.Float(0f, 1f) < 0.2f) ? 39 : 19;
			bool strike = (m_subsystemTime.GameTime - m_lastLightningStrikeTime > 1.0);
            bool setBodyOnFire = true;
            ModsManager.HookAction("OnLightningStrike", loader =>
			{
				loader.OnLightningStrike(this, ref targetPosition, ref strike, ref explosionPressure, ref setBodyOnFire);
				return false;
			});
			if (m_lightningStrikePosition.HasValue || !strike)
			{
				return;
            }
            m_lastLightningStrikeTime = m_subsystemTime.GameTime;
			m_lightningStrikePosition = targetPosition;
			m_lightningStrikeBrightness = 1f;
			float num = float.MaxValue;
			foreach (Vector3 listenerPosition in m_subsystemAudio.ListenerPositions)
			{
				float num2 = Vector2.Distance(new Vector2(listenerPosition.X, listenerPosition.Z), new Vector2(targetPosition.X, targetPosition.Z));
				if (num2 < num)
				{
					num = num2;
				}
			}
			float delay = m_subsystemAudio.CalculateDelay(num);
			if (num < 40f)
			{
				m_subsystemAudio.PlayRandomSound("Audio/ThunderNear", 1f, m_random.Float(-0.2f, 0.2f), 0f, delay);
			}
			else if (num < 200f)
			{
				m_subsystemAudio.PlayRandomSound("Audio/ThunderFar", 0.8f, m_random.Float(-0.2f, 0.2f), 0f, delay);
			}
			if (m_subsystemGameInfo.WorldSettings.EnvironmentBehaviorMode != 0)
			{
				return;
			}
			DynamicArray<ComponentBody> dynamicArray = [];
			m_subsystemBodies.FindBodiesAroundPoint(new Vector2(targetPosition.X, targetPosition.Z), 4f, dynamicArray);
			for (int i = 0; i < dynamicArray.Count; i++)
			{
				ComponentBody componentBody = dynamicArray.Array[i];
				if (setBodyOnFire && componentBody.Position.Y > targetPosition.Y - 1.5f && Vector2.Distance(new Vector2(componentBody.Position.X, componentBody.Position.Z), new Vector2(targetPosition.X, targetPosition.Z)) < 4f)
				{
					componentBody.Entity.FindComponent<ComponentOnFire>()?.SetOnFire(null, m_random.Float(12f, 15f));
				}
				ComponentCreature componentCreature = componentBody.Entity.FindComponent<ComponentCreature>();
				if (componentCreature != null && componentCreature.PlayerStats != null)
				{
					componentCreature.PlayerStats.StruckByLightning++;
				}
			}
			bool flag = true;
			int num3 = Terrain.ToCell(targetPosition.X);
			int num4 = Terrain.ToCell(targetPosition.Y);
			int num5 = Terrain.ToCell(targetPosition.Z);
			if (!manual)
			{
				for (int j = -1; j <= 1; j++)
				{
					for (int k = -1; k <= 1; k++)
					{
						for (int l = -1; l <= 1; l++)
						{
							if (BlocksManager.Blocks[m_subsystemTerrain.Terrain.GetCellContents(num3 + j, num4 + k, num5 + l)] is LeavesBlock)
							{
								flag = false;
							}
						}
					}
				}
			}
			if (flag)
			{
				float pressure = (m_random.Bool(0.2f) ? 39 : 19);
				base.Project.FindSubsystem<SubsystemExplosions>(throwOnError: true).AddExplosion(num3, num4 + 1, num5, pressure, isIncendiary: false, noExplosionSound: true);
			}
			int cellValue = m_subsystemTerrain.Terrain.GetCellValue(num3, num4, num5);
			int num6 = Terrain.ExtractContents(cellValue);
			if (num6 != 0)
			{
				Block block = BlocksManager.Blocks[num6];
				m_subsystemParticles.AddParticleSystem(block.CreateDebrisParticleSystem(m_subsystemTerrain, new Vector3((float)num3 + 0.5f, (float)num4 + 1.5f, (float)num5 + 0.5f), cellValue, 2.5f));
			}
		}

		public delegate float CalculateFogDelegate(Vector3 viewPosition, Vector3 position);
		public CalculateFogDelegate CalculateFog { get; set; }

		public delegate float CalculateFogNoHazeDelegate(Vector3 viewPosition, Vector3 position);
		public CalculateFogNoHazeDelegate CalculateFogNoHaze { get; set; }

		public void Update(float dt)
		{
			UpdateMoonPhase();
			UpdateLightAndViewParameters();
		}

		public void Draw(Camera camera, int drawOrder)
		{
			if (drawOrder == m_drawOrders[0])
			{
				ViewUnderWaterDepth = 0f;
				ViewUnderMagmaDepth = 0f;
				Vector3 viewPosition = camera.ViewPosition;
				int x = Terrain.ToCell(viewPosition.X);
				int y = Terrain.ToCell(viewPosition.Y);
				int z = Terrain.ToCell(viewPosition.Z);
				FluidBlock surfaceFluidBlock;
				float? surfaceHeight = m_subsystemFluidBlockBehavior.GetSurfaceHeight(x, y, z, out surfaceFluidBlock);
				if (surfaceHeight.HasValue)
				{
					if (surfaceFluidBlock is WaterBlock)
					{
						ViewUnderWaterDepth = surfaceHeight.Value + 0.1f - viewPosition.Y;
					}
					else if (surfaceFluidBlock is MagmaBlock)
					{
						ViewUnderMagmaDepth = surfaceHeight.Value + 1f - viewPosition.Y;
					}
				}
				if (ViewUnderWaterDepth > 0f)
				{
					int seasonalHumidity = m_subsystemTerrain.Terrain.GetSeasonalHumidity(x, z);
					int temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(x, z) + SubsystemWeather.GetTemperatureAdjustmentAtHeight(y);
					Color c = BlockColorsMap.Water.Lookup(temperature, seasonalHumidity);
					float num = MathUtils.Lerp(1f, 0.5f, (float)seasonalHumidity / 15f);
					float num2 = MathUtils.Lerp(1f, 0.2f, MathUtils.Saturate(0.075f * (ViewUnderWaterDepth - 2f)));
					float num3 = MathUtils.Lerp(0.33f, 1f, SkyLightIntensity);
					m_viewHazeStart = 0f;
					m_viewHazeDensity = MathUtils.Lerp(0.25f, 0.1f, num * num2 * num3);
					m_viewFogDensity = 0f;
					m_viewFogBottom = 0f;
					m_viewFogTop = 1f;
					m_viewFogColor = Color.MultiplyColorOnly(c, 0.66f * num2 * num3);//在水中的视图雾颜色
					VisibilityRangeYMultiplier = 1f;
					m_viewIsSkyVisible = false;
				}
				else if (ViewUnderMagmaDepth > 0f)
				{
					m_viewHazeStart = 0f;
					m_viewHazeDensity = 10f;
					m_viewFogDensity = 0f;
					m_viewFogBottom = 0f;
					m_viewFogTop = 1f;
					m_viewFogColor = new Color(255, 80, 0);//在岩浆中的视图雾颜色
					VisibilityRangeYMultiplier = 1f;
					m_viewIsSkyVisible = false;
				}
				else
				{
					m_fogSeedRandom.Seed(m_subsystemWeather.FogSeed);
					float num4 = (m_fogSeedRandom.Bool(0.66f) ? m_fogSeedRandom.Float(62f, 82f) : m_fogSeedRandom.Float(62f, 180f));
					float x2 = Math.Clamp(num4 + m_fogSeedRandom.Float(-20f, 20f), 62f, 180f);
					float num5 = (m_fogSeedRandom.Bool(0.66f) ? m_fogSeedRandom.Float(12f, 22f) : m_fogSeedRandom.Float(12f, 80f));
					m_viewFogBottom = MathUtils.Lerp(num4, x2, m_subsystemWeather.FogProgress);
					m_viewFogTop = m_viewFogBottom + num5;
					m_viewFogDensity = MathF.Pow(m_subsystemWeather.FogIntensity, 2f) * m_fogSeedRandom.Float(0.04f, 0.1f);
					float num6 = 256f;
					float num7 = 128f;
					int seasonalTemperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(Terrain.ToCell(viewPosition.X), Terrain.ToCell(viewPosition.Z));
					float f = CalculateHazeFactor();
					float num8 = MathUtils.Lerp(0.5f, 0f, f);
					float num9 = MathUtils.Lerp(1f, 0.8f, f);
					m_viewHazeStart = VisibilityRange * num8;
					m_viewHazeDensity = 1f / ((num9 - num8) * VisibilityRange);
					Color color = CalculateSkyColor(new Vector3(1f, 0f, 0f), seasonalTemperature);
					Color color2 = CalculateSkyColor(new Vector3(0f, 0f, 1f), seasonalTemperature);
					Color color3 = CalculateSkyColor(new Vector3(-1f, 0f, 0f), seasonalTemperature);
					Color color4 = CalculateSkyColor(new Vector3(0f, 0f, -1f), seasonalTemperature);
					Color c2 = 0.25f * color + 0.25f * color2 + 0.25f * color3 + 0.25f * color4;
					Color c3 = CalculateSkyColor(new Vector3(camera.ViewDirection.X, 0f, camera.ViewDirection.Z), seasonalTemperature);
					//在正常情况下（空气中）视图雾
					m_viewFogColor = Color.Lerp(c3, c2, CalculateSkyFog(camera.ViewPosition));
					VisibilityRangeYMultiplier = MathUtils.Lerp(VisibilityRange / num6, VisibilityRange / num7, MathF.Pow(m_subsystemWeather.PrecipitationIntensity, 4f));
					m_viewIsSkyVisible = true;
				}
				if (!FogEnabled)
				{
					m_viewHazeDensity = 0f;
					m_viewFogDensity = 0f;
				}
				if (!DrawSkyEnabled || !m_viewIsSkyVisible || SettingsManager.SkyRenderingMode == SkyRenderingMode.Disabled)
				{
					FlatBatch2D flatBatch2D = m_primitivesRenderer2d.FlatBatch(-1, DepthStencilState.None, RasterizerState.CullNoneScissor, BlendState.Opaque);
					int count = flatBatch2D.TriangleVertices.Count;
					ModsManager.HookAction("ViewFogColor", modLoader =>
					{
						modLoader.ViewFogColor(ViewUnderWaterDepth, ViewUnderMagmaDepth, ref m_viewFogColor);
						return false;
					});
					flatBatch2D.QueueQuad(Vector2.Zero, camera.ViewportSize, 0f, m_viewFogColor);
					flatBatch2D.TransformTriangles(camera.ViewportMatrix, count);
					m_primitivesRenderer2d.Flush();
				}
			}
			else if (drawOrder == m_drawOrders[1])
			{
				if (DrawSkyEnabled && m_viewIsSkyVisible && SettingsManager.SkyRenderingMode != SkyRenderingMode.Disabled)
				{
					DrawSkydome(camera);
					if (DrawGalaxyEnabled)
					{
						DrawStars(camera);
						DrawSunAndMoon(camera);
					}
					DrawClouds(camera);
					ModsManager.HookAction("SkyDrawExtra", loader => { loader.SkyDrawExtra(this, camera); return false; });
					if (Shader != null && ShaderAlphaTest != null)
					{
						if (m_primitiveRender.Shader == null && m_primitiveRender.ShaderAlphaTest == null)
						{
							m_primitiveRender.Shader = Shader;
							m_primitiveRender.ShaderAlphaTest = ShaderAlphaTest;
							m_primitiveRender.Camera = camera;
						}
						m_primitiveRender.Flush(m_primitivesRenderer3d, camera.ViewProjectionMatrix, true, int.MaxValue);
					}
					else
					{
						m_primitivesRenderer3d.Flush(camera.ViewProjectionMatrix);
					}
					return;
				}
			}
			else
			{
				DrawLightning(camera);
				m_primitivesRenderer3d.Flush(camera.ViewProjectionMatrix);
			}
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemTimeOfDay = base.Project.FindSubsystem<SubsystemTimeOfDay>(throwOnError: true);
			m_subsystemSeasons = base.Project.FindSubsystem<SubsystemSeasons>(throwOnError: true);
			m_subsystemTime = base.Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemGameInfo = base.Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_subsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			m_subsystemWeather = base.Project.FindSubsystem<SubsystemWeather>(throwOnError: true);
			m_subsystemAudio = base.Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_subsystemBodies = base.Project.FindSubsystem<SubsystemBodies>(throwOnError: true);
			m_subsystemParticles = base.Project.FindSubsystem<SubsystemParticles>(throwOnError: true);
			m_subsystemFluidBlockBehavior = base.Project.FindSubsystem<SubsystemFluidBlockBehavior>(throwOnError: true);
			m_sunTexture = ContentManager.Get<Texture2D>("Textures/Sun");
			m_glowTexture = ContentManager.Get<Texture2D>("Textures/SkyGlow");
			m_cloudsTexture = ContentManager.Get<Texture2D>("Textures/Clouds");
			m_primitiveRender = new SkyPrimitiveRender();
			for (int i = 0; i < 8; i++)
			{
				m_moonTextures[i] = ContentManager.Get<Texture2D>("Textures/Moon" + (i + 1).ToString(CultureInfo.InvariantCulture));
			}
			InitializeCalculation();
			UpdateMoonPhase();
			UpdateLightAndViewParameters();
			Display.DeviceReset += Display_DeviceReset;
		}

		public virtual void InitializeCalculation()
		{
			CalculateFog = CalculateFogSurvivalcraft;
			CalculateFogNoHaze = CalculateFogNoHazeSurvivalcraft;
			CalculateLightIntensity = CalculateLightIntensitySurvivalcraft;
			CalculateSeasonAngle = CalculateSeasonAngleSurvivalcraft;
			CalculateHazeFactor = CalculateHazeFactorSurvivalcraft;
			CalculateSkyColor = CalculateSkyColorSurvivalcraft;
			CalculateSkyFog = CalculateSkyFogSurvivalcraft;
			CalculateDawnGlowIntensity = CalculateDawnGlowIntensitySurvivalcraft;
			CalculateDuskGlowIntensity = CalculateDuskGlowIntensitySurvivalcraft;
			CalculateWinterDistance = CalculateWinterDistanceSurvivalcraft;
		}

		public override void Dispose()
		{
			Display.DeviceReset -= Display_DeviceReset;
			Utilities.Dispose(ref m_starsVertexBuffer);
			Utilities.Dispose(ref m_starsIndexBuffer);
			foreach (SkyDome value in m_skyDomes.Values)
			{
				value.Dispose();
			}
			m_skyDomes.Clear();
		}

		public void Display_DeviceReset()
		{
			Utilities.Dispose(ref m_starsVertexBuffer);
			Utilities.Dispose(ref m_starsIndexBuffer);
			foreach (SkyDome value in m_skyDomes.Values)
			{
				value.Dispose();
			}
			m_skyDomes.Clear();
		}

		public void DrawSkydome(Camera camera)
		{
			if (!m_skyDomes.TryGetValue(camera.GameWidget, out SkyDome value))
			{
				value = new SkyDome();
				m_skyDomes.Add(camera.GameWidget, value);
			}
			if (value.VertexBuffer == null || value.IndexBuffer == null)
			{
				Utilities.Dispose(ref value.VertexBuffer);
				Utilities.Dispose(ref value.IndexBuffer);
				value.VertexBuffer = new VertexBuffer(m_skyVertexDeclaration, value.Vertices.Length);
				value.IndexBuffer = new IndexBuffer(IndexFormat.SixteenBits, value.Indices.Length);
				FillSkyIndexBuffer(value);
				value.LastUpdateTimeOfDay = null;
			}
			int x = Terrain.ToCell(camera.ViewPosition.X);
			int z = Terrain.ToCell(camera.ViewPosition.Z);
			float precipitationIntensity = m_subsystemWeather.PrecipitationIntensity;
			float timeOfDay = m_subsystemTimeOfDay.TimeOfDay;
			int seasonalTemperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(x, z);
			bool flag = true;
			if (value.LastUpdateTimeOfDay.HasValue && !(MathF.Abs(timeOfDay - value.LastUpdateTimeOfDay.Value) > 0.0005f) && value.LastUpdatePrecipitationIntensity.HasValue && !(MathF.Abs(precipitationIntensity - value.LastUpdatePrecipitationIntensity.Value) > 0.02f) && ((precipitationIntensity != 0f && precipitationIntensity != 1f) || value.LastUpdatePrecipitationIntensity.Value == precipitationIntensity) && m_lightningStrikeBrightness == value.LastUpdateLightningStrikeBrightness && value.LastUpdateTemperature.HasValue)
			{
				int? lastUpdateTemperature = value.LastUpdateTemperature;
				if (seasonalTemperature == lastUpdateTemperature.GetValueOrDefault() && lastUpdateTemperature.HasValue && value.LastUpdateTemperature.HasValue && !(MathF.Abs(m_viewFogDensity - value.LastUpdateFogDensity.Value) > 0.002f))
				{
					flag = false;
				}
			}
			if (flag)
			{
				value.LastUpdateTimeOfDay = timeOfDay;
				value.LastUpdatePrecipitationIntensity = precipitationIntensity;
				value.LastUpdateLightningStrikeBrightness = m_lightningStrikeBrightness;
				value.LastUpdateTemperature = seasonalTemperature;
				value.LastUpdateFogDensity = m_viewFogDensity;
				FillSkyVertexBuffer(value, timeOfDay, precipitationIntensity, seasonalTemperature);
			}
			Display.DepthStencilState = DepthStencilState.DepthRead;
			Display.RasterizerState = RasterizerState.CullNoneScissor;
			float num = CalculateSkyFog(camera.ViewPosition);
			Display.BlendState = BlendState.Opaque;
			m_shaderFlat.Transforms.World[0] = Matrix.CreateTranslation(camera.ViewPosition) * camera.ViewProjectionMatrix;
			m_shaderFlat.Color = new Vector4(1f - num);
			m_shaderFlat.AdditiveColor = num * new Vector4(ViewFogColor);
			Display.DrawIndexed(PrimitiveType.TriangleList, m_shaderFlat, value.VertexBuffer, value.IndexBuffer, 0, value.IndexBuffer.IndicesCount);
		}

		public void DrawStars(Camera camera)
		{
			float precipitationIntensity = m_subsystemWeather.PrecipitationIntensity;
			float timeOfDay = m_subsystemTimeOfDay.TimeOfDay;
			if (m_starsVertexBuffer == null || m_starsIndexBuffer == null)
			{
				Utilities.Dispose(ref m_starsVertexBuffer);
				Utilities.Dispose(ref m_starsIndexBuffer);
				m_starsVertexBuffer = new VertexBuffer(m_starsVertexDeclaration, 1000);
				m_starsIndexBuffer = new IndexBuffer(IndexFormat.SixteenBits, 1500);
				FillStarsBuffers();
			}
			Display.DepthStencilState = DepthStencilState.DepthRead;
			Display.RasterizerState = RasterizerState.CullNoneScissor;
			float num = MathUtils.Sqr((1f - CalculateLightIntensity(timeOfDay)) * (1f - precipitationIntensity));
			num *= 1f - CalculateSkyFog(camera.ViewPosition);
			if (num > 0.01f)
			{
				Display.BlendState = BlendState.Additive;
				m_shaderTextured.Transforms.World[0] = Matrix.CreateRotationZ(-2f * timeOfDay * (float)Math.PI) * Matrix.CreateRotationX(CalculateSeasonAngle()) * Matrix.CreateTranslation(camera.ViewPosition) * camera.ViewProjectionMatrix;
				m_shaderTextured.Color = new Vector4(1f, 1f, 1f, num);
				m_shaderTextured.Texture = ContentManager.Get<Texture2D>("Textures/Star");
				m_shaderTextured.SamplerState = SamplerState.LinearClamp;
				Display.DrawIndexed(PrimitiveType.TriangleList, m_shaderTextured, m_starsVertexBuffer, m_starsIndexBuffer, 0, m_starsIndexBuffer.IndicesCount);
			}
		}

		public void DrawSunAndMoon(Camera camera)
		{
			float precipitationIntensity = m_subsystemWeather.PrecipitationIntensity;
			float timeOfDay = m_subsystemTimeOfDay.TimeOfDay;
			float f = MathUtils.Max(CalculateDawnGlowIntensity(timeOfDay), CalculateDuskGlowIntensity(timeOfDay));
			float num = (float)Math.PI * 2f * (timeOfDay - m_subsystemTimeOfDay.Midday);
			float angle = num + (float)Math.PI;
			float num2 = MathUtils.Lerp(90f, 160f, f);
			float num3 = MathUtils.Lerp(60f, 80f, f);
			Color color = Color.Lerp(new Color(255, 255, 255), new Color(255, 255, 160), f);
			Color white = Color.White;
			white *= 1f - SkyLightIntensity;
			color *= MathUtils.Lerp(1f, 0f, precipitationIntensity);
			white *= MathUtils.Lerp(1f, 0f, precipitationIntensity);
			Color color2 = color * 0.6f * MathUtils.Lerp(1f, 0f, precipitationIntensity);
			Color color3 = color * 0.2f * MathUtils.Lerp(1f, 0f, precipitationIntensity);
			TexturedBatch3D batch = m_primitivesRenderer3d.TexturedBatch(m_glowTexture, useAlphaTest: false, 0, DepthStencilState.DepthRead, null, BlendState.Additive);
			TexturedBatch3D batch2 = m_primitivesRenderer3d.TexturedBatch(m_sunTexture, useAlphaTest: false, 1, DepthStencilState.DepthRead, null, BlendState.AlphaBlend);
			TexturedBatch3D batch3 = m_primitivesRenderer3d.TexturedBatch(m_moonTextures[MoonPhase], useAlphaTest: false, 1, DepthStencilState.DepthRead, null, BlendState.AlphaBlend);
			QueueCelestialBody(batch, camera.ViewPosition, color2, 900f, 3.5f * num2, num);
			QueueCelestialBody(batch, camera.ViewPosition, color3, 900f, 3.5f * num3, angle);
			QueueCelestialBody(batch2, camera.ViewPosition, color, 900f, num2, num);
			QueueCelestialBody(batch3, camera.ViewPosition, white, 900f, num3, angle);
		}

		public void DrawLightning(Camera camera)
		{
			if (!m_lightningStrikePosition.HasValue)
			{
				return;
			}
			FlatBatch3D flatBatch3D = m_primitivesRenderer3d.FlatBatch(0, DepthStencilState.DepthRead, null, BlendState.Additive);
			Color color0 = (1f - CalculateSkyFog(camera.ViewPosition)) * Color.White;
			Vector3 value = m_lightningStrikePosition.Value;
			Vector3 unitY = Vector3.UnitY;
			Vector3 v = Vector3.Normalize(Vector3.Cross(camera.ViewDirection, unitY));
			Viewport viewport = Display.Viewport;
			float num = Vector4.Transform(new Vector4(value, 1f), camera.ViewProjectionMatrix).W * 2f / ((float)viewport.Width * camera.ProjectionMatrix.M11);
			for (int i = 0; i < (int)(m_lightningStrikeBrightness * 30f); i++)
			{
				float s = m_random.NormalFloat(0f, 1f * num);
				float s2 = m_random.NormalFloat(0f, 1f * num);
				Vector3 v2 = (s * v) + (s2 * unitY);
				float num2 = 260f;
				while (num2 > value.Y)
				{
					uint num3 = MathUtils.Hash((uint)(m_lightningStrikePosition.Value.X + (100f * m_lightningStrikePosition.Value.Z) + (200f * num2)));
					float num4 = MathUtils.Lerp(4f, 10f, (float)(double)(num3 & 0xFF) / 255f);
					float s3 = ((num3 & 1) == 0) ? 1 : (-1);
					float s4 = MathUtils.Lerp(0.05f, 0.2f, (float)(double)((num3 >> 8) & 0xFF) / 255f);
					float num5 = num2;
					float num6 = num5 - (num4 * MathUtils.Lerp(0.45f, 0.55f, (float)(double)((num3 >> 16) & 0xFF) / 255f));
					float num7 = num5 - (num4 * MathUtils.Lerp(0.45f, 0.55f, (float)(double)((num3 >> 24) & 0xFF) / 255f));
					float num8 = num5 - num4;
					Vector3 p = new Vector3(value.X, num5, value.Z) + v2;
					Vector3 vector = new Vector3(value.X, num6, value.Z) + v2 - (num4 * v * s3 * s4);
					Vector3 vector2 = new Vector3(value.X, num7, value.Z) + v2 + (num4 * v * s3 * s4);
					Vector3 p2 = new Vector3(value.X, num8, value.Z) + v2;
					Color color = color0 * 0.2f * MathUtils.Saturate((260f - num5) * 0.2f);
					Color color2 = color0 * 0.2f * MathUtils.Saturate((260f - num6) * 0.2f);
					Color color3 = color0 * 0.2f * MathUtils.Saturate((260f - num7) * 0.2f);
					Color color4 = color0 * 0.2f * MathUtils.Saturate((260f - num8) * 0.2f);
					flatBatch3D.QueueLine(p, vector, color, color2);
					flatBatch3D.QueueLine(vector, vector2, color2, color3);
					flatBatch3D.QueueLine(vector2, p2, color3, color4);
					num2 -= num4;
				}
			}
			float num9 = MathUtils.Lerp(0.3f, 0.75f, (0.5f * (float)Math.Sin(MathUtils.Remainder(1.0 * m_subsystemTime.GameTime, 6.2831854820251465))) + 0.5f);
			m_lightningStrikeBrightness -= m_subsystemTime.GameTimeDelta / num9;
			if (m_lightningStrikeBrightness <= 0f)
			{
				m_lightningStrikePosition = null;
				m_lightningStrikeBrightness = 0f;
			}
		}

		public void DrawClouds(Camera camera)
		{
			if (SettingsManager.SkyRenderingMode == SkyRenderingMode.NoClouds)
			{
				return;
			}
			float f = CalculateHazeFactor();
			float num = MathUtils.Lerp(0.03f, 1f, MathUtils.Sqr(SkyLightIntensity)) * MathUtils.Lerp(1f, 0.2f, f);
			float f2 = CalculateSkyFog(camera.ViewPosition);
			m_cloudsLayerColors[0] = Color.Lerp(Color.White * (num * 0.75f), ViewFogColor, f2);
			m_cloudsLayerColors[1] = Color.Lerp(Color.White * (num * 0.66f), ViewFogColor, f2);
			m_cloudsLayerColors[2] = ViewFogColor;
			m_cloudsLayerColors[3] = Color.Transparent;
			double gameTime = m_subsystemTime.GameTime;
			Vector3 viewPosition = camera.ViewPosition;
			Vector2 v = new((float)MathUtils.Remainder((0.0020000000949949026 * gameTime) - (double)(viewPosition.X / 1900f * 1.75f), 1.0) + (viewPosition.X / 1900f * 1.75f), (float)MathUtils.Remainder((0.0020000000949949026 * gameTime) - (double)(viewPosition.Z / 1900f * 1.75f), 1.0) + (viewPosition.Z / 1900f * 1.75f));
			TexturedBatch3D texturedBatch3D = m_primitivesRenderer3d.TexturedBatch(m_cloudsTexture, useAlphaTest: false, 2, DepthStencilState.DepthRead, null, BlendState.AlphaBlend, SamplerState.LinearWrap);
			DynamicArray<VertexPositionColorTexture> triangleVertices = texturedBatch3D.TriangleVertices;
			DynamicArray<int> triangleIndices = texturedBatch3D.TriangleIndices;
			int count = triangleVertices.Count;
			int count2 = triangleVertices.Count;
			int count3 = triangleIndices.Count;
			triangleVertices.Count += 49;
			triangleIndices.Count += 216;
			for (int i = 0; i < 7; i++)
			{
				for (int j = 0; j < 7; j++)
				{
					int num2 = j - 3;
					int num3 = i - 3;
					int num4 = MathUtils.Max(Math.Abs(num2), Math.Abs(num3));
					float num5 = m_cloudsLayerRadii[num4];
					float num6 = (num4 > 0) ? (num5 / MathF.Sqrt((num2 * num2) + (num3 * num3))) : 0f;
					float num7 = (float)num2 * num6;
					float num8 = (float)num3 * num6;
					float y = MathUtils.Lerp(600f, 60f, num5 * num5);
					Vector3 position = new(viewPosition.X + (num7 * 1900f), y, viewPosition.Z + (num8 * 1900f));
					Vector2 texCoord = (new Vector2(position.X, position.Z) / 1900f * 1.75f) - v;
					Color color = m_cloudsLayerColors[num4];
					texturedBatch3D.TriangleVertices.Array[count2++] = new VertexPositionColorTexture(position, color, texCoord);
					if (j > 0 && i > 0)
					{
						ushort num9 = (ushort)(count + j + (i * 7));
						ushort num10 = (ushort)(count + (j - 1) + (i * 7));
						ushort num11 = (ushort)(count + (j - 1) + ((i - 1) * 7));
						ushort num12 = (ushort)(count + j + ((i - 1) * 7));
						if ((num2 <= 0 && num3 <= 0) || (num2 > 0 && num3 > 0))
						{
							texturedBatch3D.TriangleIndices.Array[count3++] = num9;
							texturedBatch3D.TriangleIndices.Array[count3++] = num10;
							texturedBatch3D.TriangleIndices.Array[count3++] = num11;
							texturedBatch3D.TriangleIndices.Array[count3++] = num11;
							texturedBatch3D.TriangleIndices.Array[count3++] = num12;
							texturedBatch3D.TriangleIndices.Array[count3++] = num9;
						}
						else
						{
							texturedBatch3D.TriangleIndices.Array[count3++] = num9;
							texturedBatch3D.TriangleIndices.Array[count3++] = num10;
							texturedBatch3D.TriangleIndices.Array[count3++] = num12;
							texturedBatch3D.TriangleIndices.Array[count3++] = num10;
							texturedBatch3D.TriangleIndices.Array[count3++] = num11;
							texturedBatch3D.TriangleIndices.Array[count3++] = num12;
						}
					}
				}
			}
			_ = DrawCloudsWireframe;
		}

		public void QueueCelestialBody(TexturedBatch3D batch, Vector3 viewPosition, Color color, float distance, float radius, float angle)
		{
			color *= 1f - CalculateSkyFog(viewPosition);
			if (color.A > 0)
			{
				Matrix m = Matrix.Identity;
				m *= Matrix.CreateTranslation(0f, distance, 0f);
				m *= Matrix.CreateRotationZ(0f - angle);
				m *= Matrix.CreateRotationX(CalculateSeasonAngle());
				m *= Matrix.CreateTranslation(viewPosition);
				Vector3 v = new Vector3(0f - radius, 0f, 0f - radius);
				Vector3 v2 = new Vector3(radius, 0f, 0f - radius);
				Vector3 v3 = new Vector3(radius, 0f, radius);
				Vector3 v4 = new Vector3(0f - radius, 0f, radius);
				Vector3.Transform(ref v, ref m, out v);
				Vector3.Transform(ref v2, ref m, out v2);
				Vector3.Transform(ref v3, ref m, out v3);
				Vector3.Transform(ref v4, ref m, out v4);
				batch.QueueQuad(v, v2, v3, v4, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), new Vector2(0f, 0f), color);
			}
		}

		public void UpdateLightAndViewParameters()
		{
			VisibilityRange = SettingsManager.VisibilityRange;
			SkyLightIntensity = CalculateLightIntensity(m_subsystemTimeOfDay.TimeOfDay);
			if (MoonPhase == 4)
			{
				SkyLightValue = m_lightValuesMoonless[(int)MathF.Round(MathUtils.Lerp(0f, 5f, SkyLightIntensity))];
			}
			else
			{
				SkyLightValue = m_lightValuesNormal[(int)MathF.Round(MathUtils.Lerp(0f, 5f, SkyLightIntensity))];
			}
		}

		public void UpdateMoonPhase()
		{
			MoonPhase = ((int)Math.Floor(m_subsystemTimeOfDay.Day - 0.5 + 5.0) % 8 + 8) % 8;
		}

		public delegate float CalculateLightIntensityDelegate(float timeOfDay);
		public CalculateLightIntensityDelegate CalculateLightIntensity { get; set; }

		public delegate float CalculateSeasonAngleDelegate();
		public CalculateSeasonAngleDelegate CalculateSeasonAngle { get; set; }

		public delegate float CalculateHazeFactorDelegate();
		public CalculateHazeFactorDelegate CalculateHazeFactor { get; set; }

		public delegate Color CalculateSkyColorDelegate(Vector3 direction,int temperature);
		public CalculateSkyColorDelegate CalculateSkyColor { get; set; }

		public delegate float CalculateSkyFogDelegate(Vector3 viewPosition);
		public CalculateSkyFogDelegate CalculateSkyFog { get; set; }

		public float FogIntegral(float y)
		{
			return MathUtils.SmoothStep(ViewFogBottom, ViewFogTop, y) * (ViewFogTop - ViewFogBottom) + ViewFogBottom;
		}

		public void FillSkyVertexBuffer(SkyDome skyDome, float timeOfDay, float precipitationIntensity, int temperature)
		{
			for (int i = 0; i < 8; i++)
			{
				float x = (float)Math.PI / 2f * MathUtils.Sqr((float)i / 7f);
				for (int j = 0; j < 16; j++)
				{
					int num = j + (i * 16);
					float x2 = (float)Math.PI * 2f * (float)j / 16f;
					float num2 = 1800f * MathF.Cos(x);
					skyDome.Vertices[num].Position.X = num2 * MathF.Sin(x2);
					skyDome.Vertices[num].Position.Z = num2 * MathF.Cos(x2);
					skyDome.Vertices[num].Position.Y = (1800f * MathF.Sin(x)) - ((i == 0) ? 450f : 0f);
					skyDome.Vertices[num].Color = CalculateSkyColor(skyDome.Vertices[num].Position, temperature);
				}
			}
			skyDome.VertexBuffer.SetData(skyDome.Vertices, 0, skyDome.Vertices.Length);
		}

		public void FillSkyIndexBuffer(SkyDome skyDome)
		{
			int num = 0;
			for (int i = 0; i < 7; i++)
			{
				for (int j = 0; j < 16; j++)
				{
					int num2 = j;
					int num3 = (j + 1) % 16;
					int num4 = i;
					int num5 = i + 1;
					skyDome.Indices[num++] = (ushort)(num2 + (num4 * 16));
					skyDome.Indices[num++] = (ushort)(num3 + (num4 * 16));
					skyDome.Indices[num++] = (ushort)(num3 + (num5 * 16));
					skyDome.Indices[num++] = (ushort)(num3 + (num5 * 16));
					skyDome.Indices[num++] = (ushort)(num2 + (num5 * 16));
					skyDome.Indices[num++] = (ushort)(num2 + (num4 * 16));
				}
			}
			for (int k = 2; k < 16; k++)
			{
				skyDome.Indices[num++] = 0;
				skyDome.Indices[num++] = (ushort)(k - 1);
				skyDome.Indices[num++] = (ushort)k;
			}
			skyDome.IndexBuffer.SetData(skyDome.Indices, 0, skyDome.Indices.Length);
		}

		public void FillStarsBuffers()
		{
			Random random = new Random(10);
			StarVertex[] array = new StarVertex[1000];
			for (int i = 0; i < 250; i++)
			{
				float x;
				Color c;
				Vector3 v;
				switch (i)
				{
					case 0:
						x = 1.05f;
						c = new Color(1f, 1f, 1f);
						v = new Vector3(0f, 0f, 1f);
						break;
					case 1:
						x = 0.91f;
						c = new Color(1f, 0.8f, 0.6f);
						v = new Vector3(-0.007f, -0.05f, 1f);
						break;
					case 2:
						x = 0.94f;
						c = new Color(1f, 0.8f, 0.7f);
						v = new Vector3(0f, -0.11f, 1f);
						break;
					default:
						x = random.Float(0.7f, 1f);
						c = new Color(random.Float(0.8f, 1f), 0.8f, random.Float(0.8f, 1f));
						do
						{
							v = new Vector3(random.Float(-1f, 1f), random.Float(-1f, 1f), random.Float(-1f, 1f));
						}
						while (v.LengthSquared() > 1f);
						break;
				}
				float num = 7.6500006f * MathF.Pow(x, 3f);
				float s = MathF.Pow(x, 4f);
				c = Color.MultiplyAlphaOnly(c, s);
				v = Vector3.Normalize(v);
				Vector3 v2 = 900f * v;
				Vector3 vector = Vector3.Normalize(Vector3.Cross((v.X > v.Y) ? Vector3.UnitY : Vector3.UnitX, v));
				Vector3 v3 = Vector3.Normalize(Vector3.Cross(vector, v));
				Vector3 position = v2 + (s * (-vector - v3));
				Vector3 position2 = v2 + (s * (vector - v3));
				Vector3 position3 = v2 + (s * (vector + v3));
				Vector3 position4 = v2 + (s * (-vector + v3));
				StarVertex starVertex = array[i * 4] = new StarVertex
				{
					Position = position,
					TextureCoordinate = new Vector2(0f, 0f),
					Color = c
				};
				starVertex = array[(i * 4) + 1] = new StarVertex
				{
					Position = position2,
					TextureCoordinate = new Vector2(1f, 0f),
					Color = c
				};
				starVertex = array[(i * 4) + 2] = new StarVertex
				{
					Position = position3,
					TextureCoordinate = new Vector2(1f, 1f),
					Color = c
				};
				starVertex = array[(i * 4) + 3] = new StarVertex
				{
					Position = position4,
					TextureCoordinate = new Vector2(0f, 1f),
					Color = c
				};
			}
			m_starsVertexBuffer.SetData(array, 0, array.Length);
			ushort[] array2 = new ushort[1500];
			for (int j = 0; j < 250; j++)
			{
				array2[j * 6] = (ushort)(j * 4);
				array2[(j * 6) + 1] = (ushort)((j * 4) + 1);
				array2[(j * 6) + 2] = (ushort)((j * 4) + 2);
				array2[(j * 6) + 3] = (ushort)((j * 4) + 2);
				array2[(j * 6) + 4] = (ushort)((j * 4) + 3);
				array2[(j * 6) + 5] = (ushort)(j * 4);
			}
			m_starsIndexBuffer.SetData(array2, 0, array2.Length);
		}

		public delegate float CalculateDawnGlowIntensityDelegate(float timeOfDay);
		public CalculateDawnGlowIntensityDelegate CalculateDawnGlowIntensity { get; set; }

		public delegate float CalculateDuskGlowIntensityDelegate(float timeOfDay);
		public CalculateDuskGlowIntensityDelegate CalculateDuskGlowIntensity;

		public delegate float CalculateWinterDistanceDelegate();
		public CalculateWinterDistanceDelegate CalculateWinterDistance;

		#region CalculationSurvivalcraft
		public float CalculateFogSurvivalcraft(Vector3 viewPosition,Vector3 position)
		{
			Vector3 vector = viewPosition - position;
			vector.Y *= VisibilityRangeYMultiplier;
			float num = vector.Length();
			float num2 = (FogIntegral(viewPosition.Y) - FogIntegral(position.Y)) / (viewPosition.Y - position.Y);
			float num3 = MathUtils.Saturate(ViewHazeDensity * (num - ViewHazeStart));
			float num4 = num2 * ViewFogDensity * num;
			return MathUtils.Saturate(num3 + num4);
		}
		public float CalculateFogNoHazeSurvivalcraft(Vector3 viewPosition,Vector3 position)
		{
			Vector3 vector = viewPosition - position;
			vector.Y *= VisibilityRangeYMultiplier;
			float num = vector.Length();
			return MathUtils.Saturate((FogIntegral(viewPosition.Y) - FogIntegral(position.Y)) / (viewPosition.Y - position.Y) * ViewFogDensity * num);
		}
		public float CalculateLightIntensitySurvivalcraft(float timeOfDay)
		{
			if(IntervalUtils.IsBetween(timeOfDay,m_subsystemTimeOfDay.NightStart,m_subsystemTimeOfDay.DawnStart))
			{
				return 0f;
			}
			if(IntervalUtils.IsBetween(timeOfDay,m_subsystemTimeOfDay.DawnStart,m_subsystemTimeOfDay.DayStart))
			{
				return IntervalUtils.Interval(m_subsystemTimeOfDay.DawnStart,timeOfDay) / m_subsystemTimeOfDay.DawnInterval;
			}
			if(IntervalUtils.IsBetween(timeOfDay,m_subsystemTimeOfDay.DayStart,m_subsystemTimeOfDay.DuskStart))
			{
				return 1f;
			}
			return 1f - IntervalUtils.Interval(m_subsystemTimeOfDay.DuskStart,timeOfDay) / m_subsystemTimeOfDay.DuskInterval;
		}
		public float CalculateSeasonAngleSurvivalcraft()
		{
			return -0.4f - 0.7f * (0.5f - 0.5f * MathF.Cos((m_subsystemGameInfo.WorldSettings.TimeOfYear - SubsystemSeasons.MidSummer) * 2f * MathF.PI));
		}
		public float CalculateHazeFactorSurvivalcraft()
		{
			return MathUtils.Saturate(m_subsystemWeather.PrecipitationIntensity + 30f * m_viewFogDensity);
		}
		public Color CalculateSkyColorSurvivalcraft(Vector3 direction,int temperature)
		{
			float timeOfDay = m_subsystemTimeOfDay.TimeOfDay;
			float f = CalculateHazeFactor();
			direction = Vector3.Normalize(direction);
			Vector2 vector = Vector2.Normalize(new Vector2(direction.X,direction.Z));
			float num = CalculateLightIntensity(timeOfDay);
			float f2 = MathUtils.Saturate((float)temperature / 15f);
			Vector3 v = new Vector3(0.65f,0.68f,0.7f);
			Vector3 v2 = Vector3.Lerp(new Vector3(0.33f,0.39f,0.46f),new Vector3(0.15f,0.3f,0.56f),f2);
			Vector3 v3 = Vector3.Lerp(new Vector3(0.79f,0.83f,0.88f),new Vector3(0.64f,0.77f,0.91f),f2);
			Vector3 v4 = Vector3.Lerp(v2,v,f) * num;
			Vector3 vector2 = Vector3.Lerp(v3,v,f) * num;
			Vector3 vector3 = new Vector3(1f,0.3f,-0.2f);
			Vector3 vector4 = new Vector3(1f,0.3f,-0.2f);
			if(m_lightningStrikePosition.HasValue)
			{
				v4 = Vector3.Max(new Vector3(m_lightningStrikeBrightness),v4);
			}
			float num2 = MathUtils.Lerp(CalculateDawnGlowIntensity(timeOfDay),0f,f);
			float num3 = MathUtils.Lerp(CalculateDuskGlowIntensity(timeOfDay),0f,f);
			float f3 = MathUtils.Saturate((direction.Y - 0.1f) / 0.4f);
			float num4 = num2 * MathUtils.Sqr(MathUtils.Saturate(0f - vector.X));
			float num5 = num3 * MathUtils.Sqr(MathUtils.Saturate(vector.X));
			Color color = new Color(Vector3.Lerp(vector2 + vector3 * num4 + vector4 * num5,v4,f3));
			ModsManager.HookAction("ChangeSkyColor",loader => {
				color = loader.ChangeSkyColor(color,direction,timeOfDay,temperature);
				return true;
			});
			return color;
		}
		public float CalculateSkyFogSurvivalcraft(Vector3 viewPosition)
		{
			return CalculateFogNoHaze(viewPosition,viewPosition + new Vector3(1000f,150f,0f));
		}
		public float CalculateDawnGlowIntensitySurvivalcraft(float timeOfDay)
		{
			float num = MathUtils.Lerp(0.1f,0.75f,MathUtils.LinearStep(-0.05f,0.15f,CalculateWinterDistance()));
			float middawn = m_subsystemTimeOfDay.Middawn;
			float num2 = 1f * m_subsystemTimeOfDay.DawnInterval;
			return num * MathUtils.Max(1f - IntervalUtils.Distance(timeOfDay,middawn) / num2 * 2f,0f);
		}
		public float CalculateDuskGlowIntensitySurvivalcraft(float timeOfDay)
		{
			float num = MathUtils.Lerp(0.2f,1f,MathUtils.LinearStep(-0.05f,0.15f,CalculateWinterDistance()));
			float middusk = m_subsystemTimeOfDay.Middusk;
			float num2 = 1f * m_subsystemTimeOfDay.DuskInterval;
			return num * MathUtils.Max(1f - IntervalUtils.Distance(timeOfDay,middusk) / num2 * 2f,0f);
		}
		public float CalculateWinterDistanceSurvivalcraft()
		{
			float t = IntervalUtils.Midpoint(SubsystemSeasons.WinterStart,SubsystemSeasons.SpringStart);
			float num = IntervalUtils.Interval(SubsystemSeasons.WinterStart,SubsystemSeasons.SpringStart);
			return IntervalUtils.Distance(m_subsystemGameInfo.WorldSettings.TimeOfYear,t) - 0.5f * num;
		}
		#endregion
	}
}

using Engine;
using GameEntitySystem;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq;
using TemplatesDatabase;

namespace Game
{
	public class ComponentPlayer : ComponentCreature, IUpdateable
	{
		public SubsystemGameInfo m_subsystemGameInfo;

		public SubsystemTime m_subsystemTime;

		public SubsystemAudio m_subsystemAudio;

		public SubsystemPickables m_subsystemPickables;

		public SubsystemTerrain m_subsystemTerrain;

		public bool m_aimHintIssued;

		public static string fName = "ComponentPlayer";

		public double m_lastActionTime;

		public bool m_speedOrderBlocked;

		public Ray3? m_aim;

		public bool m_isAimBlocked;

		public bool m_isDigBlocked;

		public bool m_doAimBlockLook = true;//手机端在执行Aim操作的时候，允许旋转屏幕，比如RYSH的喝水、武器的格挡

		public bool m_allowAddLookOrder = true;

		public double? m_aimStartTime;

		public double AimDuration
		{
			get
			{
				if (m_aimStartTime.HasValue)
					return m_subsystemTime.GameTime - m_aimStartTime.Value;
				return -1;
			}
		}

		public PlayerData PlayerData
		{
			get;
			set;
		}

		public GameWidget GameWidget => PlayerData.GameWidget;

		public ContainerWidget GuiWidget => PlayerData.GameWidget.GuiWidget;

		public ViewWidget ViewWidget => PlayerData.GameWidget.ViewWidget;

		public ComponentGui ComponentGui
		{
			get;
			set;
		}

		public ComponentInput ComponentInput
		{
			get;
			set;
		}

		public ComponentBlockHighlight ComponentBlockHighlight
		{
			get;
			set;
		}

		public ComponentScreenOverlays ComponentScreenOverlays
		{
			get;
			set;
		}

		public ComponentAimingSights ComponentAimingSights
		{
			get;
			set;
		}

		public ComponentMiner ComponentMiner
		{
			get;
			set;
		}

		public ComponentRider ComponentRider
		{
			get;
			set;
		}

		public ComponentSleep ComponentSleep
		{
			get;
			set;
		}

		public ComponentVitalStats ComponentVitalStats
		{
			get;
			set;
		}

		public ComponentSickness ComponentSickness
		{
			get;
			set;
		}

		public ComponentFlu ComponentFlu
		{
			get;
			set;
		}

		public ComponentLevel ComponentLevel
		{
			get;
			set;
		}

		public ComponentClothing ComponentClothing
		{
			get;
			set;
		}

		public ComponentOuterClothingModel ComponentOuterClothingModel
		{
			get;
			set;
		}

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public DragHostWidget m_dragHostWidget;

		public DragHostWidget DragHostWidget
		{
			get
			{
				if (m_dragHostWidget == null)
				{
					m_dragHostWidget = (GameWidget != null) ? GameWidget.Children.Find<DragHostWidget>(throwIfNotFound: false) : null;
				}
				return m_dragHostWidget;
			}
		}

		public virtual void DealWithPlayerInteract(int priorityUse, int priorityPlace, int priorityInteract,
			PlayerInput playerInput, TerrainRaycastResult? terrainRaycastResult, MovingBlocksRaycastResult? movingBlocksRaycastResult, out bool flag)
		{
			bool dealed = false;
			for(int t = 0; t < 3 && !dealed; t++)
			{
                int maxPriority = -1;
                if (maxPriority < priorityUse) maxPriority = priorityUse;
                if (maxPriority < priorityPlace) maxPriority = priorityPlace;
                if (maxPriority < priorityInteract) maxPriority = priorityInteract;
				if (maxPriority <= 0) break;
                if (maxPriority == priorityUse && !dealed){
					dealed = ComponentMiner.Use(playerInput.Interact.Value);
					priorityUse = -2;
				}
				if (maxPriority == priorityInteract && !dealed)
				{
					if(movingBlocksRaycastResult.HasValue)
					{
						dealed = ComponentMiner.Interact(movingBlocksRaycastResult.Value);
					}
					else if(terrainRaycastResult.HasValue){
						dealed = ComponentMiner.Interact(terrainRaycastResult.Value);
					}
					priorityInteract = -2;
				}
				if(maxPriority == priorityPlace && !dealed)
				{
					dealed = ComponentMiner.Place(terrainRaycastResult.Value);
					priorityPlace = -2;
                }
			}
			if (dealed)
			{
                m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
                flag = true;
                m_isAimBlocked = true;
				return;
            }
			flag = false;
		}
		public void Update(float dt)
		{
			PlayerInput playerInput = ComponentInput.PlayerInput;
			if (ComponentInput.IsControlledByTouch && m_aim.HasValue && m_doAimBlockLook)
			{
				playerInput.Look = Vector2.Zero;
			}
			if (ComponentMiner.Inventory != null)
			{
				ComponentMiner.Inventory.ActiveSlotIndex += playerInput.ScrollInventory;
				if (playerInput.SelectInventorySlot.HasValue)
				{
					ComponentMiner.Inventory.ActiveSlotIndex = Math.Clamp(playerInput.SelectInventorySlot.Value, 0, 9);
				}
			}
			ComponentSteedBehavior componentSteedBehavior = null;
			ComponentBoat componentBoat = null;
			ComponentMount mount = ComponentRider.Mount;
            if (mount != null)
			{
				componentSteedBehavior = mount.Entity.FindComponent<ComponentSteedBehavior>();
				componentBoat = mount.Entity.FindComponent<ComponentBoat>();
                if (componentSteedBehavior != null)
                {
                    bool skipVanilla_h = false;
                    ModsManager.HookAction("OnPlayerControlSteed", loader =>
                    {
                        loader.OnPlayerControlSteed(this, skipVanilla_h, out bool skipVanilla);
                        skipVanilla_h |= skipVanilla;
                        return false;
                    });
                    if (!skipVanilla_h)
                    {
                        if (playerInput.Move.Z > 0.5f && !m_speedOrderBlocked)
                        {
                            if (PlayerData.PlayerClass == PlayerClass.Male)
                            {
                                m_subsystemAudio.PlayRandomSound("Audio/Creatures/MaleYellFast", 0.75f, 0f, ComponentBody.Position, 2f, autoDelay: false);
                            }
                            else
                            {
                                m_subsystemAudio.PlayRandomSound("Audio/Creatures/FemaleYellFast", 0.75f, 0f, ComponentBody.Position, 2f, autoDelay: false);
                            }
                            componentSteedBehavior.SpeedOrder = 1;
                            m_speedOrderBlocked = true;
                        }
                        else if (playerInput.Move.Z < -0.5f && !m_speedOrderBlocked)
                        {
                            if (PlayerData.PlayerClass == PlayerClass.Male)
                            {
                                m_subsystemAudio.PlayRandomSound("Audio/Creatures/MaleYellSlow", 0.75f, 0f, ComponentBody.Position, 2f, autoDelay: false);
                            }
                            else
                            {
                                m_subsystemAudio.PlayRandomSound("Audio/Creatures/FemaleYellSlow", 0.75f, 0f, ComponentBody.Position, 2f, autoDelay: false);
                            }
                            componentSteedBehavior.SpeedOrder = -1;
                            m_speedOrderBlocked = true;
                        }
                        else if (MathF.Abs(playerInput.Move.Z) <= 0.25f)
                        {
                            m_speedOrderBlocked = false;
                        }
                        componentSteedBehavior.TurnOrder = playerInput.Move.X;
                        componentSteedBehavior.JumpOrder = playerInput.Jump ? 1 : 0;
                        ComponentLocomotion.LookOrder = new Vector2(playerInput.Look.X, 0f);
                    }
                }
                else if (componentBoat != null)
                {
                    bool skipVanilla_h = false;
                    ModsManager.HookAction("OnPlayerControlBoat", loader =>
                    {
                        loader.OnPlayerControlBoat(this, skipVanilla_h, out bool skipVanilla);
                        skipVanilla_h |= skipVanilla;
                        return false;
                    });
                    if (!skipVanilla_h)
                    {
                        componentBoat.TurnOrder = playerInput.Move.X;
                        componentBoat.MoveOrder = playerInput.Move.Z;
                        ComponentLocomotion.LookOrder = new Vector2(playerInput.Look.X, 0f);
                        ComponentCreatureModel.RowLeftOrder = playerInput.Move.X < -0.2f || playerInput.Move.Z > 0.2f;
                        ComponentCreatureModel.RowRightOrder = playerInput.Move.X > 0.2f || playerInput.Move.Z > 0.2f;
                    }
                }
				else
				{
                    bool skipVanilla_h = false;
                    ModsManager.HookAction("OnPlayerControlOtherMount", loader =>
                    {
                        loader.OnPlayerControlOtherMount(this, skipVanilla_h, out bool skipVanilla);
                        skipVanilla_h |= skipVanilla;
                        return false;
                    });
                }
            }
			else
			{
                bool skipVanilla_h = false;
                ModsManager.HookAction("OnPlayerControlWalk", loader =>
                {
                    loader.OnPlayerControlWalk(this, skipVanilla_h, out bool skipVanilla);
                    skipVanilla_h |= skipVanilla;
                    return false;
                });
                if (!skipVanilla_h)
				{
                    ComponentLocomotion.WalkOrder = ComponentBody.IsCrouching ? (0.66f * new Vector2(playerInput.CrouchMove.X, playerInput.CrouchMove.Z)) : new Vector2(playerInput.Move.X, playerInput.Move.Z);
                    ComponentLocomotion.FlyOrder = new Vector3(0f, playerInput.Move.Y, 0f);
                    ComponentLocomotion.TurnOrder = playerInput.Look * new Vector2(1f, 0f);
                    ComponentLocomotion.JumpOrder = MathUtils.Max(playerInput.Jump ? 1 : 0, ComponentLocomotion.JumpOrder);
                }
			}
			if (m_allowAddLookOrder)
			{
                ComponentLocomotion.LookOrder += playerInput.Look * (SettingsManager.FlipVerticalAxis ? new Vector2(0f, -1f) : new Vector2(0f, 1f));
                ComponentLocomotion.VrLookOrder = playerInput.VrLook;
                ComponentLocomotion.VrMoveOrder = playerInput.VrMove;
            }
			int num = Terrain.ExtractContents(ComponentMiner.ActiveBlockValue);
			Block block = BlocksManager.Blocks[num];
			bool flag = false;
			if (playerInput.Interact.HasValue)
			{
				double timeIntervalLastActionTime = 0.33;
                TerrainRaycastResult? terrainRaycastResult = ComponentMiner.Raycast<TerrainRaycastResult>(playerInput.Interact.Value, RaycastMode.Interaction);
                MovingBlocksRaycastResult? movingBlocksRaycastResult = ComponentMiner.Raycast<MovingBlocksRaycastResult>(playerInput.Interact.Value,RaycastMode.Interaction);
				int priorityUse = block.GetPriorityUse(ComponentMiner.ActiveBlockValue, ComponentMiner);
                int priorityPlace = 0;
                int priorityInteract = 0;
				if(movingBlocksRaycastResult.HasValue)
				{
					int raycastValue = movingBlocksRaycastResult.Value.MovingBlock?.Value ?? 0;
					if(raycastValue != 0)
					{
						priorityInteract = BlocksManager.Blocks[Terrain.ExtractContents(raycastValue)].GetPriorityInteract(raycastValue,ComponentMiner);
					}
				}
                else if (terrainRaycastResult.HasValue)
                {
                    int raycastValue = terrainRaycastResult.Value.Value;
                    priorityPlace = block.GetPriorityPlace(ComponentMiner.ActiveBlockValue, ComponentMiner);
                    priorityInteract = BlocksManager.Blocks[Terrain.ExtractContents(raycastValue)].GetPriorityInteract(raycastValue, ComponentMiner);
                }
                ModsManager.HookAction("OnPlayerInputInteract", loader =>
                {
					loader.OnPlayerInputInteract(this, ref flag, ref timeIntervalLastActionTime, ref priorityUse, ref priorityInteract, ref priorityPlace);
                    return false;
                });
				if (!flag && m_subsystemTime.GameTime - m_lastActionTime > timeIntervalLastActionTime)
				{
                    //处理三者的关系，优先级最高的优先执行
                    DealWithPlayerInteract(priorityUse, priorityPlace, priorityInteract, playerInput, terrainRaycastResult, movingBlocksRaycastResult, out flag);
					m_lastActionTime = timeIntervalLastActionTime;
                }
            }
				
			float timeIntervalAim = (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative) ? 0.1f : 1.4f;
			if (playerInput.Aim.HasValue)
			{
				bool skipVanilla_h = false;
                ModsManager.HookAction("UpdatePlayerInputAim", loader =>
                {
                    loader.UpdatePlayerInputAim(this, true, ref flag, ref timeIntervalAim, skipVanilla_h, out bool skip);
                    skipVanilla_h |= skip;
                    return false;
                });
                if (!skipVanilla_h && block.IsAimable_(ComponentMiner.ActiveBlockValue) && m_subsystemTime.GameTime - m_lastActionTime > timeIntervalAim)
                {
                    if (!m_isAimBlocked)
                    {
                        Ray3 value = playerInput.Aim.Value;
                        Vector3 vector = GameWidget.ActiveCamera.WorldToScreen(value.Position + value.Direction, Matrix.Identity);
                        Point2 size = Window.Size;
                        if (vector.X >= size.X * 0.02f && vector.X < size.X * 0.98f && vector.Y >= size.Y * 0.02f && vector.Y < size.Y * 0.98f)
                        {
                            m_aim = value;
							if (!m_aimStartTime.HasValue) m_aimStartTime = m_subsystemTime.GameTime;
                            if (ComponentMiner.Aim(value, AimState.InProgress))
                            {
                                ComponentMiner.Aim(m_aim.Value, AimState.Cancelled);
                                m_aim = null;
								m_aimStartTime = null;
                                m_isAimBlocked = true;
                            }
                            else if (!m_aimHintIssued && Time.PeriodicEvent(1.0, 0.0))
                            {
                                Time.QueueTimeDelayedExecution(Time.RealTime + 3.0, delegate
                                {
                                    if (!m_aimHintIssued && m_aim.HasValue && !ComponentBody.IsCrouching)
                                    {
                                        m_aimHintIssued = true;
                                        ComponentGui.DisplaySmallMessage(LanguageControl.Get(fName, 1), Color.White, blinking: true, playNotificationSound: true);
                                    }
                                });
                            }
                        }
                        else if (m_aim.HasValue)
                        {
                            ComponentMiner.Aim(m_aim.Value, AimState.Cancelled);
                            m_aim = null;
							m_aimStartTime = null;
                            m_isAimBlocked = true;
                        }
                    }
                }
            }
            else
            {
                m_isAimBlocked = false;
                bool skipVanilla_h = false;
                ModsManager.HookAction("UpdatePlayerInputAim", loader =>
                {
                    loader.UpdatePlayerInputAim(this, false, ref flag, ref timeIntervalAim, skipVanilla_h, out bool skip);
                    skipVanilla_h |= skip;
                    return false;
                });
                if (!skipVanilla_h && m_aim.HasValue)
                {
                    ComponentMiner.Aim(m_aim.Value, AimState.Completed);
                    m_aim = null;
					m_aimStartTime = null;
                    m_lastActionTime = m_subsystemTime.GameTime;
                }
            }

            flag |= m_aim.HasValue;
			if (playerInput.Hit.HasValue)
			{
				bool skipVanilla_ = false;
				double timeIntervalHit = 0.33000001311302185;
				float meleeAttackRange = 2f;
                ModsManager.HookAction("OnPlayerInputHit", loader =>
                {
                    loader.OnPlayerInputHit(this, ref flag, ref timeIntervalHit, ref meleeAttackRange, skipVanilla_, out bool skip);
                    skipVanilla_ |= skip;
                    return false;
                });
                if (!skipVanilla_ && !flag && m_subsystemTime.GameTime - m_lastActionTime > timeIntervalHit && block.GetMeleeHitProbability(ComponentMiner.ActiveBlockValue) > 0 && meleeAttackRange > 0)
                {
					BodyRaycastResult? bodyRaycastResult;
					if(meleeAttackRange <= 5f)
						bodyRaycastResult = ComponentMiner.Raycast<BodyRaycastResult>(playerInput.Hit.Value, RaycastMode.Interaction);
					else
						bodyRaycastResult = ComponentMiner.Raycast<BodyRaycastResult>(playerInput.Hit.Value, RaycastMode.Interaction, true, true, true, meleeAttackRange);
                    if (bodyRaycastResult.HasValue)
                    {
                        flag = true;
                        m_isDigBlocked = true;
                        if (Vector3.Distance(bodyRaycastResult.Value.HitPoint(), ComponentCreatureModel.EyePosition) <= meleeAttackRange)
                        {
                            ComponentMiner.Hit(bodyRaycastResult.Value.ComponentBody, bodyRaycastResult.Value.HitPoint(), playerInput.Hit.Value.Direction);
                        }
                    }
                }
            }

            double timeIntervalDig = 0.33000001311302185;
			if(m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative) timeIntervalDig = SettingsManager.CreativeDigTime;
            if (playerInput.Dig.HasValue)
			{
                bool skipVanilla_ = false;
                ModsManager.HookAction("UpdatePlayerInputDig", loader =>
                {
                    loader.UpdatePlayerInputDig(this, true, ref flag, ref timeIntervalDig, skipVanilla_, out bool skip);
                    skipVanilla_ |= skip;
                    return false;
                });
                if (!skipVanilla_ && !flag && !m_isDigBlocked && m_subsystemTime.GameTime - m_lastActionTime > timeIntervalDig)
                {
                    TerrainRaycastResult? terrainRaycastResult2 = ComponentMiner.Raycast<TerrainRaycastResult>(playerInput.Dig.Value, RaycastMode.Digging);
                    if (terrainRaycastResult2.HasValue && ComponentMiner.Dig(terrainRaycastResult2.Value))
                    {
                        m_lastActionTime = m_subsystemTime.GameTime;
                        m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
                    }
                }
            }
			if (!playerInput.Dig.HasValue)
			{
				m_isDigBlocked = false;
                bool skipVanilla_ = false;
                ModsManager.HookAction("UpdatePlayerInputDig", loader =>
                {
                    loader.UpdatePlayerInputDig(this, false, ref flag, ref timeIntervalDig, skipVanilla_, out bool skip);
                    skipVanilla_ |= skip;
                    return false;
                });
            }
			if (playerInput.Drop && ComponentMiner.Inventory != null)
			{
                bool skipVanilla_ = false;
                ModsManager.HookAction("UpdatePlayerInputDrop", loader =>
                {
                    loader.OnPlayerInputDrop(this, skipVanilla_, out bool skip);
                    skipVanilla_ |= skip;
                    return false;
                });
                if (!skipVanilla_)
				{
                    IInventory inventory = ComponentMiner.Inventory;
                    int slotValue = inventory.GetSlotValue(inventory.ActiveSlotIndex);
                    int num3 = inventory.RemoveSlotItems(count: inventory.GetSlotCount(inventory.ActiveSlotIndex), slotIndex: inventory.ActiveSlotIndex);
                    if (slotValue != 0 && num3 != 0)
                    {
                        Vector3 position = ComponentBody.Position + new Vector3(0f, ComponentBody.StanceBoxSize.Y * 0.66f, 0f) + (0.25f * ComponentBody.Matrix.Forward);
                        Vector3 value2 = 8f * Matrix.CreateFromQuaternion(ComponentCreatureModel.EyeRotation).Forward;
                        m_subsystemPickables.AddPickable(slotValue, num3, position, value2, null, Entity);
                    }
                }
			}
			if (!playerInput.PickBlockType.HasValue || flag)
			{
				return;
			}
			var componentCreativeInventory = ComponentMiner.Inventory as ComponentCreativeInventory;
			if (componentCreativeInventory == null)
			{
				return;
			}
			TerrainRaycastResult? terrainRaycastResult3 = ComponentMiner.Raycast<TerrainRaycastResult>(playerInput.PickBlockType.Value, RaycastMode.Digging, raycastTerrain: true, raycastBodies: false, raycastMovingBlocks: false);
			if (!terrainRaycastResult3.HasValue)
			{
				return;
			}
			int value3 = terrainRaycastResult3.Value.Value;
			value3 = Terrain.ReplaceLight(value3, 0);
			int num4 = Terrain.ExtractContents(value3);
			Block block2 = BlocksManager.Blocks[num4];
			int num5 = 0;
			IEnumerable<int> creativeValues = block2.GetCreativeValues();
			if (block2.GetCreativeValues().Contains(value3))
			{
				num5 = value3;
			}
			if (num5 == 0 && !block2.IsNonDuplicable_(value3))
			{
				var list = new List<BlockDropValue>();
				block2.GetDropValues(m_subsystemTerrain, value3, 0, int.MaxValue, list, out bool _);
				if (list.Count > 0 && list[0].Count > 0)
				{
					num5 = list[0].Value;
				}
			}
			if (num5 == 0)
			{
				num5 = creativeValues.FirstOrDefault();
			}
			if (num5 == 0)
			{
				return;
			}
			int num6 = -1;
			for (int i = 0; i < 10; i++)
			{
				if (componentCreativeInventory.GetSlotCapacity(i, num5) > 0 && componentCreativeInventory.GetSlotCount(i) > 0 && componentCreativeInventory.GetSlotValue(i) == num5)
				{
					num6 = i;
					break;
				}
			}
			if (num6 < 0)
			{
				for (int j = 0; j < 10; j++)
				{
					if (componentCreativeInventory.GetSlotCapacity(j, num5) > 0 && (componentCreativeInventory.GetSlotCount(j) == 0 || componentCreativeInventory.GetSlotValue(j) == 0))
					{
						num6 = j;
						break;
					}
				}
			}
			if (num6 < 0)
			{
				num6 = componentCreativeInventory.ActiveSlotIndex;
			}
			componentCreativeInventory.RemoveSlotItems(num6, int.MaxValue);
			componentCreativeInventory.AddSlotItems(num6, num5, 1);
			componentCreativeInventory.ActiveSlotIndex = num6;
			ComponentGui.DisplaySmallMessage(block2.GetDisplayName(m_subsystemTerrain, value3), Color.White, blinking: false, playNotificationSound: false);
			m_subsystemAudio.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f, 0f);
		}

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			base.Load(valuesDictionary, idToEntityMap);
			m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
			m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(throwOnError: true);
			m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			ComponentGui = Entity.FindComponent<ComponentGui>(throwOnError: true);
			ComponentInput = Entity.FindComponent<ComponentInput>(throwOnError: true);
			ComponentScreenOverlays = Entity.FindComponent<ComponentScreenOverlays>(throwOnError: true);
			ComponentBlockHighlight = Entity.FindComponent<ComponentBlockHighlight>(throwOnError: true);
			ComponentAimingSights = Entity.FindComponent<ComponentAimingSights>(throwOnError: true);
			ComponentMiner = Entity.FindComponent<ComponentMiner>(throwOnError: true);
			ComponentRider = Entity.FindComponent<ComponentRider>(throwOnError: true);
			ComponentSleep = Entity.FindComponent<ComponentSleep>(throwOnError: true);
			ComponentVitalStats = Entity.FindComponent<ComponentVitalStats>(throwOnError: true);
			ComponentSickness = Entity.FindComponent<ComponentSickness>(throwOnError: true);
			ComponentFlu = Entity.FindComponent<ComponentFlu>(throwOnError: true);
			ComponentLevel = Entity.FindComponent<ComponentLevel>(throwOnError: true);
			ComponentClothing = Entity.FindComponent<ComponentClothing>(throwOnError: true);
			ComponentOuterClothingModel = Entity.FindComponent<ComponentOuterClothingModel>(throwOnError: true);
			int playerIndex = valuesDictionary.GetValue<int>("PlayerIndex");
			PlayerData = Project.FindSubsystem<SubsystemPlayers>(throwOnError: true).PlayersData.First((PlayerData d) => d.PlayerIndex == playerIndex);
		}

		public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
		{
			base.Save(valuesDictionary, entityToIdMap);
			valuesDictionary.SetValue("PlayerIndex", PlayerData.PlayerIndex);
		}
	}
}

using Engine;
using GameEntitySystem;
using System;
using TemplatesDatabase;

namespace Game
{
	public class ComponentFrame : Component
	{
		public Vector3 m_position;

		public Quaternion m_rotation;

		public bool m_cachedMatrixValid;

		public Matrix m_cachedMatrix;

		public Vector3 Position
		{
			get
			{
				return m_position;
			}
			set
			{
				if (value != m_position)
				{
					m_cachedMatrixValid = false;
					m_position = value;
					PositionChanged?.Invoke(this);
				}
			}
		}

		public Quaternion Rotation
		{
			get
			{
				return m_rotation;
			}
			set
			{
				value = Quaternion.Normalize(value);
				if (value != m_rotation)
				{
					m_cachedMatrixValid = false;
					m_rotation = value;
					RotationChanged?.Invoke(this);
				}
			}
		}

		public Matrix Matrix
		{
			get
			{
				if (!m_cachedMatrixValid)
				{
					m_cachedMatrix = Matrix.CreateFromQuaternion(Rotation);
					m_cachedMatrix.Translation = Position;
				}
				return m_cachedMatrix;
			}
		}

		public virtual Action<ComponentFrame> PositionChanged { get; set; }
		public virtual Action<ComponentFrame> RotationChanged { get; set; }
		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			Position = valuesDictionary.GetValue<Vector3>("Position");
			Rotation = valuesDictionary.GetValue<Quaternion>("Rotation");
		}

		public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
		{
			valuesDictionary.SetValue("Position", Position);
			valuesDictionary.SetValue("Rotation", Rotation);
		}
	}
}

using Engine;
using GameEntitySystem;
using TemplatesDatabase;

namespace Game
{
	public abstract class ComponentCreatureModel : ComponentModel, IUpdateable
	{
		public SubsystemTime m_subsystemTime;

		public SubsystemGameInfo m_subsystemGameInfo;

		public ComponentCreature m_componentCreature;

		public Vector3? m_eyePosition;

		public Quaternion? m_eyeRotation;

		public float m_injuryColorFactor;

		public Vector3 m_randomLookPoint;

		public Random m_random = new();

		public float Bob
		{
			get;
			set;
		}

		public float MovementAnimationPhase
		{
			get;
			set;
		}

		public float DeathPhase
		{
			get;
			set;
		}

		public Vector3 DeathCauseOffset
		{
			get;
			set;
		}

		public Vector3? LookAtOrder
		{
			get;
			set;
		}

		public bool LookRandomOrder
		{
			get;
			set;
		}

		public float HeadShakeOrder
		{
			get;
			set;
		}

		public bool AttackOrder
		{
			get;
			set;
		}

		public bool FeedOrder
		{
			get;
			set;
		}

		public bool RowLeftOrder
		{
			get;
			set;
		}

		public bool RowRightOrder
		{
			get;
			set;
		}

		public float AimHandAngleOrder
		{
			get;
			set;
		}

		public Vector3 InHandItemOffsetOrder
		{
			get;
			set;
		}

		public Vector3 InHandItemRotationOrder
		{
			get;
			set;
		}

		public bool IsAttackHitMoment
		{
			get;
			set;
		}

		public Vector3 EyePosition
		{
			get
			{
				if (!m_eyePosition.HasValue)
				{
					m_eyePosition = CalculateEyePosition();
				}
				return m_eyePosition.Value;
			}
		}

		public Quaternion EyeRotation
		{
			get
			{
				if (!m_eyeRotation.HasValue)
				{
					m_eyeRotation = CalculateEyeRotation();
				}
				return m_eyeRotation.Value;
			}
		}

		public UpdateOrder UpdateOrder
		{
			get
			{
				ComponentBody parentBody = m_componentCreature.ComponentBody.ParentBody;
				if (parentBody != null)
				{
					ComponentCreatureModel componentCreatureModel = parentBody.Entity.FindComponent<ComponentCreatureModel>();
					if (componentCreatureModel != null)
					{
						return componentCreatureModel.UpdateOrder + 1;
					}
				}
				return UpdateOrder.CreatureModels;
			}
		}

		public override void Animate()
		{
			AnimateCreature();
			Opacity = (m_componentCreature.ComponentSpawn.SpawnDuration > 0f) ? ((float)MathUtils.Saturate((m_subsystemGameInfo.TotalElapsedGameTime - m_componentCreature.ComponentSpawn.SpawnTime) / m_componentCreature.ComponentSpawn.SpawnDuration)) : 1f;
			if (m_componentCreature.ComponentSpawn.DespawnTime.HasValue)
			{
				Opacity = MathUtils.Min(Opacity.Value, (float)MathUtils.Saturate(1.0 - ((m_subsystemGameInfo.TotalElapsedGameTime - m_componentCreature.ComponentSpawn.DespawnTime.Value) / m_componentCreature.ComponentSpawn.DespawnDuration)));
			}
			DiffuseColor = Vector3.Lerp(Vector3.One, new Vector3(1f, 0f, 0f), m_injuryColorFactor);
			if (Opacity.HasValue && Opacity.Value < 1f)
			{
				bool num = m_componentCreature.ComponentBody.ImmersionFactor >= 1f;
				bool flag = m_subsystemSky.ViewUnderWaterDepth > 0f;
				RenderingMode = num == flag ? ModelRenderingMode.TransparentAfterWater : ModelRenderingMode.TransparentBeforeWater;
			}
			else
			{
				RenderingMode = ModelRenderingMode.Solid;
			}
		}

		public abstract void AnimateCreature();

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			base.Load(valuesDictionary, idToEntityMap);
			m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
			m_subsystemSky = Project.FindSubsystem<SubsystemSky>(throwOnError: true);
			m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_componentCreature = Entity.FindComponent<ComponentCreature>(throwOnError: true);
			m_componentCreature.ComponentHealth.Injured += delegate (Injury injury)
			{
				ComponentCreature attacker = injury.Attacker;
				if (attacker == null) return;
				if (DeathPhase == 0f && m_componentCreature.ComponentHealth.Health == 0f)
				{
					DeathCauseOffset = attacker.ComponentBody.BoundingBox.Center() - m_componentCreature.ComponentBody.BoundingBox.Center();
				}
			};
		}

		public override void OnEntityAdded()
		{
			m_componentCreature.ComponentBody.PositionChanged += delegate
			{
				m_eyePosition = null;
			};
			m_componentCreature.ComponentBody.RotationChanged += delegate
			{
				m_eyeRotation = null;
			};
		}

		public virtual void Update(float dt)
		{
			if (LookRandomOrder)
			{
				Matrix matrix = m_componentCreature.ComponentBody.Matrix;
				var v = Vector3.Normalize(m_randomLookPoint - m_componentCreature.ComponentCreatureModel.EyePosition);
				if (m_random.Float(0f, 1f) < 0.25f * dt || Vector3.Dot(matrix.Forward, v) < 0.2f)
				{
					float s = m_random.Float(-5f, 5f);
					float s2 = m_random.Float(-1f, 1f);
					float s3 = m_random.Float(3f, 8f);
					m_randomLookPoint = m_componentCreature.ComponentCreatureModel.EyePosition + (s3 * matrix.Forward) + (s2 * matrix.Up) + (s * matrix.Right);
				}
				LookAtOrder = m_randomLookPoint;
			}
			if (LookAtOrder.HasValue)
			{
				Vector3 forward = m_componentCreature.ComponentBody.Matrix.Forward;
				Vector3 v2 = LookAtOrder.Value - m_componentCreature.ComponentCreatureModel.EyePosition;
				float x = Vector2.Angle(new Vector2(forward.X, forward.Z), new Vector2(v2.X, v2.Z));
				float y = MathF.Asin(0.99f * Vector3.Normalize(v2).Y);
				m_componentCreature.ComponentLocomotion.LookOrder = new Vector2(x, y) - m_componentCreature.ComponentLocomotion.LookAngles;
			}
			if (HeadShakeOrder > 0f)
			{
				HeadShakeOrder = MathUtils.Max(HeadShakeOrder - dt, 0f);
				float num = 1f * MathUtils.Saturate(4f * HeadShakeOrder);
				m_componentCreature.ComponentLocomotion.LookOrder = new Vector2(num * (float)Math.Sin((16.0 * m_subsystemTime.GameTime) + (0.01f * GetHashCode())), 0f) - m_componentCreature.ComponentLocomotion.LookAngles;
			}
			if (m_componentCreature.ComponentHealth.Health == 0f)
			{
				DeathPhase = MathUtils.Min(DeathPhase + (3f * dt), 1f);
			}
			m_eyePosition = null;
			m_eyeRotation = null;
			LookRandomOrder = false;
			LookAtOrder = null;
		}

		public virtual Vector3 CalculateEyePosition()
		{
			Matrix matrix = m_componentCreature.ComponentBody.Matrix;
			return m_componentCreature.ComponentBody.Position + (matrix.Up * 0.95f * m_componentCreature.ComponentBody.BoxSize.Y) + (matrix.Forward * 0.45f * m_componentCreature.ComponentBody.BoxSize.Z);
		}

		public virtual Quaternion CalculateEyeRotation()
		{
			return m_componentCreature.ComponentBody.Rotation * Quaternion.CreateFromYawPitchRoll(0f - m_componentCreature.ComponentLocomotion.LookAngles.X, m_componentCreature.ComponentLocomotion.LookAngles.Y, 0f);
		}
	}
}

using Engine.Media;

namespace Engine.Graphics
{
	public  class PrimitivesRenderer3D : BasePrimitivesRenderer<FlatBatch3D, TexturedBatch3D, FontBatch3D>
	{
		public FlatBatch3D FlatBatch(int layer = 0, DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, BlendState blendState = null)
		{
			depthStencilState = depthStencilState ?? DepthStencilState.Default;
			rasterizerState = rasterizerState ?? RasterizerState.CullNoneScissor;
			blendState = blendState ?? BlendState.AlphaBlend;
			return FindFlatBatch(layer, depthStencilState, rasterizerState, blendState);
		}

		public TexturedBatch3D TexturedBatch(Texture2D texture, bool useAlphaTest = false, int layer = 0, DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, BlendState blendState = null, SamplerState samplerState = null)
		{
			depthStencilState = depthStencilState ?? DepthStencilState.Default;
			rasterizerState = rasterizerState ?? RasterizerState.CullNoneScissor;
			blendState = blendState ?? BlendState.AlphaBlend;
			samplerState = samplerState ?? SamplerState.LinearClamp;
			return FindTexturedBatch(texture, useAlphaTest, layer, depthStencilState, rasterizerState, blendState, samplerState);
		}

		public FontBatch3D FontBatch(BitmapFont font, int layer = 0, DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, BlendState blendState = null, SamplerState samplerState = null)
		{
			depthStencilState = depthStencilState ?? DepthStencilState.Default;
			rasterizerState = rasterizerState ?? RasterizerState.CullNoneScissor;
			blendState = blendState ?? BlendState.AlphaBlend;
			samplerState = samplerState ?? SamplerState.LinearClamp;
			return FindFontBatch(font, layer, depthStencilState, rasterizerState, blendState, samplerState);
		}
	}
}
using Engine;
using GameEntitySystem;
using System;
using System.Collections.Generic;
using TemplatesDatabase;

namespace Game
{
	public class SubsystemTerrain : Subsystem, IDrawable, IUpdateable
	{
		public static bool TerrainRenderingEnabled = true;

		public Dictionary<Point3, bool> m_modifiedCells = [];

		public DynamicArray<Point3> m_modifiedList = [];

		public static Point3[] m_neighborOffsets = new Point3[7]
		{
			new(0, 0, 0),
			new(-1, 0, 0),
			new(1, 0, 0),
			new(0, -1, 0),
			new(0, 1, 0),
			new(0, 0, -1),
			new(0, 0, 1)
		};

		public SubsystemSky m_subsystemsky;

		public SubsystemTime m_subsystemTime;

		public SubsystemTimeOfDay m_subsystemTimeOfDay;

		public SubsystemGameWidgets m_subsystemViews;

		public SubsystemParticles m_subsystemParticles;

		public SubsystemPickables m_subsystemPickables;

		public SubsystemBlockBehaviors m_subsystemBlockBehaviors;

		public List<BlockDropValue> m_dropValues = [];

		public static int[] m_drawOrders = new int[2]
		{
			0,
			100
		};

		public SubsystemGameInfo SubsystemGameInfo
		{
			get;
			set;
		}

		public SubsystemAnimatedTextures SubsystemAnimatedTextures
		{
			get;
			set;
		}

		public SubsystemFurnitureBlockBehavior SubsystemFurnitureBlockBehavior
		{
			get;
			set;
		}

		public SubsystemPalette SubsystemPalette
		{
			get;
			set;
		}

		public Terrain Terrain
		{
			get;
			set;
		}

		public TerrainUpdater TerrainUpdater
		{
			get;
			set;
		}

		public TerrainRenderer TerrainRenderer
		{
			get;
			set;
		}

		public TerrainSerializer23 TerrainSerializer
		{
			get;
			set;
		}

		public ITerrainContentsGenerator TerrainContentsGenerator
		{
			get;
			set;
		}

		public BlockGeometryGenerator BlockGeometryGenerator
		{
			get;
			set;
		}

		public int[] DrawOrders => m_drawOrders;

		public UpdateOrder UpdateOrder => UpdateOrder.Terrain;

		public virtual void ProcessModifiedCells()
		{
			m_modifiedList.Clear();
			foreach (Point3 key in m_modifiedCells.Keys)
			{
				m_modifiedList.Add(key);
			}
			m_modifiedCells.Clear();
			for (int i = 0; i < m_modifiedList.Count; i++)
			{
				Point3 point = m_modifiedList.Array[i];
				for (int j = 0; j < m_neighborOffsets.Length; j++)
				{
					Point3 point2 = m_neighborOffsets[j];
					int cellValue = Terrain.GetCellValue(point.X + point2.X, point.Y + point2.Y, point.Z + point2.Z);
					SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(cellValue));
					for (int k = 0; k < blockBehaviors.Length; k++)
					{
						blockBehaviors[k].OnNeighborBlockChanged(point.X + point2.X, point.Y + point2.Y, point.Z + point2.Z, point.X, point.Y, point.Z);
					}
				}
			}
		}

		public virtual TerrainRaycastResult? Raycast(Vector3 start, Vector3 end, bool useInteractionBoxes, bool skipAirBlocks, Func<int, float, bool> action)
		{
			float num = Vector3.Distance(start, end);
			if (num > 1000f)
			{
				end = start + (1000f * Vector3.Normalize(end - start));
			}
			var ray = new Ray3(start, Vector3.Normalize(end - start));
			float x = start.X;
			float y = start.Y;
			float z = start.Z;
			float x2 = end.X;
			float y2 = end.Y;
			float z2 = end.Z;
			int num2 = Terrain.ToCell(x);
			int num3 = Terrain.ToCell(y);
			int num4 = Terrain.ToCell(z);
			int num5 = Terrain.ToCell(x2);
			int num6 = Terrain.ToCell(y2);
			int num7 = Terrain.ToCell(z2);
			int num8 = (x < x2) ? 1 : ((x > x2) ? (-1) : 0);
			int num9 = (y < y2) ? 1 : ((y > y2) ? (-1) : 0);
			int num10 = (z < z2) ? 1 : ((z > z2) ? (-1) : 0);
			float num11 = MathF.Floor(x);
			float num12 = num11 + 1f;
			float num13 = ((x > x2) ? (x - num11) : (num12 - x)) / Math.Abs(x2 - x);
			float num14 = MathF.Floor(y);
			float num15 = num14 + 1f;
			float num16 = ((y > y2) ? (y - num14) : (num15 - y)) / Math.Abs(y2 - y);
			float num17 = MathF.Floor(z);
			float num18 = num17 + 1f;
			float num19 = ((z > z2) ? (z - num17) : (num18 - z)) / Math.Abs(z2 - z);
			float num20 = 1f / Math.Abs(x2 - x);
			float num21 = 1f / Math.Abs(y2 - y);
			float num22 = 1f / Math.Abs(z2 - z);
			while (true)
			{
				BoundingBox boundingBox = default;
				int collisionBoxIndex = 0;
				float? num23 = null;
				int cellValue = Terrain.GetCellValue(num2, num3, num4);
				int num24 = Terrain.ExtractContents(cellValue);
				if (num24 != 0 || !skipAirBlocks)
				{
					var ray2 = new Ray3(ray.Position - new Vector3(num2, num3, num4), ray.Direction);
					float? num25 = BlocksManager.Blocks[num24].Raycast(ray2, this, cellValue, useInteractionBoxes, out int nearestBoxIndex, out BoundingBox nearestBox);
					if (num25.HasValue && (!num23.HasValue || num25.Value < num23.Value))
					{
						num23 = num25;
						collisionBoxIndex = nearestBoxIndex;
						boundingBox = nearestBox;
					}
				}
				if (num23.HasValue && num23.Value <= num && (action == null || action(cellValue, num23.Value)))
				{
					int face = 0;
					Vector3 vector = start - new Vector3(num2, num3, num4) + (num23.Value * ray.Direction);
					float num26 = float.MaxValue;
					float num27 = MathF.Abs(vector.X - boundingBox.Min.X);
					if (num27 < num26)
					{
						num26 = num27;
						face = 3;
					}
					num27 = MathF.Abs(vector.X - boundingBox.Max.X);
					if (num27 < num26)
					{
						num26 = num27;
						face = 1;
					}
					num27 = MathF.Abs(vector.Y - boundingBox.Min.Y);
					if (num27 < num26)
					{
						num26 = num27;
						face = 5;
					}
					num27 = MathF.Abs(vector.Y - boundingBox.Max.Y);
					if (num27 < num26)
					{
						num26 = num27;
						face = 4;
					}
					num27 = MathF.Abs(vector.Z - boundingBox.Min.Z);
					if (num27 < num26)
					{
						num26 = num27;
						face = 2;
					}
					num27 = MathF.Abs(vector.Z - boundingBox.Max.Z);
					if (num27 < num26)
					{
						num26 = num27;
						face = 0;
					}
					TerrainRaycastResult value = default;
					value.Ray = ray;
					value.Value = cellValue;
					value.CellFace = new CellFace
					{
						X = num2,
						Y = num3,
						Z = num4,
						Face = face
					};
					value.CollisionBoxIndex = collisionBoxIndex;
					value.Distance = num23.Value;
					return value;
				}
				if (num13 <= num16 && num13 <= num19)
				{
					if (num2 == num5)
					{
						break;
					}
					num13 += num20;
					num2 += num8;
				}
				else if (num16 <= num13 && num16 <= num19)
				{
					if (num3 == num6)
					{
						break;
					}
					num16 += num21;
					num3 += num9;
				}
				else
				{
					if (num4 == num7)
					{
						break;
					}
					num19 += num22;
					num4 += num10;
				}
			}
			return null;
		}

		public virtual void ChangeCell(int x,int y,int z,int value,bool updateModificationCounter = true, MovingBlock movingBlock = null)
		{
			bool pass = false;
			ModsManager.HookAction("TerrainChangeCell",loader => {
				loader.TerrainChangeCell(this,x,y,z,value,out bool Skip);
				pass |= Skip;
				return false;
			});
			if(pass) return;
			if(!Terrain.IsCellValid(x,y,z))
			{
				return;
			}
			int cellValueFast = Terrain.GetCellValueFast(x,y,z);
			value = Terrain.ReplaceLight(value,0);
			cellValueFast = Terrain.ReplaceLight(cellValueFast,0);
			if(value == cellValueFast)
			{
				return;
			}
			Terrain.SetCellValueFast(x,y,z,value);
			TerrainChunk chunkAtCell = Terrain.GetChunkAtCell(x,z);
			if(chunkAtCell != null)
			{
				if(updateModificationCounter)
				{
					chunkAtCell.ModificationCounter++;
				}
				TerrainUpdater.DowngradeChunkNeighborhoodState(chunkAtCell.Coords,1,TerrainChunkState.InvalidLight,forceGeometryRegeneration: false);
			}
			m_modifiedCells[new Point3(x,y,z)] = true;
			try
			{
				ChangeCellToBehavior(x,y,z,cellValueFast,value,movingBlock);
			}
			catch(Exception e)
			{
				Log.Error("Block behavior on terrain change execute error: " + e);
			}
		}
		public virtual void ChangeCellToBehavior(int x,int y,int z,int oldValue, int newValue, MovingBlock movingBlock)
		{
			int num = Terrain.ExtractContents(oldValue);
			int num2 = Terrain.ExtractContents(newValue);
			SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(oldValue));
			SubsystemBlockBehavior[] blockBehaviors2 = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(newValue));
			if(movingBlock?.MovingBlockSet != null)
			{
				if(movingBlock.MovingBlockSet.Stopped)
				{
					for(int j = 0; j < blockBehaviors2.Length; j++)
					{
						blockBehaviors2[j].OnBlockStopMoving(newValue,oldValue,x,y,z,movingBlock);
					}
				}
				else
				{
					for(int j = 0; j < blockBehaviors.Length; j++)
					{
						blockBehaviors[j].OnBlockStartMoving(oldValue,newValue,x,y,z,movingBlock);
					}
				}
				return;
			}
			if (num2 != num)
			{
				for (int i = 0; i < blockBehaviors.Length; i++)
				{
					blockBehaviors[i].OnBlockRemoved(oldValue, newValue, x, y, z);
				}
				for (int j = 0; j < blockBehaviors2.Length; j++)
				{
					blockBehaviors2[j].OnBlockAdded(newValue, oldValue, x, y, z);
				}
			}
			else
			{
				for (int k = 0; k < blockBehaviors2.Length; k++)
				{
					blockBehaviors2[k].OnBlockModified(newValue, oldValue, x, y, z);
				}
			}
		}

		public virtual void DestroyCell(int toolLevel, int x, int y, int z, int newValue, bool noDrop, bool noParticleSystem, MovingBlock movingBlock = null)
		{
			int cellValue = Terrain.GetCellValue(x, y, z);
			int num = Terrain.ExtractContents(cellValue);
			Block block = BlocksManager.Blocks[num];
			if (num != 0)
			{
				bool showDebris = true;
				if (!noDrop)
				{
					m_dropValues.Clear();
					block.GetDropValues(this, cellValue, newValue, toolLevel, m_dropValues, out showDebris);
					for (int i = 0; i < m_dropValues.Count; i++)
					{
						BlockDropValue dropValue = m_dropValues[i];
						if (dropValue.Count > 0)
						{
							SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(dropValue.Value));
							for (int j = 0; j < blockBehaviors.Length; j++)
							{
								blockBehaviors[j].OnItemHarvested(x, y, z, cellValue, ref dropValue, ref newValue);
							}
							if (dropValue.Count > 0 && Terrain.ExtractContents(dropValue.Value) != 0)
							{
								Vector3 position = new Vector3(x, y, z) + new Vector3(0.5f);
								m_subsystemPickables.AddPickable(dropValue.Value, dropValue.Count, position, null, null);
							}
						}
					}
				}
				if (showDebris && !noParticleSystem && m_subsystemViews.CalculateDistanceFromNearestView(new Vector3(x, y, z)) < 16f)
				{
					m_subsystemParticles.AddParticleSystem(block.CreateDebrisParticleSystem(this, new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), cellValue, 1f));
				}
			}
			ChangeCell(x, y, z, newValue, true, movingBlock);
		}

		public virtual void Draw(Camera camera, int drawOrder)
		{
			if (TerrainRenderingEnabled)
			{
				if (drawOrder == DrawOrders[0])
				{
					TerrainUpdater.PrepareForDrawing(camera);
					TerrainRenderer.PrepareForDrawing(camera);
					TerrainRenderer.DrawOpaque(camera);
					TerrainRenderer.DrawAlphaTested(camera);
				}
				else if (drawOrder == m_drawOrders[1])
				{
					TerrainRenderer.DrawTransparent(camera);
				}
			}
		}

		public virtual void Update(float dt)
		{
			TerrainUpdater.Update();
			ProcessModifiedCells();
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemViews = Project.FindSubsystem<SubsystemGameWidgets>(throwOnError: true);
			SubsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
			m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(throwOnError: true);
			m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(throwOnError: true);
			m_subsystemBlockBehaviors = Project.FindSubsystem<SubsystemBlockBehaviors>(throwOnError: true);
			SubsystemAnimatedTextures = Project.FindSubsystem<SubsystemAnimatedTextures>(throwOnError: true);
			SubsystemFurnitureBlockBehavior = Project.FindSubsystem<SubsystemFurnitureBlockBehavior>(throwOnError: true);
			m_subsystemsky = Project.FindSubsystem<SubsystemSky>();
			m_subsystemTime = Project.FindSubsystem<SubsystemTime>();
			m_subsystemTimeOfDay = Project.FindSubsystem<SubsystemTimeOfDay>();
			SubsystemPalette = Project.FindSubsystem<SubsystemPalette>(throwOnError: true);
			Terrain = new Terrain();
			TerrainRenderer = new TerrainRenderer(this);
			TerrainUpdater = new TerrainUpdater(this);
			TerrainSerializer = new TerrainSerializer23(SubsystemGameInfo.DirectoryName);
			BlockGeometryGenerator = new BlockGeometryGenerator(Terrain, this, Project.FindSubsystem<SubsystemElectricity>(throwOnError: true), SubsystemFurnitureBlockBehavior, Project.FindSubsystem<SubsystemMetersBlockBehavior>(throwOnError: true), SubsystemPalette);
			TerrainGenerationMode terrainGenerationMode = SubsystemGameInfo.WorldSettings.TerrainGenerationMode;
			if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.1") <= 0)
			{
				if (terrainGenerationMode == TerrainGenerationMode.FlatContinent || terrainGenerationMode == TerrainGenerationMode.FlatIsland)
				{
					TerrainContentsGenerator = new TerrainContentsGeneratorFlat(this);
				}
				else
				{
					TerrainContentsGenerator = new TerrainContentsGenerator21(this);
				}
			}
			else if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.2") == 0)
			{
				if (terrainGenerationMode == TerrainGenerationMode.FlatContinent || terrainGenerationMode == TerrainGenerationMode.FlatIsland)
				{
					TerrainContentsGenerator = new TerrainContentsGeneratorFlat(this);
				}
				else
				{
					TerrainContentsGenerator = new TerrainContentsGenerator22(this);
				}
			}
			else if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.3") == 0)
			{
				if (terrainGenerationMode == TerrainGenerationMode.FlatContinent || terrainGenerationMode == TerrainGenerationMode.FlatIsland)
				{
					TerrainContentsGenerator = new TerrainContentsGeneratorFlat(this);
				}
				else
				{
					TerrainContentsGenerator = new TerrainContentsGenerator23(this);
				}
			}
			else if (terrainGenerationMode == TerrainGenerationMode.FlatContinent || terrainGenerationMode == TerrainGenerationMode.FlatIsland)
			{
				TerrainContentsGenerator = new TerrainContentsGeneratorFlat(this);
			}
			else
			{
				TerrainContentsGenerator = new TerrainContentsGenerator24(this);
			}
		}

		public override void Save(ValuesDictionary valuesDictionary)
		{
			TerrainUpdater.UpdateEvent.WaitOne();
			try
			{
				TerrainChunk[] allocatedChunks = Terrain.AllocatedChunks;
				foreach (TerrainChunk chunk in allocatedChunks)
				{
					TerrainSerializer.SaveChunk(chunk);
				}
			}
			finally
			{
				TerrainUpdater.UpdateEvent.Set();
			}
		}

		public override void Dispose()
		{
			TerrainRenderer.Dispose();
			TerrainUpdater.Dispose();
			TerrainSerializer.Dispose();
			Terrain.Dispose();
		}
	}
}
using Engine;
using Engine.Graphics;

namespace Game
{
	public abstract class Camera
	{
		public GameWidget GameWidget
		{
			get;
			set;
		}

		public VrEye? Eye { get; set; }

		public abstract Vector3 ViewPosition
		{
			get;
		}

		public abstract Vector3 ViewDirection
		{
			get;
		}

		public abstract Vector3 ViewUp
		{
			get;
		}

		public abstract Vector3 ViewRight
		{
			get;
		}

		public abstract Matrix ViewMatrix
		{
			get;
		}

		public abstract Matrix InvertedViewMatrix
		{
			get;
		}

		public abstract Matrix ProjectionMatrix
		{
			get;
		}

		public abstract Matrix ScreenProjectionMatrix
		{
			get;
		}

		public abstract Matrix InvertedProjectionMatrix
		{
			get;
		}

		public abstract Matrix ViewProjectionMatrix
		{
			get;
		}

		public abstract Vector2 ViewportSize
		{
			get;
		}

		public abstract Matrix ViewportMatrix
		{
			get;
		}

		public abstract BoundingFrustum ViewFrustum
		{
			get;
		}

		public abstract bool UsesMovementControls
		{
			get;
		}

		public abstract bool IsEntityControlEnabled
		{
			get;
		}

		public Camera(GameWidget gameWidget)
		{
			GameWidget = gameWidget;
		}

		public Vector3 WorldToScreen(Vector3 worldPoint, Matrix worldMatrix)
		{
			return new Viewport(0, 0, Window.Size.X, Window.Size.Y).Project(worldPoint, ScreenProjectionMatrix, ViewMatrix, worldMatrix);
		}

		public Vector3 ScreenToWorld(Vector3 screenPoint, Matrix worldMatrix)
		{
			return new Viewport(0, 0, Window.Size.X, Window.Size.Y).Unproject(screenPoint, ScreenProjectionMatrix, ViewMatrix, worldMatrix);
		}

		public virtual void Activate(Camera previousCamera)
		{
		}

		public abstract void Update(float dt);
		public virtual void PrepareForDrawing() { }
	}
}

using Engine;
using Engine.Graphics;
using GameEntitySystem;
using Jint.Native;
using System.Linq;
using System.Xml.Linq;

namespace Game
{
	public class InventorySlotWidget : CanvasWidget, IDragTargetWidget
	{
		public BevelledRectangleWidget m_rectangleWidget;

		public RectangleWidget m_highlightWidget;

		public BlockIconWidget m_blockIconWidget;

		public LabelWidget m_countWidget;

		public ValueBarWidget m_healthBarWidget;

		public RectangleWidget m_editOverlayWidget;

		public RectangleWidget m_interactiveOverlayWidget;

		public RectangleWidget m_foodOverlayWidget;

		public LabelWidget m_splitLabelWidget;

		public GameWidget m_gameWidget;

		public DragHostWidget m_dragHostWidget;

		public IInventory m_inventory;

		public int m_slotIndex;

		public DragMode? m_dragMode;

		public bool m_focus;

		public int m_lastCount = -1;

		public InventoryDragData m_inventoryDragData;

		public SubsystemTerrain m_subsystemTerrain;

		public ComponentPlayer m_componentPlayer;

		public Entity m_entity;

		public virtual bool HideBlockIcon
		{
			get;
			set;
		}

        public virtual bool HideEditOverlay
		{
			get;
			set;
		}

		public virtual bool HideInteractiveOverlay
		{
			get;
			set;
		}

		public virtual bool HideFoodOverlay
		{
			get;
			set;
		}

		public virtual bool HideHighlightRectangle
		{
			get;
			set;
		}

		public virtual bool HideHealthBar
		{
			get;
			set;
		}

		public virtual bool ProcessingOnly
		{
			get;
			set;
		}

		public virtual Color CenterColor
		{
			get
			{
				return m_rectangleWidget.CenterColor;
			}
			set
			{
				m_rectangleWidget.CenterColor = value;
			}
		}

		public virtual Color BevelColor
		{
			get
			{
				return m_rectangleWidget.BevelColor;
			}
			set
			{
				m_rectangleWidget.BevelColor = value;
			}
		}

		public virtual Matrix? CustomViewMatrix
		{
			get
			{
				return m_blockIconWidget.CustomViewMatrix;
			}
			set
			{
				m_blockIconWidget.CustomViewMatrix = value;
			}
		}

		public virtual GameWidget GameWidget
		{
			get
			{
				if (m_gameWidget == null)
				{
					for (ContainerWidget parentWidget = ParentWidget; parentWidget != null; parentWidget = parentWidget.ParentWidget)
					{
						var gameWidget = parentWidget as GameWidget;
						if (gameWidget != null)
						{
							m_gameWidget = gameWidget;
							break;
						}
					}
				}
				return m_gameWidget;
			}
		}

		public virtual DragHostWidget DragHostWidget
		{
			get
			{
				if (m_dragHostWidget == null)
				{
					m_dragHostWidget = (GameWidget != null) ? GameWidget.Children.Find<DragHostWidget>(throwIfNotFound: false) : null;
				}
				return m_dragHostWidget;
			}
		}

		public InventorySlotWidget()
		{
			Size = new Vector2(72f, 72f);
			var list = new List<Widget>();
			//不知道做什么的
			m_rectangleWidget = new BevelledRectangleWidget
			{
				BevelSize = -2f,
				DirectionalLight = 0.15f,
				CenterColor = Color.Transparent
			};
			list.Add(m_rectangleWidget);
			//不知道做什么的
			m_highlightWidget = new RectangleWidget
			{
				FillColor = Color.Transparent,
				OutlineColor = Color.Transparent
			};
			list.Add(m_highlightWidget);
			//方块图标
			m_blockIconWidget = new BlockIconWidget
			{
				HorizontalAlignment = WidgetAlignment.Center,
				VerticalAlignment = WidgetAlignment.Center,
				Margin = new Vector2(2f, 2f)
			};
			list.Add(m_blockIconWidget);
			//方块数量标志
			m_countWidget = new LabelWidget
			{
				FontScale = 1f,
				HorizontalAlignment = WidgetAlignment.Far,
				VerticalAlignment = WidgetAlignment.Far,
				Margin = new Vector2(6f, 2f)
			};
			list.Add(m_countWidget);
			//耐久条
			m_healthBarWidget = new ValueBarWidget
			{
				LayoutDirection = LayoutDirection.Vertical,
				HorizontalAlignment = WidgetAlignment.Near,
				VerticalAlignment = WidgetAlignment.Far,
				BarsCount = 3,
				FlipDirection = true,
				LitBarColor = new Color(32, 128, 0),
				UnlitBarColor = new Color(24, 24, 24, 64),
				BarSize = new Vector2(12f, 12f),
				BarSubtexture = ContentManager.Get<Subtexture>("Textures/Atlas/ProgressBar"),
				Margin = new Vector2(4f, 4f)
			};
			list.Add(m_healthBarWidget);
			//右上角显示物品的编辑、交互、腐烂信息的面板
			var stackPanelWidget = new StackPanelWidget
			{
				Direction = LayoutDirection.Horizontal,
				HorizontalAlignment = WidgetAlignment.Far,
				Margin = new Vector2(3f, 3f)
			};
            //标记可交互方块的手标记
            m_interactiveOverlayWidget = new RectangleWidget
			{
				Subtexture = ContentManager.Get<Subtexture>("Textures/Atlas/InteractiveItemOverlay"),
				Size = new Vector2(13f, 14f),
				FillColor = new Color(160, 160, 160),
				OutlineColor = Color.Transparent
			};
			stackPanelWidget.Children.Add(m_interactiveOverlayWidget);
            //标记可编辑方块的编辑标记
            m_editOverlayWidget = new RectangleWidget
			{
				Subtexture = ContentManager.Get<Subtexture>("Textures/Atlas/EditItemOverlay"),
				Size = new Vector2(12f, 14f),
				FillColor = new Color(160, 160, 160),
				OutlineColor = Color.Transparent
			};
            stackPanelWidget.Children.Add(m_editOverlayWidget);
            //标记可腐烂方块的食物标记
            m_foodOverlayWidget = new RectangleWidget
			{
				Subtexture = ContentManager.Get<Subtexture>("Textures/Atlas/FoodItemOverlay"),
				Size = new Vector2(11f, 14f),
				FillColor = new Color(160, 160, 160),
				OutlineColor = Color.Transparent
			};
			stackPanelWidget.Children.Add(m_foodOverlayWidget);
			//完成stackPanelWidget的操作
			list.Add(stackPanelWidget);
            //红框Split标记
            m_splitLabelWidget = new LabelWidget
			{
				Text = "Split",
				Color = new Color(255, 64, 0),
				HorizontalAlignment = WidgetAlignment.Near,
				VerticalAlignment = WidgetAlignment.Near,
				Margin = new Vector2(2f, 0f)
			};
			list.Add(m_splitLabelWidget);
			//为mod提供的标记
			ModsManager.HookAction("OnInventorySlotWidgetDefined", loader =>
			{
				loader.OnInventorySlotWidgetDefined(this, out List<Widget> childrenWidgetsToAdd);
				if(childrenWidgetsToAdd != null)
				{
					list.AddRange(childrenWidgetsToAdd);
				}
				return false;
			});
			//最后将Array放到Childred中
			Children.Add(list.ToArray());
		}

		public virtual void AssignInventorySlot(IInventory inventory, int slotIndex)
		{
			m_inventory = inventory;
			m_slotIndex = slotIndex;
			m_subsystemTerrain = inventory?.Project.FindSubsystem<SubsystemTerrain>(throwOnError: true);
			UpdateEnvironmentData(m_blockIconWidget.DrawBlockEnvironmentData);
		}

		public override void Update()
		{
			if (m_inventory == null || DragHostWidget == null)
			{
				return;
			}
			WidgetInput input = Input;
			ComponentPlayer viewPlayer = GetViewPlayer();
			int slotValue = m_inventory.GetSlotValue(m_slotIndex);
			int num = Terrain.ExtractContents(slotValue);
			Block block = BlocksManager.Blocks[num];
			UpdateEnvironmentData(m_blockIconWidget.DrawBlockEnvironmentData);
            m_blockIconWidget.DrawBlockEnvironmentData.Owner = m_entity;
            if (m_focus && !input.Press.HasValue)
			{
				m_focus = false;
			}
			else if (input.Tap.HasValue && HitTestGlobal(input.Tap.Value) == this)
			{
				m_focus = true;
			}
			if (input.SpecialClick.HasValue && HitTestGlobal(input.SpecialClick.Value.Start) == this && HitTestGlobal(input.SpecialClick.Value.End) == this)
			{
				IInventory inventory = null;
				foreach (InventorySlotWidget item in ((ContainerWidget)RootWidget).AllChildren.OfType<InventorySlotWidget>())
				{
					if (item.m_inventory != null && item.m_inventory != m_inventory && item.Input == Input && item.IsEnabledGlobal && item.IsVisibleGlobal)
					{
						inventory = item.m_inventory;
						break;
					}
				}
				if (inventory != null)
				{
					int num2 = ComponentInventoryBase.FindAcquireSlotForItem(inventory, slotValue);
					if (num2 >= 0)
					{
						HandleMoveItem(m_inventory, m_slotIndex, inventory, num2, m_inventory.GetSlotCount(m_slotIndex));
					}
				}
			}
			if (input.Click.HasValue && HitTestGlobal(input.Click.Value.Start) == this && HitTestGlobal(input.Click.Value.End) == this)
			{
				bool flag = false;
				if (viewPlayer != null)
				{
					if (viewPlayer.ComponentInput.SplitSourceInventory == m_inventory && viewPlayer.ComponentInput.SplitSourceSlotIndex == m_slotIndex)
					{
						viewPlayer.ComponentInput.SetSplitSourceInventoryAndSlot(null, -1);
						flag = true;
					}
					else if (viewPlayer.ComponentInput.SplitSourceInventory != null)
					{
						flag = HandleMoveItem(viewPlayer.ComponentInput.SplitSourceInventory, viewPlayer.ComponentInput.SplitSourceSlotIndex, m_inventory, m_slotIndex, 1);
						AudioManager.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f);
					}
				}
				if (!flag && m_inventory.ActiveSlotIndex != m_slotIndex && m_slotIndex < 10)
				{
					m_inventory.ActiveSlotIndex = m_slotIndex;
					if (m_inventory.ActiveSlotIndex == m_slotIndex)
					{
						AudioManager.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f);
					}
				}
			}
			if (!m_focus || ProcessingOnly || viewPlayer == null)
			{
				return;
			}
			Vector2? hold = input.Hold;
			if (hold.HasValue && HitTestGlobal(hold.Value) == this && !DragHostWidget.IsDragInProgress && m_inventory.GetSlotCount(m_slotIndex) > 0 && (viewPlayer.ComponentInput.SplitSourceInventory != m_inventory || viewPlayer.ComponentInput.SplitSourceSlotIndex != m_slotIndex))
			{
				input.Clear();
				viewPlayer.ComponentInput.SetSplitSourceInventoryAndSlot(m_inventory, m_slotIndex);
				AudioManager.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f);
			}
			Vector2? drag = input.Drag;
			if (!drag.HasValue || HitTestGlobal(drag.Value) != this || DragHostWidget.IsDragInProgress)
			{
				return;
			}
			int slotCount = m_inventory.GetSlotCount(m_slotIndex);
			if (slotCount > 0)
			{
				DragMode dragMode = input.DragMode;
				if (viewPlayer.ComponentInput.SplitSourceInventory == m_inventory && viewPlayer.ComponentInput.SplitSourceSlotIndex == m_slotIndex)
				{
					dragMode = SettingsManager.DragHalfInSplit ? DragMode.HalfItems : DragMode.SingleItem;
				}
				int num3 = (dragMode != 0) ? 1 : slotCount;
				if (dragMode == DragMode.HalfItems) num3 = (slotCount + 1) / 2;
				var containerWidget = (ContainerWidget)LoadWidget(null, ContentManager.Get<XElement>("Widgets/InventoryDragWidget"), null);
				containerWidget.Children.Find<BlockIconWidget>("InventoryDragWidget.Icon").Value = Terrain.ReplaceLight(slotValue, 15);
				containerWidget.Children.Find<LabelWidget>("InventoryDragWidget.Name").Text = block.GetDisplayName(m_subsystemTerrain, slotValue);
				containerWidget.Children.Find<LabelWidget>("InventoryDragWidget.Count").Text = num3.ToString();
				containerWidget.Children.Find<LabelWidget>("InventoryDragWidget.Count").IsVisible = !(m_inventory is ComponentCreativeInventory) && !(m_inventory is ComponentFurnitureInventory);
				UpdateEnvironmentData(containerWidget.Children.Find<BlockIconWidget>("InventoryDragWidget.Icon").DrawBlockEnvironmentData);
				DragHostWidget.BeginDrag(containerWidget, new InventoryDragData
				{
					Inventory = m_inventory,
					SlotIndex = m_slotIndex,
					DragMode = dragMode
				}, delegate
				{
					m_dragMode = null;
				});
				m_dragMode = dragMode;
			}
		}

		public override void MeasureOverride(Vector2 parentAvailableSize)
		{
			if (m_inventory != null)
			{
				bool flag = m_inventory is ComponentCreativeInventory || m_inventory is ComponentFurnitureInventory;
				int num = m_inventory.GetSlotCount(m_slotIndex);
				if (!flag && m_dragMode.HasValue)
				{
					num = m_dragMode.Value switch
					{
						DragMode.AllItems => 0,
						DragMode.SingleItem => num - 1,
						DragMode.HalfItems => num - (num + 1) / 2,
						_ => 0
					};
				}
				m_rectangleWidget.IsVisible = true;
				if (num > 0)
				{
					int slotValue = m_inventory.GetSlotValue(m_slotIndex);
					int num2 = Terrain.ExtractContents(slotValue);
					Block block = BlocksManager.Blocks[num2];
					bool flag2 = block.GetRotPeriod(slotValue) > 0 && block.GetDamage(slotValue) > 0;
					m_blockIconWidget.Value = Terrain.ReplaceLight(slotValue, 15);
					m_blockIconWidget.IsVisible = !HideBlockIcon;
					if (num != m_lastCount)
					{
						m_countWidget.Text = num.ToString();
						m_lastCount = num;
					}
					m_countWidget.IsVisible = num > 1 && !flag;
					m_editOverlayWidget.IsVisible = !HideEditOverlay && block.IsEditable_(slotValue);
					m_interactiveOverlayWidget.IsVisible = !HideInteractiveOverlay && block.IsInteractive(m_subsystemTerrain, slotValue);
					m_foodOverlayWidget.IsVisible = !HideFoodOverlay && block.GetRotPeriod(slotValue) > 0;
					m_foodOverlayWidget.FillColor = flag2 ? new Color(128, 64, 0) : new Color(160, 160, 160);
					if (!flag)
					{
						float percent = block.GetBlockHealth(slotValue);
						if (percent >= 0)
						{
							m_healthBarWidget.IsVisible = true;
							m_healthBarWidget.Value = percent;
						}
						else
						{
							m_healthBarWidget.IsVisible = false;
						}
					}
					else
					{
						m_healthBarWidget.IsVisible = false;
					}

				}
				else
				{
					m_blockIconWidget.IsVisible = false;
					m_countWidget.IsVisible = false;
					m_healthBarWidget.IsVisible = false;
					m_editOverlayWidget.IsVisible = false;
					m_interactiveOverlayWidget.IsVisible = false;
					m_foodOverlayWidget.IsVisible = false;
				}
				m_highlightWidget.IsVisible = !HideHighlightRectangle;
				m_highlightWidget.OutlineColor = Color.Transparent;
				m_highlightWidget.FillColor = Color.Transparent;
				m_splitLabelWidget.IsVisible = false;
				if (m_slotIndex == m_inventory.ActiveSlotIndex)
				{
					m_highlightWidget.OutlineColor = new Color(0, 0, 0);
					m_highlightWidget.FillColor = new Color(0, 0, 0, 80);
				}
				if (IsSplitMode())
				{
					m_highlightWidget.OutlineColor = new Color(255, 64, 0);
					m_splitLabelWidget.IsVisible = true;
				}
			}
			else
			{
				m_rectangleWidget.IsVisible = false;
				m_highlightWidget.IsVisible = false;
				m_blockIconWidget.IsVisible = false;
				m_countWidget.IsVisible = false;
				m_healthBarWidget.IsVisible = false;
				m_editOverlayWidget.IsVisible = false;
				m_interactiveOverlayWidget.IsVisible = false;
				m_foodOverlayWidget.IsVisible = false;
				m_splitLabelWidget.IsVisible = false;
			}
			IsDrawRequired = m_inventoryDragData != null;
			base.MeasureOverride(parentAvailableSize);
			ModsManager.HookAction("InventorySlotWidgetMeasureOverride", loader =>
			{
				loader.InventorySlotWidgetMeasureOverride(this, parentAvailableSize);
				return false;
			});
		}

		public override void Draw(DrawContext dc)
		{
			if (m_inventory != null && m_inventoryDragData != null)
			{
				int slotValue = m_inventoryDragData.Inventory.GetSlotValue(m_inventoryDragData.SlotIndex);
				if (m_inventory.GetSlotProcessCapacity(m_slotIndex, slotValue) >= 0 || m_inventory.GetSlotCapacity(m_slotIndex, slotValue) > 0)
				{
					float num = 80f * GlobalTransform.Right.Length();
					var center = Vector2.Transform(ActualSize / 2f, GlobalTransform);
					FlatBatch2D flatBatch2D = dc.PrimitivesRenderer2D.FlatBatch(100);
					flatBatch2D.QueueEllipse(center, new Vector2(num), 0f, new Color(0, 0, 0, 96) * GlobalColorTransform, 64);
					flatBatch2D.QueueEllipse(center, new Vector2(num - 0.5f), 0f, new Color(0, 0, 0, 64) * GlobalColorTransform, 64);
					flatBatch2D.QueueEllipse(center, new Vector2(num + 0.5f), 0f, new Color(0, 0, 0, 48) * GlobalColorTransform, 64);
					flatBatch2D.QueueDisc(center, new Vector2(num), 0f, new Color(0, 0, 0, 48) * GlobalColorTransform, 64);
				}
			}
			m_inventoryDragData = null;
		}

		public void DragOver(Widget dragWidget, object data)
		{
			m_inventoryDragData = data as InventoryDragData;
		}

		public virtual void DragDrop(Widget dragWidget, object data)
		{
			var inventoryDragData = data as InventoryDragData;
			if (m_inventory != null && inventoryDragData != null)
			{
				HandleDragDrop(inventoryDragData.Inventory, inventoryDragData.SlotIndex, inventoryDragData.DragMode, m_inventory, m_slotIndex);
			}
		}

		private void UpdateEnvironmentData(DrawBlockEnvironmentData environmentData)
		{
			environmentData.SubsystemTerrain = m_subsystemTerrain;
			if (!(m_inventory is Component))
			{
				return;
			}
			Component component = (Component)m_inventory;
			ComponentFrame componentFrame = component.Entity.FindComponent<ComponentFrame>();
			if (componentFrame != null)
			{
				Point3 point = Terrain.ToCell(componentFrame.Position);
				environmentData.InWorldMatrix = componentFrame.Matrix;
				environmentData.Temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(point.X, point.Z);
				environmentData.Humidity = m_subsystemTerrain.Terrain.GetSeasonalHumidity(point.X, point.Z);
			}
			else
			{
				ComponentBlockEntity componentBlockEntity = component.Entity.FindComponent<ComponentBlockEntity>();
				if (componentBlockEntity != null)
				{
					Point3 coordinates = componentBlockEntity.Coordinates;
					environmentData.InWorldMatrix = Matrix.Identity;
					environmentData.Temperature = m_subsystemTerrain.Terrain.GetSeasonalTemperature(coordinates.X, coordinates.Z);
					environmentData.Humidity = m_subsystemTerrain.Terrain.GetSeasonalHumidity(coordinates.X, coordinates.Z);
				}
			}
			ComponentVitalStats componentVitalStats = component.Entity.FindComponent<ComponentVitalStats>();
			if (componentVitalStats != null)
			{
				environmentData.EnvironmentTemperature = componentVitalStats.EnvironmentTemperature;
			}
		}

		public virtual ComponentPlayer GetViewPlayer()
		{
			if (GameWidget == null)
			{
				return null;
			}
			return GameWidget.PlayerData.ComponentPlayer;
		}

		public virtual bool IsSplitMode()
		{
			ComponentPlayer viewPlayer = GetViewPlayer();
			if (viewPlayer != null)
			{
				if (m_inventory != null && m_inventory == viewPlayer.ComponentInput.SplitSourceInventory)
				{
					return m_slotIndex == viewPlayer.ComponentInput.SplitSourceSlotIndex;
				}
				return false;
			}
			return false;
		}

		public virtual bool HandleMoveItem(IInventory sourceInventory, int sourceSlotIndex, IInventory targetInventory, int targetSlotIndex, int count)
		{
            bool moved_ = false;
            ModsManager.HookAction("HandleMoveInventoryItem", loader =>
            {
                loader.HandleMoveInventoryItem(this, sourceInventory, sourceSlotIndex, targetInventory, targetSlotIndex, ref count, out bool moved);
                moved_ |= moved;
                return false;
            });
            int slotValue = sourceInventory.GetSlotValue(sourceSlotIndex);
			int slotValue2 = targetInventory.GetSlotValue(targetSlotIndex);
			int slotCount = sourceInventory.GetSlotCount(sourceSlotIndex);
			int slotCount2 = targetInventory.GetSlotCount(targetSlotIndex);
			if (slotCount2 == 0 || slotValue == slotValue2)
			{
				int num = MathUtils.Min(targetInventory.GetSlotCapacity(targetSlotIndex, slotValue) - slotCount2, slotCount, count);
				if (num > 0)
				{
					int count2 = sourceInventory.RemoveSlotItems(sourceSlotIndex, num);
					targetInventory.AddSlotItems(targetSlotIndex, slotValue, count2);
					return true;
				}
			}
			return moved_;
		}

		public virtual bool HandleDragDrop(IInventory sourceInventory, int sourceSlotIndex, DragMode dragMode, IInventory targetInventory, int targetSlotIndex)
		{
			int sourceSlotValue = sourceInventory.GetSlotValue(sourceSlotIndex);
			int targetSlotValue = targetInventory.GetSlotValue(targetSlotIndex);
			int dragCount = sourceInventory.GetSlotCount(sourceSlotIndex);
			int targetSlotCount = targetInventory.GetSlotCount(targetSlotIndex);
			int targetSlotCapacity = targetInventory.GetSlotCapacity(targetSlotIndex, sourceSlotValue);
			int targetSlotProcessCapacity = targetInventory.GetSlotProcessCapacity(targetSlotIndex, sourceSlotValue);
			if (dragMode == DragMode.SingleItem)
			{
				dragCount = MathUtils.Min(dragCount, 1);
			}
			else if (dragMode == DragMode.HalfItems)
            {
                dragCount = (dragCount + 1) / 2;
			}
			bool flag = false;
			//先进行Process操作
			ModsManager.HookAction("HandleInventoryDragProcess", loader => {
				loader.HandleInventoryDragProcess(this, sourceInventory, sourceSlotIndex, targetInventory, targetSlotIndex, ref targetSlotProcessCapacity);
				return false;
			});
			if (targetSlotProcessCapacity > 0)
			{
				int processCount = sourceInventory.RemoveSlotItems(sourceSlotIndex, MathUtils.Min(dragCount, targetSlotProcessCapacity));
				targetInventory.ProcessSlotItems(targetSlotIndex, sourceSlotValue, dragCount, processCount, out int processedValue, out int processedCount);
				if (processedValue != 0 && processedCount != 0)
				{
					//TODO:ProcessItem允许突破格子物品上限限制
					int count = MathUtils.Min(sourceInventory.GetSlotCapacity(sourceSlotIndex, processedValue), processedCount);
					sourceInventory.AddSlotItems(sourceSlotIndex, processedValue, count);
                }
				flag = true;
			}
			else if (!ProcessingOnly)
			{
				bool movedByMods = false;
				ModsManager.HookAction("HandleInventoryDragMove", loader =>
				{
					loader.HandleInventoryDragMove(this, sourceInventory, sourceSlotIndex, targetInventory, targetSlotIndex, movedByMods, out bool skip);
					movedByMods |= skip;
					return false;
				});
				if (!movedByMods)
				{
                    //移动物品
                    if ((targetSlotCount == 0 || sourceSlotValue == targetSlotValue) && targetSlotCount < targetSlotCapacity)
                    {
                        int num2 = MathUtils.Min(targetSlotCapacity - targetSlotCount, dragCount);
                        bool handleMove = HandleMoveItem(sourceInventory, sourceSlotIndex, targetInventory, targetSlotIndex, num2);
                        if (handleMove) flag = true;
                    }
                    //交换两个物品栏之间的物品
                    else if (targetInventory.GetSlotCapacity(targetSlotIndex, sourceSlotValue) >= dragCount
                        && sourceInventory.GetSlotCapacity(sourceSlotIndex, targetSlotValue) >= targetSlotCount
                        && sourceInventory.GetSlotCount(sourceSlotIndex) == dragCount)
                    {
                        int count3 = targetInventory.RemoveSlotItems(targetSlotIndex, targetSlotCount);
                        int count4 = sourceInventory.RemoveSlotItems(sourceSlotIndex, dragCount);
                        targetInventory.AddSlotItems(targetSlotIndex, sourceSlotValue, count4);
                        sourceInventory.AddSlotItems(sourceSlotIndex, targetSlotValue, count3);
                        flag = true;
                    }
                }
			}

			if (flag)
			{
				AudioManager.PlaySound("Audio/UI/ItemMoved", 1f, 0f, 0f);
			}
			return flag;
		}
	}
}

using Engine;
using System.Xml.Linq;

namespace Game
{
	public class ChestWidget : CanvasWidget
	{
		public ComponentChest m_componentChest;

		public GridPanelWidget m_inventoryGrid;

		public GridPanelWidget m_chestGrid;

		public ChestWidget(IInventory inventory, ComponentChest componentChest)
		{
			m_componentChest = componentChest;
			XElement node = ContentManager.Get<XElement>("Widgets/ChestWidget");
			LoadContents(this, node);
			m_inventoryGrid = Children.Find<GridPanelWidget>("InventoryGrid");
			m_chestGrid = Children.Find<GridPanelWidget>("ChestGrid");
			int num = 0;
			for (int i = 0; i < m_chestGrid.RowsCount; i++)
			{
				for (int j = 0; j < m_chestGrid.ColumnsCount; j++)
				{
					var inventorySlotWidget = new InventorySlotWidget();
					inventorySlotWidget.AssignInventorySlot(componentChest, num++);
					m_chestGrid.Children.Add(inventorySlotWidget);
					m_chestGrid.SetWidgetCell(inventorySlotWidget, new Point2(j, i));
				}
			}
			num = 10;
			for (int k = 0; k < m_inventoryGrid.RowsCount; k++)
			{
				for (int l = 0; l < m_inventoryGrid.ColumnsCount; l++)
				{
					var inventorySlotWidget2 = new InventorySlotWidget();
					inventorySlotWidget2.AssignInventorySlot(inventory, num++);
					m_inventoryGrid.Children.Add(inventorySlotWidget2);
					m_inventoryGrid.SetWidgetCell(inventorySlotWidget2, new Point2(l, k));
				}
			}
		}

		public override void Update()
		{
			if (!m_componentChest.IsAddedToProject)
			{
				ParentWidget.Children.Remove(this);
			}
		}
	}
}

OK源代码基础类型已经展示完整，请开始你的表演