public override void OnBlockRemoved()
        {
            base.OnBlockRemoved();

            if (Api is ICoreClientAPI)
            {
                RemoveRenderedFruits();
            }

            int dropCount = 0;
            for (int i = 0; i < fruitPoints.Length; i++)
            {
                FruitData val = fruitPoints[i];
                if (val.variant < 0 || val.currentStage == 0) continue;
                Item item = Api.World.GetItem(new AssetLocation(fruitCodeBases[val.variant] + val.currentStage));
                if (item == null) continue;
                if (item.Attributes != null && item.Attributes["onGround"].AsBool(false)) continue;  // ignore fruits already on the ground

                if (val.currentStage == this.ripeStage)
                {
                    dropCount++;
                }
                else if (Math.Abs(val.currentStage - this.ripeStage) == 1 && Api.World.Rand.NextDouble() > 0.5) dropCount++;
            }

            if (dropCount > 0)
            {
                ItemStack stack = new ItemStack(Api.World.GetItem(dropCode), dropCount);
                Api.World.SpawnItemEntity(stack, Blockentity.Pos.ToVec3d().Add(0.5, 0.25, 0.5));
            }
        }
 public virtual void RemoveRenderedFruits()
 {
     if (positions == null || fruitCodeBases == null) return;
     for (int i = 0; i < fruitPoints.Length; i++)
     {
         FruitData val = fruitPoints[i];
         if (val.variant >= 0 && val.currentStage > 0) manager.RemoveFruit(fruitCodeBases[val.variant] + val.currentStage, positions[i]);
     }
 }
