/// <summary> /// Called by GrowableBlockManager to process an update to a block /// Also called very soon after block creation /// </summary> /// <param name="timeNextUpdateHours">The time in timecycle hours when to call UpdateBlock again</param> /// <returns>True if there should be another UpdateBlock call at 'timeNextUpdateHours'</returns> public virtual bool UpdateBlock(IGrowableBlock block, double timeNowHours, out double timeNextUpdateHours) { timeNextUpdateHours = 0.0; if (block == null) { return(false); // discard null blocks } if (block.CurrentStageIndex >= Stages.Count) { return(false); // completed growth, discard } if (!block.IsValid) { return(false); } switch (GrowthType) { case EGrowthType.FirstNightRandom: return(DoUpdateFirstNightRandom(block, timeNowHours, out timeNextUpdateHours)); case EGrowthType.Always: return(DoUpdateAlways(block, timeNowHours, out timeNextUpdateHours)); default: Log.WriteError("Unexpected growthType: {0}", GrowthType); return(false); } }
/// <summary> /// Reports which blocks are tracked in a first iteration to prepare for saving. /// Track how many blocks there are to initialize the array at proper capacity later /// </summary> public virtual void PrepareSaving(IGrowableBlock block) { if (block.IsValid) { BlockCountToSave++; } }
/// <summary> /// Process update from a block that grows every night at a random time (wheat, flax) /// </summary> protected virtual bool DoUpdateFirstNightRandom(IGrowableBlock block, double timeNowHours, out double timeNextUpdateHours) { timeNextUpdateHours = 0.0; double timeDif = timeNowHours - block.LastUpdateHours; if (timeDif > 0.0) { block.Growth = block.Growth + (float)timeDif; } block.LastUpdateHours = timeNowHours; float growthLeft = Stages[block.CurrentStageIndex].GrowthTime - block.Growth; if (growthLeft <= 0f) { if (TryAdvanceStage(block, block.CurrentStageIndex)) { if (!block.IsValid) { return(false); } // block grew, update again randomly in next night timeNextUpdateHours = timeNowHours + TimeCycle.TimeTillSunSet + Random.NextDouble(0.5, TimeCycle.NightLength - 0.5); return(true); } else { // area not loaded, check again in 0.5 - 1.5 ingame hours timeNextUpdateHours = timeNowHours + Random.NextDouble(0.5, 1.5); return(true); } } // growth not completed float timeTillSunRise = TimeCycle.TimeTillSunRise; if (growthLeft <= timeTillSunRise) { // can grow this night float nightLength = TimeCycle.NightLength; if (timeTillSunRise < nightLength) { // night already started timeNextUpdateHours = timeNowHours + Random.NextDouble(growthLeft, timeTillSunRise); } else { // night not started yet timeNextUpdateHours = timeNowHours + Random.NextDouble(timeTillSunRise - nightLength + 0.5f, timeTillSunRise - 0.5); } } else { // can't grow this/coming night, wait a day ish timeNextUpdateHours = timeNowHours + Random.NextDouble(18.0, 24.0); } return(true); }
/// <summary> /// Called to save this specific block /// </summary> public virtual void SaveBlock(IGrowableBlock block) { if (SaveArray == null) { SaveArray = new JSONNode(NodeType.Array); SaveArray.SetArrayCapacity(BlockCountToSave); BlockCountToSave = 0; // reset capacity for next autosave/quit } SaveArray.AddToArray(block.GetJSON()); }
public override bool TryAdvanceStage(IGrowableBlock block, byte currentStageIndex) { Logger.Log("{0} TryAdvanceStage", filename); Vector3Int pos = block.Position; if (currentStageIndex == 0 && pos.IsValid) { for (int i = 0; i < logs.Count; i++) { ushort currentType; if (World.TryGetTypeAt(pos + logs[i], out currentType)) { if (currentType == 0 || currentType == saplingIndex) { if (!ServerManager.TryChangeBlock(pos + logs[i], logIndex)) { return(false); // not loaded } } } else { return(false); // not loaded } } for (int i = 0; i < leaves.Count; i++) { ushort currentType; if (World.TryGetTypeAt(pos + leaves[i], out currentType)) { if (currentType == 0) { if (!ServerManager.TryChangeBlock(pos + leaves[i], leavesIndex)) { return(false); // not loaded } } } else { return(false); // not loaded } } } // succesfully grew, or invalid stage index. Either case, done. block.SetInvalid(); return(true); }
public override bool TryAdvanceStage(IGrowableBlock block, byte currentStageIndex) { if (currentStageIndex == 0) { Vector3Int pos = block.Position; for (int i = 0; i < logs.Count; i++) { ushort currentType; if (World.TryGetTypeAt(pos + logs[i], out currentType)) { if (currentType == 0 || currentType == BuiltinBlocks.CherrySapling) { if (!ServerManager.TryChangeBlock(pos + logs[i], BuiltinBlocks.LogTemperate)) { return(false); // not loaded } } } else { return(false); // not loaded } } for (int i = 0; i < leaves.Count; i++) { ushort currentType; if (World.TryGetTypeAt(pos + leaves[i], out currentType)) { if (currentType == 0) { if (!ServerManager.TryChangeBlock(pos + leaves[i], BuiltinBlocks.CherryBlossom)) { return(false); // not loaded } } } else { return(false); // not loaded } } } // succesfully grew, or invalid stage index. Either case, done. block.SetInvalid(); return(true); }
/// <summary> /// Process update from a block that grows 24/7 (saplings) /// </summary> protected virtual bool DoUpdateAlways(IGrowableBlock block, double timeNowHours, out double timeNextUpdateHours) { timeNextUpdateHours = 0.0; double timeDif = timeNowHours - block.LastUpdateHours; if (timeDif > 0.0) { block.Growth = block.Growth + (float)timeDif; } block.LastUpdateHours = timeNowHours; float growthLeft = Stages[block.CurrentStageIndex].GrowthTime - block.Growth; if (growthLeft <= 0f) { if (TryAdvanceStage(block, block.CurrentStageIndex)) { if (!block.IsValid) { return(false); } growthLeft = Stages[block.CurrentStageIndex].GrowthTime - block.Growth; timeNextUpdateHours = timeNowHours + growthLeft; return(true); } else { // area not loaded, check again in 0.5 - 1.5 ingame hours timeNextUpdateHours = timeNowHours + Random.NextDouble(0.5, 1.5); return(true); } } // growth not completed timeNextUpdateHours = timeNowHours + growthLeft + 0.1f; return(true); }
/// <summary> /// Called when a stage is grown. /// By default places the BlockType of the stage at the position /// </summary> public virtual bool TryAdvanceStage(IGrowableBlock block, byte currentStageIndex) { byte nextStageIndex = (byte)(currentStageIndex + 1); if (nextStageIndex < Stages.Count) { // more stages to go IGrowableStage nextStage = Stages[nextStageIndex]; ushort oldType; if (World.TryGetTypeAt(block.Position, out oldType)) { if (oldType == 0) { // no block... certainly not a valid stage block.SetInvalid(); return(true); } if (oldType != Stages[currentStageIndex].BlockTypeIndex) { // ?? current block type does not match current stage type. // Probably legacy imported blocks // Try to recover what stage to be for (int i = 0; i < Stages.Count; i++) { if (Stages[i].BlockTypeIndex == oldType) { block.CurrentStageIndex = (byte)i; return(false); } } block.SetInvalid(); return(true); } } else { return(false); } if (ServerManager.TryChangeBlock(block.Position, nextStage.BlockTypeIndex)) { if (nextStageIndex == Stages.Count - 1) { // reached last stage block.SetInvalid(); } else { block.CurrentStageIndex = nextStageIndex; block.Growth = Random.NextFloat(0f, RandomStartGrowthMax * Stages[nextStageIndex].GrowthTime); } return(true); } else { return(false); } } else { // at last stage already block.SetInvalid(); return(true); } }