Пример #3
0
 /// <summary>
 /// Add a fruit to render, with its germination date in gametime  (allows for it to be grown, transitioned etc)
 /// </summary>
 public void AddFruit(AssetLocation code, Vec3d position, FruitData data)
 {
     if (Api.Side == EnumAppSide.Client)
     {
         Item fruit = Api.World.GetItem(code);
         if (fruit != null)
         {
             Renderer.AddFruit(fruit, position, data);
         }
     }
 }
        public void InitializeArrays()
        {
            // If initialising on fresh creation, both arrays will be null  (otherwise fruitPoints was already initialised in FromTreeAttributes)

            if (fruitPoints == null)
            {
                // This code path is called on block placement (i.e. when previous stage crop grows to final stage)
                // This initialises each fruit point with a different germination time
                // (if called after FromTreeAttributes, fruitPoints will already have been populated, and GetGerminationDate() will be called in the next CheckForGrowth() call instead)

                fruitPoints = new FruitData[positionsCount];
                int randomSelector = Math.Abs(this.Blockentity.Pos.GetHashCode()) % fruitCodeBases.Length;

                for (int i = 0; i < positionsCount; i++)
                {
                    int fruitVariant = i;
                    if (i >= fruitCodeBases.Length) fruitVariant = randomSelector++ % fruitCodeBases.Length;
                    fruitPoints[i] = new FruitData(fruitVariant, GetGerminationDate(), this, null);
                }
            }

            positions = new Vec3d[positionsCount];

            Vec3f temp = new Vec3f();
            float[] matrix = null;
            if (Blockentity.Block.RandomizeRotations)
            {
                // For performance, only call the hash function once per blockEntity loaded
                int randomSelector = GameMath.MurmurHash3(-Blockentity.Pos.X, Blockentity.Block.RandomizeAxes == EnumRandomizeAxes.XYZ ? Blockentity.Pos.Y : 0, Blockentity.Pos.Z);
                matrix = randomRotMatrices[GameMath.Mod(randomSelector, randomRotations.Length)];
            }

            for (int i = 0; i < positionsCount; i++)
            {
                if (Api.Side == EnumAppSide.Client)
                {
                    positions[i] = new Vec3d(points[i * 3], points[i * 3 + 1], points[i * 3 + 2]);
                    if (matrix != null)
                    {
                        Mat4f.MulWithVec3_Position(matrix, (float)positions[i].X, (float)positions[i].Y, (float)positions[i].Z, temp);
                        positions[i].X = temp.X;
                        positions[i].Y = temp.Y;
                        positions[i].Z = temp.Z;
                    }
                }
                else
                {
                    positions[i] = new Vec3d((i + 1) / positionsCount, (i + 1) / positionsCount, (i + 1) / positionsCount);  //dummy vector for serverside - exact positions don't matter because they won't be rendered
                }

                positions[i].Add(Blockentity.Pos);
            }
        }
        public override void ToTreeAttributes(ITreeAttribute tree)
        {
            base.ToTreeAttributes(tree);

            tree.SetInt("count", positionsCount);
            for (int i = 0; i < positionsCount; i++)
            {
                FruitData val = fruitPoints[i];
                if (val == null) continue;
                tree.SetDouble("td" + i, val.transitionDate);
                tree.SetInt("var" + i, val.variant);
                tree.SetInt("tc" + i, val.currentStage);
            }
        }
        public virtual void OnPlayerInteractStop(float secondsUsed, IPlayer player, Vec3d hit)
        {
            if (secondsUsed < 0.2f) return;

            for (int i = 0; i < fruitPoints.Length; i++)
            {
                FruitData val = fruitPoints[i];
                if (val.variant >= 0 && val.currentStage >= this.ripeStage)
                {
                    Item item = Api.World.GetItem(new AssetLocation(fruitCodeBases[val.variant] + val.currentStage));
                    if (item == null) continue;
                    if (item.Attributes != null && item.Attributes["onGround"].AsBool(false)) continue;  // ignore fruits already on the ground

                    if (Api.Side == EnumAppSide.Client) manager.RemoveFruit(fruitCodeBases[val.variant] + val.currentStage, positions[i]);
                    val.variant = -1;   // Flag this fruit as picked
                    val.transitionDate = Double.MaxValue;

                    if (val.currentStage >= this.ripeStage)  // allow both ripe and overripe fruits to be picked
                    {
                        // Play snickety sound
                        double posx = Blockentity.Pos.X + hit.X;
                        double posy = Blockentity.Pos.Y + hit.Y;
                        double posz = Blockentity.Pos.Z + hit.Z;
                        player.Entity.World.PlaySoundAt(new AssetLocation("sounds/effect/squish1"), posx, posy, posz, player, 1.1f + (float)Api.World.Rand.NextDouble() * 0.4f, 16, 0.25f);

                        // Update transition time of any non-started fruit, otherwise they may all start immediately
                        double now = Api.World.Calendar.TotalDays;
                        for (int j = 0; j < fruitPoints.Length; j++)
                        {
                            val = fruitPoints[j];
                            if (val.variant >= 0 && val.currentStage == 0 && val.transitionDate < now)
                            {
                                val.transitionDate = now + Api.World.Rand.NextDouble() * maxGerminationDays / 2;
                            }
                        }

                        // Give the player one item
                        ItemStack stack = new ItemStack(Api.World.GetItem(dropCode), 1);

                        if (!player.InventoryManager.TryGiveItemstack(stack))
                        {
                            Api.World.SpawnItemEntity(stack, Blockentity.Pos.ToVec3d().Add(0.5, 0.25, 0.5));
                        }
                    }
                    Blockentity.MarkDirty();
                    break;
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Add a fruit to render, with its germination date in gametime  (allows for it to be grown, transitioned etc)
        /// </summary>
        public void AddFruit(Item fruit, Vec3d position, FruitData data)
        {
            if (fruit.Shape == null)
            {
                return;
            }

            if (!renderers.TryGetValue(fruit.Code, out FruitRenderer renderer))
            {
                renderer = new FruitRenderer(capi, fruit);
                renderers.Add(fruit.Code, renderer);
            }

            renderer.AddFruit(position, data);
        }
        public virtual bool OnPlayerInteract(float secondsUsed, IPlayer player, Vec3d hit)
        {
            if (player?.InventoryManager?.ActiveTool != EnumTool.Knife) return false;

            if (Api.Side == EnumAppSide.Server) return true;

            bool hasPickableFruit = false;
            for (int i = 0; i < fruitPoints.Length; i++)
            {
                FruitData val = fruitPoints[i];
                if (val.variant >= 0 && val.currentStage >= this.ripeStage)
                {
                    Item item = Api.World.GetItem(new AssetLocation(fruitCodeBases[val.variant] + val.currentStage));
                    if (item == null) continue;
                    if (item.Attributes != null && item.Attributes["onGround"].AsBool(false)) continue;  // ignore fruits already on the ground

                    hasPickableFruit = true;
                    break;
                }
           }

            return hasPickableFruit && secondsUsed < 0.3f;
        }
        public override void FromTreeAttributes(ITreeAttribute tree, IWorldAccessor worldForResolving)
        {
            base.FromTreeAttributes(tree, worldForResolving);

            if (positionsCount == 0) positionsCount = tree.GetInt("count");
            if (positionsCount == 0) positionsCount = 10;
            if (fruitPoints == null) fruitPoints = new FruitData[positionsCount];

            for (int i = 0; i < positionsCount; i++)
            {
                double td = tree.GetDouble("td" + i);
                int var = tree.GetInt("var" + i);
                int tc = tree.GetInt("tc" + i);

                FruitData val = fruitPoints[i];
                if (val == null)
                {
                    val = new FruitData(-1, td, this, null);
                    fruitPoints[i] = val;
                }
                if (Api is ICoreClientAPI && val.variant >= 0)  //there was an existing FruitData at this position
                {
                    manager.RemoveFruit(fruitCodeBases[val.variant] + val.currentStage, positions[i]);
                }
                val.variant = var;
                val.currentStage = tc;
                val.transitionDate = td;

                if (Api is ICoreClientAPI && val.variant >= 0 && val.currentStage > 0)
                {
                    val.SetRandomRotation(Api.World, i, positions[i], this.Blockentity.Pos);
                    manager.AddFruit(new AssetLocation(fruitCodeBases[val.variant] + val.currentStage), positions[i], val);
                }
            }


        }
        public override void Initialize(ICoreAPI api, JsonObject properties)
        {
            base.Initialize(api, properties);
            dateLastChecked = Api.World.Calendar.TotalDays;

            // Read the properties

            fruitCodeBases = properties["fruitCodeBases"].AsArray<string>(new string[0]);
            if (fruitCodeBases.Length == 0) return;

            positionsCount = properties["positions"].AsInt(0);
            if (positionsCount <= 0) return;

            string maturePlant = properties["maturePlant"].AsString(null);
            if (maturePlant == null) return;
            Block mature = api.World.GetBlock(new AssetLocation(maturePlant));
            if (!(mature is BlockFruiting matureCrop)) return;
            if (Api.Side == EnumAppSide.Client)
            {
                points = matureCrop.GetFruitingPoints();
            }

            maxFruit = properties["maxFruit"].AsInt(5);
            fruitStages = properties["fruitStages"].AsInt(6);
            maxGerminationDays = properties["maxGerminationDays"].AsFloat(6);
            transitionDays = properties["transitionDays"].AsFloat(1);
            successfulGrowthChance = properties["successfulGrowthChance"].AsFloat(0.75f);
            ripeStage = properties["ripeStage"].AsInt(fruitStages - 1);
            dropCode = new AssetLocation(properties["dropCode"].AsString(null));


            // Set up the manager - used for the instanced renderer

            manager = Api.ModLoader.GetModSystem<FruitingSystem>();


            // If initialising client-side after reading from tree attributes, send fruits to the renderer

            bool addToManager = false;
            if (Api.Side == EnumAppSide.Client && fruitPoints != null)
            {
                LightRgba = Api.World.BlockAccessor.GetLightRGBs(Blockentity.Pos);
                addToManager = true;
            }

            InitializeArrays();

            if (addToManager)
            {
                for (int i = 0; i < positionsCount; i++)
                {
                    FruitData val = fruitPoints[i];
                    if (val.variant >= fruitCodeBases.Length) val.variant %= fruitCodeBases.Length;
                    if (val.variant >= 0 && val.currentStage > 0)
                    {
                        val.SetRandomRotation(Api.World, i, positions[i], this.Blockentity.Pos);
                        manager.AddFruit(new AssetLocation(fruitCodeBases[val.variant] + val.currentStage), positions[i], val);
                    }
                }
            }

            // Tick the blockEntity server-side only

            if (Api.Side == EnumAppSide.Server) Blockentity.RegisterGameTickListener(CheckForGrowth, 2250);
        }
Пример #11
0
 internal void AddFruit(Vec3d position, FruitData data)
 {
     positions[position] = data;
 }