protected BlockSchematicStructure GetGeneratableStructure(VillageSchematic schem, IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int chunksize = blockAccessor.ChunkSize; int climate = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int num = rand.NextInt(schem.Structures.Length); BlockSchematicStructure schematic = schem.Structures[num]; int widthHalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f); pos.Y += schem.OffsetY; // Probe all 4 corners + center if they are on the same height int centerY = blockAccessor.GetTerrainMapheightAt(pos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf); int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf); int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf); int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf); int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); int diff = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY) - GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY); if (diff > 2) { return(null); } pos.Y += centerY - pos.Y + 1 + schem.OffsetY; if (pos.Y <= 0) { return(null); } // Ensure not floating on water tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } // Ensure not submerged in water tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } if (!TestUndergroundCheckPositions(blockAccessor, pos, schematic.UndergroundCheckPositions)) { return(null); } if (isStructureAt(pos, worldForCollectibleResolve)) { return(null); } return(schematic); }
private void growBranch(Random rand, int depth, BlockPos pos, float dx, float dy, float dz, float angleVerStart, float angleHorStart, float curWidth, float dieAt, float trunkWidthLoss, bool wideTrunk) { if (depth > 30) { Console.WriteLine("TreeGen.growBranch() aborted, too many branches!"); return; } TreeGenBranch branch = branchesByDepth[Math.Min(depth, branchesByDepth.Count - 1)]; short[] outline = forestFloor.GetOutline(); float widthloss = depth == 0 ? trunkWidthLoss : branch.WidthLoss(rand); float widthlossCurve = branch.widthlossCurve; float branchspacing = branch.branchSpacing.nextFloat(1, rand); float branchstart = branch.branchStart.nextFloat(1, rand); float branchQuantityStart = branch.branchQuantity.nextFloat(1, rand); float branchWidthMulitplierStart = branch.branchWidthMultiplier.nextFloat(1, rand); float reldistance, lastreldistance = 0; float totaldistance = curWidth / widthloss; int iteration = 0; float sequencesPerIteration = 1f / (curWidth / widthloss); float ddrag, angleVer, angleHor; // we want to place around the trunk/branch => offset the coordinates when growing stuff from the base float trunkOffsetX, trunkOffsetZ; BlockPos currentPos = new BlockPos(); float branchQuantity, branchWidth; float sinAngleVer, cosAnglerHor, sinAngleHor; float currentSequence; LCGRandom lcgrand = lcgrandTL.Value; while (curWidth > 0 && iteration++ < 5000) { curWidth -= widthloss; if (widthlossCurve + curWidth / 20 < 1f) { widthloss *= (widthlossCurve + curWidth / 20); } currentSequence = sequencesPerIteration * (iteration - 1); if (curWidth < dieAt) { break; } angleVer = branch.angleVertEvolve.nextFloat(angleVerStart, currentSequence); angleHor = branch.angleHoriEvolve.nextFloat(angleHorStart, currentSequence); sinAngleVer = GameMath.FastSin(angleVer); cosAnglerHor = GameMath.FastCos(angleHor); sinAngleHor = GameMath.FastSin(angleHor); trunkOffsetX = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * cosAnglerHor)); trunkOffsetZ = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * sinAngleHor)); ddrag = branch.gravityDrag * (float)Math.Sqrt(dx * dx + dz * dz); dx += sinAngleVer * cosAnglerHor / Math.Max(1, Math.Abs(ddrag)); dy += Math.Min(1, Math.Max(-1, GameMath.FastCos(angleVer) - ddrag)); dz += sinAngleVer * sinAngleHor / Math.Max(1, Math.Abs(ddrag)); int blockId = branch.getBlockId(curWidth, config.treeBlocks, this); if (blockId == 0) { return; } currentPos.Set(pos.X + dx, pos.Y + dy, pos.Z + dz); PlaceResumeState state = getPlaceResumeState(currentPos, blockId, wideTrunk); if (state == PlaceResumeState.CanPlace) { api.SetBlock(blockId, currentPos); // Update the canopy outline of the tree for this block position int idz = (int)(dz + 16); int idx = (int)(dx + 16); if (idz > 1 && idz < 31 && idx > 1 && idx < 31) { int canopyIndex = idz * 33 + idx; outline[canopyIndex - 68]++; outline[canopyIndex - 67]++; //bias canopy shading towards the North (- z direction) for sun effects outline[canopyIndex - 66]++; outline[canopyIndex - 65]++; outline[canopyIndex - 64]++; outline[canopyIndex - 35]++; outline[canopyIndex - 34] += 2; outline[canopyIndex - 33] += 2; outline[canopyIndex - 32] += 2; outline[canopyIndex - 31]++; outline[canopyIndex - 2]++; outline[canopyIndex - 1] += 2; outline[canopyIndex + 0] += 3; outline[canopyIndex + 1] += 2; outline[canopyIndex + 2]++; outline[canopyIndex + 33]++; } if (vineGrowthChance > 0 && rand.NextDouble() < vineGrowthChance && config.treeBlocks.vinesBlock != null) { BlockFacing facing = BlockFacing.HORIZONTALS[rand.Next(4)]; BlockPos vinePos = currentPos.AddCopy(facing); float cnt = 1 + rand.Next(11) * (vineGrowthChance + 0.2f); while (api.GetBlockId(vinePos) == 0 && cnt-- > 0) { Block block = config.treeBlocks.vinesBlock; if (cnt <= 0 && config.treeBlocks.vinesEndBlock != null) { block = config.treeBlocks.vinesEndBlock; } block.TryPlaceBlockForWorldGen(api, vinePos, facing, lcgrand); vinePos.Down(); } } } else { if (state == PlaceResumeState.Stop) { return; } } reldistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz) / totaldistance; if (reldistance < branchstart) { continue; } if (reldistance > lastreldistance + branchspacing * (1f - reldistance)) { branchspacing = branch.branchSpacing.nextFloat(1, rand); lastreldistance = reldistance; if (branch.branchQuantityEvolve != null) { branchQuantity = branch.branchQuantityEvolve.nextFloat(branchQuantityStart, currentSequence); } else { branchQuantity = branch.branchQuantity.nextFloat(1, rand); } float prevHorAngle = 0f; float horAngle; float minHorangleDist = Math.Min(GameMath.PI / 5, branch.branchHorizontalAngle.var / 5); bool first = true; while (branchQuantity-- > 0) { if (branchQuantity < 1 && rand.NextDouble() < branchQuantity) { break; } curWidth *= branch.branchWidthLossMul; horAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand); int tries = 10; while (!first && Math.Abs(horAngle - prevHorAngle) < minHorangleDist && tries-- > 0) { float newAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand); if (Math.Abs(horAngle - prevHorAngle) < Math.Abs(newAngle - prevHorAngle)) { horAngle = newAngle; } } if (branch.branchWidthMultiplierEvolve != null) { branchWidth = curWidth * branch.branchWidthMultiplierEvolve.nextFloat(branchWidthMulitplierStart, currentSequence); } else { branchWidth = branch.branchWidthMultiplier.nextFloat(curWidth, rand); } growBranch( rand, depth + 1, pos, dx + trunkOffsetX, dy, dz + trunkOffsetZ, branch.branchVerticalAngle.nextFloat(1, rand), horAngle, branchWidth, Math.Max(0, branch.dieAt.nextFloat(1, rand)), trunkWidthLoss, false ); first = false; prevHorAngle = angleHor + horAngle; } } } }
private bool asyncParticleSpawn(float dt, IAsyncParticleManager manager) { WeatherDataSnapshot weatherData = ws.BlendedWeatherData; ClimateCondition conds = ws.clientClimateCond; if (conds == null || !ws.playerChunkLoaded) { return(true); } EntityPos plrPos = capi.World.Player.Entity.Pos; float precIntensity = conds.Rainfall; float plevel = precIntensity * capi.Settings.Int["particleLevel"] / 100f; float dryness = GameMath.Clamp(1 - precIntensity, 0, 1); tmpPos.Set((int)plrPos.X, (int)plrPos.Y, (int)plrPos.Z); precIntensity = Math.Max(0, precIntensity - (float)Math.Max(0, (plrPos.Y - capi.World.SeaLevel - 5000) / 10000f)); EnumPrecipitationType precType = weatherData.BlendedPrecType; if (precType == EnumPrecipitationType.Auto) { precType = conds.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain; } int rainYPos = capi.World.BlockAccessor.GetRainMapHeightAt((int)particlePos.X, (int)particlePos.Z); particlePos.Set(capi.World.Player.Entity.Pos.X, rainYPos, capi.World.Player.Entity.Pos.Z); int onwaterSplashParticleColor = capi.World.ApplyColorMapOnRgba(lblock.ClimateColorMapResolved, lblock.SeasonColorMapResolved, ColorUtil.WhiteArgb, (int)particlePos.X, (int)particlePos.Y, (int)particlePos.Z, false); byte[] col = ColorUtil.ToBGRABytes(onwaterSplashParticleColor); onwaterSplashParticleColor = ColorUtil.ToRgba(94, col[0], col[1], col[2]); centerPos.Set((int)particlePos.X, 0, (int)particlePos.Z); for (int lx = 0; lx < 16; lx++) { int dx = (lx - 8) * 4; for (int lz = 0; lz < 16; lz++) { int dz = (lz - 8) * 4; lowResRainHeightMap[lx, lz] = capi.World.BlockAccessor.GetRainMapHeightAt(centerPos.X + dx, centerPos.Z + dz); } } parentVeloSnow.X = -Math.Max(0, weatherData.curWindSpeed.X / 2 - 0.15f); parentVeloSnow.Y = 0; parentVeloSnow.Z = 0; // Don't spawn if wind speed below 50% or if the player is 10 blocks above ground if (weatherData.curWindSpeed.X > 0.5f) // && particlePos.Y - rainYPos < 10 { SpawnDustParticles(manager, weatherData, plrPos, dryness, onwaterSplashParticleColor); } particlePos.Y = capi.World.Player.Entity.Pos.Y; if (precIntensity <= 0.02) { return(true); } if (precType == EnumPrecipitationType.Hail) { SpawnHailParticles(manager, weatherData, conds, plrPos, plevel); return(true); } if (precType == EnumPrecipitationType.Rain) { SpawnRainParticles(manager, weatherData, conds, plrPos, plevel, onwaterSplashParticleColor); } if (precType == EnumPrecipitationType.Snow) { SpawnSnowParticles(manager, weatherData, conds, plrPos, plevel); } return(true); }
private void GrowStalk(IBlockAccessor blockAccessor, BlockPos upos, float sizeModifier, float vineGrowthChance) { Block block = this; int height = 7 + rand.Next(4); int nextSegmentAtHeight = height / 3; BlockPos npos = upos.Copy(); for (int i = 0; i < height; i++) { if (!blockAccessor.GetBlock(upos).IsReplacableBy(block)) { break; } blockAccessor.SetBlock(block.BlockId, upos); if (nextSegmentAtHeight <= i) { block = ((BlockBamboo)block).NextSegment(blockAccessor); nextSegmentAtHeight += height / 3; } if (block == null) { break; } if (block == greenSeg3 || block == brownSeg3) { foreach (BlockFacing facing in BlockFacing.ALLFACES) { float chanceFac = facing == BlockFacing.UP ? 0 : 0.25f; if (rand.NextDouble() > chanceFac) { npos.Set(upos.X + facing.Normali.X, upos.Y + facing.Normali.Y, upos.Z + facing.Normali.Z); if (blockAccessor.GetBlock(npos).Replaceable >= leaves.Replaceable) { blockAccessor.SetBlock(leaves.BlockId, npos); } else { continue; } foreach (BlockFacing facing2 in BlockFacing.ALLFACES) { if (rand.NextDouble() > 0.5) { npos.Set(upos.X + facing.Normali.X + facing2.Normali.X, upos.Y + facing.Normali.Y + facing2.Normali.Y, upos.Z + facing.Normali.Z + facing2.Normali.Z); if (blockAccessor.GetBlock(npos).Replaceable >= leaves.Replaceable) { blockAccessor.SetBlock(leaves.BlockId, npos); } break; } } } } } upos.Up(); } }
void ConvertPit() { Dictionary <BlockPos, Vec2i> quantityPerColumn = new Dictionary <BlockPos, Vec2i>(); HashSet <BlockPos> visitedPositions = new HashSet <BlockPos>(); Queue <BlockPos> bfsQueue = new Queue <BlockPos>(); bfsQueue.Enqueue(pos); int maxHalfSize = 6; int firewoodBlockId = api.World.GetBlock(new AssetLocation("firewoodpile")).BlockId; Vec2i curQuantityAndYPos = new Vec2i(); while (bfsQueue.Count > 0) { BlockPos bpos = bfsQueue.Dequeue(); BlockPos bposGround = bpos.Copy(); bposGround.Y = 0; if (quantityPerColumn.TryGetValue(bposGround, out curQuantityAndYPos)) { curQuantityAndYPos.Y = Math.Min(curQuantityAndYPos.Y, bpos.Y); } else { curQuantityAndYPos = quantityPerColumn[bposGround] = new Vec2i(0, bpos.Y); } BlockEntityFirewoodPile be = api.World.BlockAccessor.GetBlockEntity(bpos) as BlockEntityFirewoodPile; if (be != null) { curQuantityAndYPos.X += be.OwnStackSize; } api.World.BlockAccessor.SetBlock(0, bpos); foreach (BlockFacing facing in BlockFacing.ALLFACES) { BlockPos npos = bpos.AddCopy(facing); Block nBlock = api.World.BlockAccessor.GetBlock(npos); // Only traverse inside the firewood pile if (nBlock.BlockId != firewoodBlockId) { continue; } // Only traverse within a 12x12x12 block cube bool inCube = Math.Abs(npos.X - pos.X) <= maxHalfSize && Math.Abs(npos.Y - pos.Y) <= maxHalfSize && Math.Abs(npos.Z - pos.Z) <= maxHalfSize; if (inCube && !visitedPositions.Contains(npos)) { bfsQueue.Enqueue(npos); visitedPositions.Add(npos); } } } BlockPos lpos = new BlockPos(); foreach (var val in quantityPerColumn) { lpos.Set(val.Key.X, val.Value.Y, val.Key.Z); int logQuantity = val.Value.X; int charCoalQuantity = (int)(logQuantity * (0.125f + (float)api.World.Rand.NextDouble() / 8)); while (charCoalQuantity > 0) { Block charcoalBlock = api.World.GetBlock(new AssetLocation("charcoalpile-" + GameMath.Clamp(charCoalQuantity, 1, 8))); api.World.BlockAccessor.SetBlock(charcoalBlock.BlockId, lpos); charCoalQuantity -= 8; lpos.Up(); } } api.World.BlockAccessor.SetBlock(0, pos); }
private void updateSounds(float dt) { float targetRainVolumeLeafy = 0; float targetRainVolumeLeafless = 0; float targetHailVolume = 0; float targetTrembleVolume = 0; float targetRainPitch = 1; float targetHailPitch = 1; WeatherDataSnapshot weatherData = weatherSys.BlendedWeatherData; if (searchComplete) { EntityPlayer eplr = capi.World.Player.Entity; plrPos.Set((int)eplr.Pos.X, (int)eplr.Pos.Y, (int)eplr.Pos.Z); searchComplete = false; TyronThreadPool.QueueTask(() => { float val = (float)Math.Pow(Math.Max(0, (capi.World.BlockAccessor.GetDistanceToRainFall(plrPos, 12, 4) - 2) / 10f), 2); roomVolumePitchLoss = GameMath.Clamp(val, 0, 1); searchComplete = true; }); } EnumPrecipitationType precType = weatherData.BlendedPrecType; if (precType == EnumPrecipitationType.Auto) { precType = weatherSys.clientClimateCond?.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain; } float nearbyLeaviness = GameMath.Clamp(GlobalConstants.CurrentNearbyRelLeavesCountClient * 60, 0, 1); ClimateCondition conds = weatherSys.clientClimateCond; if (conds.Rainfall > 0) { if (precType == EnumPrecipitationType.Rain || weatherSys.clientClimateCond.Temperature < weatherData.snowThresholdTemp) { targetRainVolumeLeafy = nearbyLeaviness * GameMath.Clamp(conds.Rainfall * 2f - Math.Max(0, 2f * (weatherData.snowThresholdTemp - weatherSys.clientClimateCond.Temperature)), 0, 1); targetRainVolumeLeafy = GameMath.Max(0, targetRainVolumeLeafy - roomVolumePitchLoss); targetRainVolumeLeafless = Math.Max(0.3f, 1 - nearbyLeaviness) * GameMath.Clamp(conds.Rainfall * 2f - Math.Max(0, 2f * (weatherData.snowThresholdTemp - weatherSys.clientClimateCond.Temperature)), 0, 1); targetRainVolumeLeafless = GameMath.Max(0, targetRainVolumeLeafless - roomVolumePitchLoss); targetRainPitch = Math.Max(0.7f, 1.25f - conds.Rainfall * 0.7f); targetRainPitch = Math.Max(0, targetRainPitch - roomVolumePitchLoss / 4f); targetTrembleVolume = GameMath.Clamp(conds.Rainfall * 1.6f - 0.8f - roomVolumePitchLoss * 0.25f, 0, 1); if (!rainSoundsOn && (targetRainVolumeLeafy > 0.01 || targetRainVolumeLeafless > 0.01)) { for (int i = 0; i < rainSoundsLeafless.Length; i++) { rainSoundsLeafless[i]?.Start(); } for (int i = 0; i < rainSoundsLeafy.Length; i++) { rainSoundsLeafy[i]?.Start(); } lowTrembleSound?.Start(); rainSoundsOn = true; curRainPitch = targetRainPitch; } if (capi.World.Player.Entity.IsEyesSubmerged()) { curRainPitch = targetRainPitch / 2; targetRainVolumeLeafy *= 0.75f; targetRainVolumeLeafless *= 0.75f; } } if (precType == EnumPrecipitationType.Hail) { targetHailVolume = GameMath.Clamp(conds.Rainfall * 2f - roomVolumePitchLoss, 0, 1); targetHailVolume = GameMath.Max(0, targetHailVolume - roomVolumePitchLoss); targetHailPitch = Math.Max(0.7f, 1.25f - conds.Rainfall * 0.7f); targetHailPitch = Math.Max(0, targetHailPitch - roomVolumePitchLoss / 4f); if (!hailSoundsOn && targetHailVolume > 0.01) { hailSound?.Start(); hailSoundsOn = true; curHailPitch = targetHailPitch; } } } curRainVolumeLeafy += (targetRainVolumeLeafy - curRainVolumeLeafy) * dt / 2; curRainVolumeLeafless += (targetRainVolumeLeafless - curRainVolumeLeafless) * dt / 2; curTrembleVolume += (targetTrembleVolume - curTrembleVolume) * dt; curHailVolume += (targetHailVolume - curHailVolume) * dt; curHailPitch += (targetHailPitch - curHailPitch) * dt; curRainPitch += (targetRainPitch - curRainPitch) * dt; if (rainSoundsOn) { for (int i = 0; i < rainSoundsLeafless.Length; i++) { rainSoundsLeafless[i]?.SetVolume(curRainVolumeLeafless); rainSoundsLeafless[i]?.SetPitch(curRainPitch); } for (int i = 0; i < rainSoundsLeafy.Length; i++) { rainSoundsLeafy[i]?.SetVolume(curRainVolumeLeafy); rainSoundsLeafy[i]?.SetPitch(curRainPitch); } lowTrembleSound?.SetVolume(curTrembleVolume); } if (hailSoundsOn) { hailSound?.SetVolume(curHailVolume); hailSound?.SetPitch(curHailPitch); } if (curRainVolumeLeafless < 0.01 && curRainVolumeLeafy < 0.01) { for (int i = 0; i < rainSoundsLeafless.Length; i++) { rainSoundsLeafless[i]?.Stop(); } for (int i = 0; i < rainSoundsLeafy.Length; i++) { rainSoundsLeafy[i]?.Stop(); } rainSoundsOn = false; } if (curHailVolume < 0.01) { hailSound?.Stop(); hailSoundsOn = false; } float wstr = (1 - roomVolumePitchLoss) * weatherData.curWindSpeed.X - 0.3f; if (wstr > 0.03f || curWindVolumeLeafy > 0.01f || curWindVolumeLeafless > 0.01f) { if (!windSoundsOn) { windSoundLeafy?.Start(); windSoundLeafless?.Start(); windSoundsOn = true; } float targetVolumeLeafy = nearbyLeaviness * 1.2f * wstr; float targetVolumeLeafless = (1 - nearbyLeaviness) * 1.2f * wstr; curWindVolumeLeafy += (targetVolumeLeafy - curWindVolumeLeafy) * dt; curWindVolumeLeafless += (targetVolumeLeafless - curWindVolumeLeafless) * dt; windSoundLeafy?.SetVolume(curWindVolumeLeafy); windSoundLeafless?.SetVolume(curWindVolumeLeafless); } else { if (windSoundsOn) { windSoundLeafy?.Stop(); windSoundLeafless?.Stop(); windSoundsOn = false; } } }
public override void OnGameTick(float deltaTime) { accum += deltaTime; slowaccum += deltaTime; veryslowaccum += deltaTime; plrpos.Set((int)entity.Pos.X, (int)entity.Pos.Y, (int)entity.Pos.Z); if (veryslowaccum > 10 && damagingFreezeHours > 3) { if (api.World.Config.GetString("harshWinters").ToBool(true)) { entity.ReceiveDamage(new DamageSource() { DamageTier = 0, Source = EnumDamageSource.Weather, Type = EnumDamageType.Frost }, 0.2f); } veryslowaccum = 0; if (eagent.Controls.Sprint) { sprinterCounter = GameMath.Clamp(sprinterCounter + 1, 0, 10); } else { sprinterCounter = GameMath.Clamp(sprinterCounter - 1, 0, 10); } } if (slowaccum > 3) { Room room = api.ModLoader.GetModSystem <RoomRegistry>().GetRoomForPosition(plrpos); inEnclosedRoom = room.ExitCount == 0 || room.SkylightCount < room.NonSkylightCount; nearHeatSourceStrength = 0; api.World.BlockAccessor.WalkBlocks(plrpos.AddCopy(-3, -3, -3), plrpos.AddCopy(3, 3, 3), (block, pos) => { BlockBehavior src; if ((src = block.GetBehavior(typeof(IHeatSource), true)) != null) { nearHeatSourceStrength += (src as IHeatSource).GetHeatStrength(api.World, pos, plrpos); } }); slowaccum = 0; updateWearableConditions(); entity.WatchedAttributes.MarkPathDirty("bodyTemp"); } if (accum > 1) { IPlayer plr = (entity as EntityPlayer)?.Player; if (plr?.WorldData.CurrentGameMode == EnumGameMode.Creative || plr?.WorldData.CurrentGameMode == EnumGameMode.Spectator) { CurBodyTemperature = NormalBodyTemperature; entity.WatchedAttributes.SetFloat("freezingEffectStrength", 0); return; } if (plr.Entity.Controls.TriesToMove || plr.Entity.Controls.Jump || plr.Entity.Controls.LeftMouseDown || plr.Entity.Controls.RightMouseDown) { lastMoveMs = entity.World.ElapsedMilliseconds; } ClimateCondition conds = api.World.BlockAccessor.GetClimateAt(plrpos, EnumGetClimateMode.NowValues); if (conds == null) { return; } Vec3d windspeed = api.World.BlockAccessor.GetWindSpeedAt(plrpos); bool rainExposed = api.World.BlockAccessor.GetRainMapHeightAt(plrpos) <= plrpos.Y; Wetness = GameMath.Clamp( Wetness + conds.Rainfall * (rainExposed ? 0.06f : 0) * (conds.Temperature < -1 ? 0.2f : 1) /* Get wet 5 times slower with snow */ + (entity.Swimming ? 1 : 0) - (float)Math.Max(0, (api.World.Calendar.TotalHours - LastWetnessUpdateTotalHours) * GameMath.Clamp(nearHeatSourceStrength, 1, 2)) , 0, 1); LastWetnessUpdateTotalHours = api.World.Calendar.TotalHours; accum = 0; float sprintBonus = sprinterCounter / 2f; float wetnessDebuff = (float)Math.Max(0, Wetness - 0.1) * 10f; // Can bear anything above 10 degrees without clothing, while standing still float hereTemperature = conds.Temperature + clothingBonus + sprintBonus - wetnessDebuff; float tempDiff = hereTemperature - GameMath.Clamp(hereTemperature, bodyTemperatureResistance, 30); // Above 10 degrees, slowly warms up if (tempDiff == 0) { tempDiff = Math.Max((hereTemperature - bodyTemperatureResistance), 0); } float ambientTempChange = GameMath.Clamp(tempDiff / 6f, -6, 6); tempChange = nearHeatSourceStrength + (inEnclosedRoom ? 1 : -(float)Math.Max((windspeed.Length() - 0.15) * 2, 0) + ambientTempChange); bool sleeping = entity.GetBehavior <EntityBehaviorTiredness>()?.IsSleeping == true; if (sleeping) { if (inEnclosedRoom) { tempChange = GameMath.Clamp(NormalBodyTemperature - CurBodyTemperature, -0.15f, 0.15f); } else if (!rainExposed) { tempChange += GameMath.Clamp(NormalBodyTemperature - CurBodyTemperature, 1f, 1f); } } float tempUpdateHoursPassed = (float)(api.World.Calendar.TotalHours - BodyTempUpdateTotalHours); if (tempUpdateHoursPassed > 0.01) { if (tempChange < -0.5 || tempChange > 0) { if (tempChange > 0.5) { tempChange *= 2; // Warming up with a firepit is twice as fast, because nobody wants to wait forever } CurBodyTemperature = GameMath.Clamp(CurBodyTemperature + tempChange * tempUpdateHoursPassed, 31, 45); } BodyTempUpdateTotalHours = api.World.Calendar.TotalHours; entity.WatchedAttributes.SetFloat("freezingEffectStrength", GameMath.Clamp((NormalBodyTemperature - CurBodyTemperature) / 4f - 0.5f, 0, 1)); if (NormalBodyTemperature - CurBodyTemperature > 4) { damagingFreezeHours += tempUpdateHoursPassed; } else { damagingFreezeHours = 0; } } } }
private bool asyncParticleSpawn(float dt, IAsyncParticleManager manager) { WeatherDataSnapshot weatherData = ws.BlendedWeatherData; ClimateCondition conds = ws.clientClimateCond; if (conds == null || !ws.playerChunkLoaded) { return(true); } EntityPos plrPos = capi.World.Player.Entity.Pos; float precIntensity = conds.Rainfall; float plevel = precIntensity * capi.Settings.Int["particleLevel"] / 100f; tmpPos.Set((int)plrPos.X, (int)plrPos.Y, (int)plrPos.Z); //float plevel = weatherData.PrecIntensity * capi.Settings.Int["particleLevel"] / 100f; EnumPrecipitationType precType = weatherData.BlendedPrecType; if (precType == EnumPrecipitationType.Auto) { precType = conds.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain; } particlePos.Set(capi.World.Player.Entity.Pos.X, capi.World.Player.Entity.Pos.Y, capi.World.Player.Entity.Pos.Z); int onwaterSplashParticleColor = capi.World.ApplyColorMapOnRgba(lblock.ClimateColorMapForMap, lblock.SeasonColorMapForMap, ColorUtil.WhiteArgb, (int)particlePos.X, (int)particlePos.Y, (int)particlePos.Z, false); byte[] col = ColorUtil.ToBGRABytes(onwaterSplashParticleColor); onwaterSplashParticleColor = ColorUtil.ToRgba(94, col[0], col[1], col[2]); centerPos.Set((int)particlePos.X, 0, (int)particlePos.Z); for (int lx = 0; lx < 16; lx++) { int dx = (lx - 8) * 4; for (int lz = 0; lz < 16; lz++) { int dz = (lz - 8) * 4; lowResRainHeightMap[lx, lz] = capi.World.BlockAccessor.GetRainMapHeightAt(centerPos.X + dx, centerPos.Z + dz); } } int rainYPos = capi.World.BlockAccessor.GetRainMapHeightAt((int)particlePos.X, (int)particlePos.Z); parentVeloSnow.X = -Math.Max(0, weatherData.curWindSpeed.X / 2 - 0.15f); parentVeloSnow.Y = 0; parentVeloSnow.Z = 0; // Don't spawn if wind speed below 70% or if the player is 10 blocks above ground if (weatherData.curWindSpeed.X > 0.7f && particlePos.Y - rainYPos < 10) { float dx = (float)(plrPos.Motion.X * 40) - 50 * weatherData.curWindSpeed.X; float dy = (float)(plrPos.Motion.Y * 40); float dz = (float)(plrPos.Motion.Z * 40); dustParticles.MinPos.Set(particlePos.X - 40 + dx, particlePos.Y + 15 + dy, particlePos.Z - 40 + dz); dustParticles.AddPos.Set(80, -20, 80); dustParticles.GravityEffect = -0.1f - (float)rand.NextDouble() * 0.1f; dustParticles.ParticleModel = EnumParticleModel.Quad; dustParticles.LifeLength = 1f; dustParticles.DieOnRainHeightmap = true; dustParticles.WindAffectednes = 8f; dustParticles.MinQuantity = 0; dustParticles.AddQuantity = 6 * (weatherData.curWindSpeed.X - 0.7f); dustParticles.MinSize = 0.1f; dustParticles.MaxSize = 0.4f; dustParticles.MinVelocity.Set(-0.025f + 8 * weatherData.curWindSpeed.X, -0.2f, -0.025f); dustParticles.AddVelocity.Set(0.05f + 4 * weatherData.curWindSpeed.X, 0.05f, 0.05f); for (int i = 0; i < 6; i++) { double px = particlePos.X + dx + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2)); double pz = particlePos.Z + dz + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2)); int py = capi.World.BlockAccessor.GetRainMapHeightAt((int)px, (int)pz); Block block = capi.World.BlockAccessor.GetBlock((int)px, py, (int)pz); if (block.IsLiquid()) { continue; } tmpPos.Set((int)px, py, (int)pz); dustParticles.Color = ColorUtil.ReverseColorBytes(block.GetColor(capi, tmpPos)); dustParticles.Color |= 255 << 24; manager.Spawn(dustParticles); } } if (precIntensity <= 0.02) { return(true); } if (precType == EnumPrecipitationType.Hail) { float dx = (float)(plrPos.Motion.X * 40) - 4 * weatherData.curWindSpeed.X; float dy = (float)(plrPos.Motion.Y * 40); float dz = (float)(plrPos.Motion.Z * 40); hailParticle.MinPos.Set(particlePos.X + dx, particlePos.Y + 15 + dy, particlePos.Z + dz); hailParticle.MinSize = 0.3f * (0.5f + conds.Rainfall); // * weatherData.PrecParticleSize; hailParticle.MaxSize = 1f * (0.5f + conds.Rainfall); // * weatherData.PrecParticleSize; //hailParticle.AddPos.Set(80, 5, 80); hailParticle.Color = ColorUtil.ToRgba(220, 210, 230, 255); hailParticle.MinQuantity = 100 * plevel; hailParticle.AddQuantity = 25 * plevel; hailParticle.MinVelocity.Set(-0.025f + 7.5f * weatherData.curWindSpeed.X, -5f, -0.025f); hailParticle.AddVelocity.Set(0.05f + 7.5f * weatherData.curWindSpeed.X, 0.05f, 0.05f); manager.Spawn(hailParticle); return(true); } if (precType == EnumPrecipitationType.Rain) { float dx = (float)(plrPos.Motion.X * 80); float dy = (float)(plrPos.Motion.Y * 80); float dz = (float)(plrPos.Motion.Z * 80); rainParticle.MinPos.Set(particlePos.X - 30 + dx, particlePos.Y + 15 + dy, particlePos.Z - 30 + dz); rainParticle.WithTerrainCollision = false; rainParticle.MinQuantity = 1000 * plevel; rainParticle.LifeLength = 1f; rainParticle.AddQuantity = 25 * plevel; rainParticle.MinSize = 0.15f * (0.5f + conds.Rainfall); // * weatherData.PrecParticleSize; rainParticle.MaxSize = 0.22f * (0.5f + conds.Rainfall); // weatherData.PrecParticleSize; rainParticle.Color = rainParticleColor; rainParticle.MinVelocity.Set(-0.025f + 8 * weatherData.curWindSpeed.X, -10f, -0.025f); rainParticle.AddVelocity.Set(0.05f + 8 * weatherData.curWindSpeed.X, 0.05f, 0.05f); manager.Spawn(rainParticle); splashParticles.MinVelocity = new Vec3f(-1f, 3, -1f); splashParticles.AddVelocity = new Vec3f(2, 0, 2); splashParticles.LifeLength = 0.1f; splashParticles.MinSize = 0.07f * (0.5f + 0.65f * conds.Rainfall); // weatherData.PrecParticleSize; splashParticles.MaxSize = 0.2f * (0.5f + 0.65f * conds.Rainfall); // weatherData.PrecParticleSize; splashParticles.ShouldSwimOnLiquid = true; splashParticles.Color = rainParticleColor; float cnt = 100 * plevel; for (int i = 0; i < cnt; i++) { double px = particlePos.X + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2)); double pz = particlePos.Z + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2)); int py = capi.World.BlockAccessor.GetRainMapHeightAt((int)px, (int)pz); Block block = capi.World.BlockAccessor.GetBlock((int)px, py, (int)pz); if (block.IsLiquid()) { splashParticles.MinPos.Set(px, py + block.TopMiddlePos.Y - 1 / 8f, pz); splashParticles.AddVelocity.Y = 1.5f; splashParticles.LifeLength = 0.17f; splashParticles.Color = onwaterSplashParticleColor; } else { double b = 0.75 + 0.25 * rand.NextDouble(); int ca = 230 - rand.Next(100); int cr = (int)(((rainParticleColor >> 16) & 0xff) * b); int cg = (int)(((rainParticleColor >> 8) & 0xff) * b); int cb = (int)(((rainParticleColor >> 0) & 0xff) * b); splashParticles.Color = (ca << 24) | (cr << 16) | (cg << 8) | cb; splashParticles.AddVelocity.Y = 0f; splashParticles.LifeLength = 0.1f; splashParticles.MinPos.Set(px, py + block.TopMiddlePos.Y + 0.05, pz); } manager.Spawn(splashParticles); } } if (precType == EnumPrecipitationType.Snow) { float wetness = 2.5f * GameMath.Clamp(ws.clientClimateCond.Temperature + 1, 0, 4) / 4f; float dx = (float)(plrPos.Motion.X * 40) - (30 - 9 * wetness) * weatherData.curWindSpeed.X; float dy = (float)(plrPos.Motion.Y * 40); float dz = (float)(plrPos.Motion.Z * 40); snowParticle.MinVelocity.Set(-0.5f + 5 * weatherData.curWindSpeed.X, -1f, -0.5f); snowParticle.AddVelocity.Set(1f + 5 * weatherData.curWindSpeed.X, 0.05f, 1f); snowParticle.Color = ColorUtil.ToRgba(255, 255, 255, 255); snowParticle.MinQuantity = 90 * plevel * (1 + wetness / 3); snowParticle.AddQuantity = 15 * plevel * (1 + wetness / 3); snowParticle.ParentVelocity = parentVeloSnow; snowParticle.ShouldDieInLiquid = true; snowParticle.LifeLength = Math.Max(1f, 4f - wetness); snowParticle.Color = ColorUtil.ColorOverlay(ColorUtil.ToRgba(255, 255, 255, 255), rainParticle.Color, wetness / 4f); snowParticle.GravityEffect = 0.005f * (1 + 20 * wetness); snowParticle.MinSize = 0.1f * conds.Rainfall; // weatherData.PrecParticleSize; snowParticle.MaxSize = 0.3f * conds.Rainfall / (1 + wetness); // weatherData.PrecParticleSize / (1 + wetness); float hrange = 40; float vrange = 20; snowParticle.MinPos.Set(particlePos.X - hrange + dx, particlePos.Y + vrange + dy, particlePos.Z - hrange + dz); snowParticle.AddPos.Set(2 * hrange + dx, -0.66f * vrange + dy, 2 * hrange + dz); manager.Spawn(snowParticle); } return(true); }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blAcc, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldgenRand) { int cnt = 2 + worldgenRand.NextInt(25); float depth = GameMath.Sqrt(GameMath.Sqrt(cnt)); float craterRadius = GameMath.Sqrt(cnt) * 1.25f; // Look for even or downwards curved ground if (pos.Y > 250 || !IsSolid(blAcc, pos.X, pos.Y - 3, pos.Z) || !IsSolid(blAcc, pos.X, pos.Y - (int)depth, pos.Z) || !IsSolid(blAcc, pos.X + (int)craterRadius, pos.Y - 1, pos.Z) || !IsSolid(blAcc, pos.X - (int)craterRadius, pos.Y - 1, pos.Z) || !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z - (int)craterRadius) || !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z + (int)craterRadius) ) { return(false); } int y1 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 5, pos.Y, pos.Z)); int y2 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X + 5, pos.Y, pos.Z)); int y3 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z + 5)); int y4 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z - 5)); if ((GameMath.Max(y1, y2, y3, y4) - GameMath.Min(y1, y2, y3, y4)) > 4) { return(false); } tmpPos = tmpPos.Set(pos.X, pos.Y - (int)depth - 2, pos.Z); while (cnt-- > 0) { tmpPos.X += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; tmpPos.Y += worldgenRand.NextInt(8) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; tmpPos.Z += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; blAcc.SetBlock(this.BlockId, tmpPos); } int sueviteBlockId = api.World.GetBlock(new AssetLocation("rock-suevite")).BlockId; int fragmentBlockId = api.World.GetBlock(new AssetLocation("loosestones-meteorite-iron-free")).BlockId; int looseSueviteBlockId = api.World.GetBlock(new AssetLocation("loosestones-suevite-free")).BlockId; float impactRockRadius = craterRadius * 1.2f; int range = (int)Math.Ceiling(impactRockRadius); int chunksize = api.World.BlockAccessor.ChunkSize; Vec2i vecTmp = new Vec2i(); // 1. Generate a basin of suevite and lower terrain for (int dx = -range; dx <= range; dx++) { for (int dz = -range; dz <= range; dz++) { float distImpactRockEdge = (dx * dx + dz * dz) / (impactRockRadius * impactRockRadius); if (distImpactRockEdge > 1) { continue; } tmpPos.X = pos.X + dx; tmpPos.Z = pos.Z + dz; int surfaceY = blAcc.GetTerrainMapheightAt(tmpPos); tmpPos.Y = surfaceY - (int)depth; vecTmp.X = tmpPos.X / chunksize; vecTmp.Y = tmpPos.Z / chunksize; IMapChunk mapchunk = blAcc.GetMapChunk(vecTmp); float q = 3 * Math.Max(0, 2 * (1 - distImpactRockEdge) - 0.2f); tmpPos.Y -= (int)q + 1; while (q > 0) { if (q < 1 && worldgenRand.NextDouble() > q) { break; } Block block = blAcc.GetBlock(tmpPos); if (block != this && block.BlockMaterial == EnumBlockMaterial.Stone) { blAcc.SetBlock(sueviteBlockId, tmpPos); } q--; tmpPos.Y++; } float distToCraterEdge = (dx * dx + dz * dz) / (craterRadius * craterRadius) + (float)worldgenRand.NextDouble() * 0.1f; if (distToCraterEdge > 1) { continue; } q = depth * (1 - distToCraterEdge); tmpPos.Y = surfaceY; Block surfaceblock = blAcc.GetBlock(tmpPos); Block abovesurfaceblock = blAcc.GetBlock(tmpPos.X, tmpPos.Y + 1, tmpPos.Z); for (int i = -1; i <= (int)q; i++) { tmpPos.Y = surfaceY - i; int id = i == (int)q ? surfaceblock.BlockId : 0; Block bblock = blAcc.GetBlock(tmpPos); if (!bblock.IsLiquid()) { blAcc.SetBlock(id, tmpPos); } } mapchunk.WorldGenTerrainHeightMap[(tmpPos.Z % chunksize) * chunksize + (tmpPos.X % chunksize)] -= (ushort)q; tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1; blAcc.SetBlock(abovesurfaceblock.BlockId, tmpPos); } } int quantityFragments = 0; if (worldgenRand.NextInt(10) == 0) { quantityFragments = worldgenRand.NextInt(10); } else if (worldgenRand.NextInt(5) == 0) { quantityFragments = worldgenRand.NextInt(5); } while (quantityFragments-- > 0) { tmpPos.Set( pos.X + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5, 0, pos.Z + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5 ); tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1; if (!blAcc.GetBlock(tmpPos.X, tmpPos.Y - 1, tmpPos.Z).SideSolid[BlockFacing.UP.Index]) { continue; } if (worldgenRand.NextDouble() < 0.3) { blAcc.SetBlock(fragmentBlockId, tmpPos); } else { blAcc.SetBlock(looseSueviteBlockId, tmpPos); } } //blAcc.SetBlock(61, pos.AddCopy(0, 20, 0)); return(true); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ) { if (!TerraGenConfig.GenerateStructures) { return; } IMapRegion region = chunks[0].MapChunk.MapRegion; IntMap forestMap = region.ForestMap; IntMap climateMap = region.ClimateMap; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; // A region has 16 chunks // Size of the forest map is RegionSize / TerraGenConfig.forestMapScale => 32*16 / 32 = 16 pixel // rlX, rlZ goes from 0..16 pixel // facF = 16/16 = 1 // Get 4 pixels for chunkx, chunkz, chunkx+1 and chunkz+1 inside the map float facF = (float)forestMap.InnerSize / regionChunkSize; forestUpLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF)); forestUpRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF)); forestBotLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF)); forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF)); float facC = (float)climateMap.InnerSize / regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC)); heightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; BlockPos pos = new BlockPos(); for (int i = 0; i < scfg.Structures.Length; i++) { WorldGenStructure struc = scfg.Structures[i]; float chance = struc.Chance * scfg.ChanceMultiplier; while (chance-- > rnd.NextDouble()) { int dx = rnd.Next(chunksize); int dz = rnd.Next(chunksize); int ySurface = heightmap[dz * chunksize + dx]; if (ySurface <= 0 || ySurface >= worldheight - 15) { continue; } if (struc.Placement == EnumStructurePlacement.Underground) { if (struc.Depth != null) { pos.Set(chunkX * chunksize + dx, ySurface - (int)struc.Depth.nextFloat(), chunkZ * chunksize + dz); } else { pos.Set(chunkX * chunksize + dx, 8 + rnd.Next(ySurface - 8 - 5), chunkZ * chunksize + dz); } } else { pos.Set(chunkX * chunksize + dx, ySurface, chunkZ * chunksize + dz); } struc.TryGenerate(worldgenBlockAccessor, api.World, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); } } }
protected bool traversable(PathNode node, float stepHeight, int maxFallHeight, Cuboidf entityCollBox, bool isDiagonal, ref float extraCost) { tmpVec.Set(node.X + centerOffsetX, node.Y, node.Z + centerOffsetZ); if (!api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { // Down ok? while (true) { tmpPos.Set(node.X, node.Y - 1, node.Z); Block block = blockAccess.GetBlock(tmpPos); if (block.LiquidCode == "lava") { return(false); // TODO: Turn into an entityAvoid boolean } if (block.LiquidCode == "water") { extraCost = 5; //node.Y--; - we swim on top break; } tmpVec.Y--; // Do we collide if we go one block down? // Our hitbox size might be >1 and we might collide with a wall only // so also test if there is actually any collision box right below us. // If collision but no collision box below: Can't really wall-walk, so fail // If no collision but hitbox below: I guess we can step on it to continue from here? // If no collision and no hitbox below: Free fall, lets keep searching downwards Cuboidf[] collboxes = block.GetCollisionBoxes(blockAccess, tmpPos); bool collidingBlockBelow = collboxes != null && collboxes.Length > 0; if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { if (!collidingBlockBelow) { return(false); } extraCost -= (block.WalkSpeedMultiplier - 1) * 8; break; } else { if (collidingBlockBelow) { extraCost -= (block.WalkSpeedMultiplier - 1) * 8; break; } } node.Y--; maxFallHeight--; if (maxFallHeight < 0) { return(false); } } // Up ok? float height = entityCollBox.Height; while (height-- > 0) { tmpVec.Y++; if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { return(false); } } return(true); } else { tmpVec.Set(node.X + centerOffsetX, node.Y + stepHeight, node.Z + centerOffsetZ); bool collideAbove = api.World.CollisionTester.GetCollidingCollisionBox(blockAccess, entityCollBox, tmpVec, ref tmpCub, false); if (!collideAbove) { if (isDiagonal) { tmpPos.Set(node.X, node.Y, node.Z); Block block = blockAccess.GetBlock(tmpPos); Cuboidf[] collboxes = block.GetCollisionBoxes(blockAccess, tmpPos); if (collboxes != null && collboxes.Length > 0) { // Ok, can step on this block node.Y++; return(true); } } else { node.Y++; return(true); } } } return(false); }
public Vec3d loadNextWanderTarget() { int tries = 9; Vec4d bestTarget = null; Vec4d curTarget = new Vec4d(); BlockPos tmpPos = new BlockPos(); if (FailedConsecutivePathfinds > 10) { WanderRangeMul = Math.Max(0.1f, WanderRangeMul * 0.9f); } else { WanderRangeMul = Math.Min(1, WanderRangeMul * 1.1f); if (rand.NextDouble() < 0.05) { WanderRangeMul = Math.Min(1, WanderRangeMul * 1.5f); } } float wRangeMul = WanderRangeMul; double dx, dy, dz; if (rand.NextDouble() < 0.05) { wRangeMul *= 3; } while (tries-- > 0) { dx = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; dy = wanderRangeVertical.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; dz = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; curTarget.X = entity.ServerPos.X + dx; curTarget.Y = entity.ServerPos.Y + dy; curTarget.Z = entity.ServerPos.Z + dz; curTarget.W = 1; Block block; block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); if (!block.IsLiquid()) { curTarget.W = 0; } else { curTarget.W = 1 / (Math.Abs(dy) + 1); //prefer not too much vertical change when underwater } //TODO: reject (or de-weight) targets not in direct line of sight (avoiding terrain) if (preferredLightLevel != null && curTarget.W != 0) { tmpPos.Set((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); int lightdiff = Math.Abs((int)preferredLightLevel - entity.World.BlockAccessor.GetLightLevel(tmpPos, EnumLightLevelType.MaxLight)); curTarget.W /= Math.Max(1, lightdiff); } if (bestTarget == null || curTarget.W > bestTarget.W) { bestTarget = new Vec4d(curTarget.X, curTarget.Y, curTarget.Z, curTarget.W); if (curTarget.W >= 1.0) { break; //have a good enough target, no need for further tries } } } if (bestTarget.W > 0) { FailedConsecutivePathfinds = Math.Max(FailedConsecutivePathfinds - 3, 0); return(bestTarget.XYZ); } FailedConsecutivePathfinds++; return(null); }
public UpdateSnowLayerChunk UpdateSnowLayer(SnowAccumSnapshot sumsnapshot, bool ignoreOldAccum, IServerMapChunk mc, Vec2i chunkPos, IWorldChunk[] chunksCol) { UpdateSnowLayerChunk updateChunk = new UpdateSnowLayerChunk(); var layers = ws.GeneralConfig.SnowLayerBlocks; int chunkX = chunkPos.X; int chunkZ = chunkPos.Y; int regionX = (chunkX * chunksize) / regionsize; int regionZ = (chunkZ * chunksize) / regionsize; int regionBasePosX = regionX * regionsize; int regionBasePosZ = regionZ * regionsize; BlockPos pos = new BlockPos(); BlockPos placePos = new BlockPos(); float aboveSeaLevelHeight = sapi.World.BlockAccessor.MapSizeY - sapi.World.SeaLevel; int[] posIndices = randomShuffles[sapi.World.Rand.Next(randomShuffles.Length)]; int prevChunkY = -99999; IWorldChunk chunk = null; int maxY = sapi.World.BlockAccessor.MapSizeY - 1; for (int i = 0; i < posIndices.Length; i++) { int posIndex = posIndices[i]; int posY = GameMath.Clamp(mc.RainHeightMap[posIndex], 0, maxY); int chunkY = posY / chunksize; pos.Set( chunkX * chunksize + posIndex % chunksize, posY, chunkZ * chunksize + posIndex / chunksize ); if (prevChunkY != chunkY) { chunk = chunksCol?[chunkY] ?? sapi.WorldManager.GetChunk(chunkX, chunkY, chunkZ); prevChunkY = chunkY; } if (chunk == null) { return(null); } float relx = (pos.X - regionBasePosX) / (float)regionsize; float rely = GameMath.Clamp((pos.Y - sapi.World.SeaLevel) / aboveSeaLevelHeight, 0, 1); float relz = (pos.Z - regionBasePosZ) / (float)regionsize; // What needs to be done here? // 1. Get desired snow cover level // 2. Get current snow cover level // - Get topmmost block. Is it snow? // - Yes. Use it as reference pos and stuff // - No. Must have no snow, increment pos.Y by 1 // 3. Compare and place block accordingly // Idea: New method Block.UpdateSnowLayer() returns a new block instance if a block change is needed // What needs to be done here, take 2 // We have 3 possible cases per-block // 1: We find upside solid block. That means it has no snow on top // 2: We find snow. That means below is a solid block. // 3: We find some other block: That means we should try to find its snow-covered variant // We have the following input data // 1. Snow accumulation changes since the last update (usually an in-game hour or 2) // 2. A precise snow level value from the position (if not set, load from snowlayer block type) (set to zero if the snowlayer is removed) // 3. The current block at position, which is either // - A snow layer: Override with internal level + accum changes // - A solid block: Plase snow on top based on internal level + accum changes // - A snow variantable block: Call the method with the new level Block block = chunk.GetLocalLiquidOrBlockAtBlockPos(sapi.World, pos); float hereAccum = 0; Vec2i vec = new Vec2i(pos.X, pos.Z); if (!ignoreOldAccum && !mc.SnowAccum.TryGetValue(vec, out hereAccum)) { hereAccum = block.GetSnowLevel(pos); } float nowAccum = hereAccum + sumsnapshot.GetAvgSnowAccumByRegionCorner(relx, rely, relz); mc.SnowAccum[vec] = GameMath.Clamp(nowAccum, -1, ws.GeneralConfig.SnowLayerBlocks.Count + 0.6f); float hereShouldLevel = nowAccum - GameMath.MurmurHash3Mod(pos.X, 0, pos.Z, 150) / 300f; float shouldIndexf = GameMath.Clamp(hereShouldLevel - 1.1f, -1, ws.GeneralConfig.SnowLayerBlocks.Count - 1); int shouldIndex = shouldIndexf < 0 ? -1 : (int)shouldIndexf; placePos.Set(pos.X, Math.Min(pos.Y + 1, sapi.World.BlockAccessor.MapSizeY - 1), pos.Z); chunkY = placePos.Y / chunksize; if (prevChunkY != chunkY) { chunk = chunksCol?[chunkY] ?? sapi.WorldManager.GetChunk(chunkX, chunkY, chunkZ); prevChunkY = chunkY; } if (chunk == null) { return(null); } Block upBlock = chunk.GetLocalLiquidOrBlockAtBlockPos(sapi.World, placePos); // Case 1: We have a block that can become snow covered (or more snow covered) placePos.Set(pos); Block newblock = block.GetSnowCoveredVariant(placePos, hereShouldLevel); if (newblock != null) { if (block.Id != newblock.Id && upBlock.Replaceable > 6000) { updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(newblock, hereShouldLevel); } } // Case 2: We have a solid block that can have snow on top else if (block.AllowSnowCoverage(sapi.World, placePos)) { placePos.Set(pos.X, pos.Y + 1, pos.Z); if (upBlock.Id != 0) { newblock = upBlock.GetSnowCoveredVariant(placePos, hereShouldLevel); if (newblock != null && upBlock.Id != newblock.Id) { updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(newblock, hereShouldLevel); } continue; } if (shouldIndex >= 0) { Block toPlaceBlock = layers.GetKeyAtIndex(shouldIndex); updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(toPlaceBlock, hereShouldLevel); } } } return(updateChunk); }
public int[] GenerateChunkImage(Vec2i chunkPos, IMapChunk mc, bool withSnow = true) { ICoreClientAPI capi = api as ICoreClientAPI; //capi.Logger.Notification("GenImg @{0}/{1}", chunkPos.X, chunkPos.Y); BlockPos tmpPos = new BlockPos(); Vec2i localpos = new Vec2i(); // Prefetch chunks for (int cy = 0; cy < chunksTmp.Length; cy++) { chunksTmp[cy] = capi.World.BlockAccessor.GetChunk(chunkPos.X, cy, chunkPos.Y); if (chunksTmp[cy] == null) { return(null); } } // Prefetch map chunks IMapChunk[] mapChunks = new IMapChunk[] { capi.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y - 1), capi.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y), capi.World.BlockAccessor.GetMapChunk(chunkPos.X, chunkPos.Y - 1) }; int[] texDataTmp = new int[chunksize * chunksize]; for (int i = 0; i < texDataTmp.Length; i++) { int y = mc.RainHeightMap[i]; int cy = y / chunksize; if (cy >= chunksTmp.Length) { continue; } MapUtil.PosInt2d(i, chunksize, localpos); int lx = localpos.X; int lz = localpos.Y; float b = 1; int leftTop, rightTop, leftBot; IMapChunk leftTopMapChunk = mc; IMapChunk rightTopMapChunk = mc; IMapChunk leftBotMapChunk = mc; int topX = lx - 1; int botX = lx; int leftZ = lz - 1; int rightZ = lz; if (topX < 0 && leftZ < 0) { leftTopMapChunk = mapChunks[0]; rightTopMapChunk = mapChunks[1]; leftBotMapChunk = mapChunks[2]; } else { if (topX < 0) { leftTopMapChunk = mapChunks[1]; rightTopMapChunk = mapChunks[1]; } if (leftZ < 0) { leftTopMapChunk = mapChunks[2]; leftBotMapChunk = mapChunks[2]; } } topX = GameMath.Mod(topX, chunksize); leftZ = GameMath.Mod(leftZ, chunksize); leftTop = leftTopMapChunk == null ? 0 : Math.Sign(y - leftTopMapChunk.RainHeightMap[leftZ * chunksize + topX]); rightTop = rightTopMapChunk == null ? 0 : Math.Sign(y - rightTopMapChunk.RainHeightMap[rightZ * chunksize + topX]); leftBot = leftBotMapChunk == null ? 0 : Math.Sign(y - leftBotMapChunk.RainHeightMap[leftZ * chunksize + botX]); float slopeness = (leftTop + rightTop + leftBot); if (slopeness > 0) { b = 1.18f; } if (slopeness < 0) { b = 0.82f; } chunksTmp[cy].Unpack(); int blockId = chunksTmp[cy].Blocks[MapUtil.Index3d(localpos.X, y % chunksize, localpos.Y, chunksize, chunksize)]; Block block = api.World.Blocks[blockId]; /*if (i == 0) * { * capi.Logger.Notification("GenImg @{0}/{1}, first block is {2}", chunkPos.X, chunkPos.Y, block.Code); * }*/ if (!withSnow && block.BlockMaterial == EnumBlockMaterial.Snow) { y--; cy = y / chunksize; chunksTmp[cy].Unpack(); blockId = chunksTmp[cy].Blocks[MapUtil.Index3d(localpos.X, y % chunksize, localpos.Y, chunksize, chunksize)]; block = api.World.Blocks[blockId]; } tmpPos.Set(chunksize * chunkPos.X + localpos.X, y, chunksize * chunkPos.Y + localpos.Y); int avgCol = block.GetColor(capi, tmpPos); int rndCol = block.GetRandomColor(capi, tmpPos, BlockFacing.UP); // Add a bit of randomness to each pixel int col = ColorUtil.ColorOverlay(avgCol, rndCol, 0.2f); texDataTmp[i] = ColorUtil.ColorMultiply3Clamped(col, b) | 255 << 24; } for (int cy = 0; cy < chunksTmp.Length; cy++) { chunksTmp[cy] = null; } return(texDataTmp); }
/// <summary> /// Attempts to transform each block as they are placed in directions different from the schematic. /// </summary> /// <param name="worldForResolve"></param> /// <param name="aroundOrigin"></param> /// <param name="angle"></param> /// <param name="flipAxis"></param> public virtual void TransformWhilePacked(IWorldAccessor worldForResolve, EnumOrigin aroundOrigin, int angle, EnumAxis?flipAxis = null) { BlockPos curPos = new BlockPos(); BlockPos startPos = new BlockPos(1024, 1024, 1024); BlocksUnpacked.Clear(); BlockEntitiesUnpacked.Clear(); DecorsUnpacked.Clear(); EntitiesUnpacked.Clear(); angle = GameMath.Mod(angle, 360); for (int i = 0; i < Indices.Count; i++) { uint index = Indices[i]; int storedBlockid = BlockIds[i]; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); AssetLocation blockCode = BlockCodes[storedBlockid]; Block newBlock = worldForResolve.GetBlock(blockCode); if (newBlock == null) { BlockEntities.Remove(index); continue; } if (flipAxis != null) { if (flipAxis == EnumAxis.Y) { dy = SizeY - dy; AssetLocation newCode = newBlock.GetVerticallyFlippedBlockCode(); newBlock = worldForResolve.GetBlock(newCode); } if (flipAxis == EnumAxis.X) { dx = SizeX - dx; AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis); newBlock = worldForResolve.GetBlock(newCode); } if (flipAxis == EnumAxis.Z) { dz = SizeZ - dz; AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis); newBlock = worldForResolve.GetBlock(newCode); } } if (angle != 0) { AssetLocation newCode = newBlock.GetRotatedBlockCode(angle); newBlock = worldForResolve.GetBlock(newCode); } if (aroundOrigin != EnumOrigin.StartPos) { dx -= SizeX / 2; dz -= SizeZ / 2; } BlockPos pos = new BlockPos(dx, dy, dz); // 90 deg: // xNew = -yOld // yNew = xOld // 180 deg: // xNew = -xOld // yNew = -yOld // 270 deg: // xNew = yOld // yNew = -xOld switch (angle) { case 90: pos.Set(-dz, dy, dx); break; case 180: pos.Set(-dx, dy, -dz); break; case 270: pos.Set(dz, dy, -dx); break; } if (aroundOrigin != EnumOrigin.StartPos) { pos.X += SizeX / 2; pos.Z += SizeZ / 2; } BlocksUnpacked[pos] = newBlock.BlockId; } for (int i = 0; i < DecorIndices.Count; i++) { uint index = DecorIndices[i]; int storedBlockid = DecorIds[i]; byte faceIndex = (byte)(storedBlockid >> 24); if (faceIndex > 5) { continue; } BlockFacing face = BlockFacing.ALLFACES[faceIndex]; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); AssetLocation blockCode = BlockCodes[storedBlockid & 0xFFFFFF]; Block newBlock = worldForResolve.GetBlock(blockCode); if (newBlock == null) { continue; } if (flipAxis != null) { if (flipAxis == EnumAxis.Y) { dy = SizeY - dy; AssetLocation newCode = newBlock.GetVerticallyFlippedBlockCode(); newBlock = worldForResolve.GetBlock(newCode); if (face.IsVertical) { face = face.Opposite; } } if (flipAxis == EnumAxis.X) { dx = SizeX - dx; AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis); newBlock = worldForResolve.GetBlock(newCode); if (face.Axis == EnumAxis.X) { face = face.Opposite; } } if (flipAxis == EnumAxis.Z) { dz = SizeZ - dz; AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis); newBlock = worldForResolve.GetBlock(newCode); if (face.Axis == EnumAxis.Z) { face = face.Opposite; } } } if (angle != 0) { AssetLocation newCode = newBlock.GetRotatedBlockCode(angle); newBlock = worldForResolve.GetBlock(newCode); } if (aroundOrigin != EnumOrigin.StartPos) { dx -= SizeX / 2; dz -= SizeZ / 2; } BlockPos pos = new BlockPos(dx, dy, dz); // 90 deg: // xNew = -yOld // yNew = xOld // 180 deg: // xNew = -xOld // yNew = -yOld // 270 deg: // xNew = yOld // yNew = -xOld switch (angle) { case 90: pos.Set(-dz, dy, dx); if (face.IsHorizontal) { face = face.GetCW(); } break; case 180: pos.Set(-dx, dy, -dz); if (face.IsHorizontal) { face = face.Opposite; } break; case 270: pos.Set(dz, dy, -dx); if (face.IsHorizontal) { face = face.GetCCW(); } break; } if (aroundOrigin != EnumOrigin.StartPos) { pos.X += SizeX / 2; pos.Z += SizeZ / 2; } DecorsUnpacked.TryGetValue(pos, out Block[] decorsTmp); if (decorsTmp == null) { decorsTmp = new Block[6]; DecorsUnpacked[pos] = decorsTmp; } decorsTmp[face.Index] = newBlock; } foreach (var val in BlockEntities) { uint index = val.Key; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); dx -= SizeX / 2; dz -= SizeZ / 2; BlockPos pos = new BlockPos(dx, dy, dz); // 90 deg: // xNew = -yOld // yNew = xOld // 180 deg: // xNew = -xOld // yNew = -yOld // 270 deg: // xNew = yOld // yNew = -xOld switch (angle) { case 90: pos.Set(-dz, dy, dx); break; case 180: pos.Set(-dx, dy, -dz); break; case 270: pos.Set(dz, dy, -dx); break; } pos.X += SizeX / 2; pos.Z += SizeZ / 2; curPos.Set(pos.X + startPos.X, pos.Y + startPos.Y, pos.Z + startPos.Z); string beData = val.Value; string entityclass = worldForResolve.GetBlock(BlocksUnpacked[pos]).EntityClass; if (entityclass != null) { BlockEntity be = worldForResolve.ClassRegistry.CreateBlockEntity(entityclass); if (be is IBlockEntityRotatable) { ITreeAttribute tree = DecodeBlockEntityData(beData); (be as IBlockEntityRotatable).OnTransformed(tree, angle, flipAxis); beData = StringEncodeTreeAttribute(tree); } BlockEntitiesUnpacked[pos] = beData; } } foreach (string entityData in Entities) { using (MemoryStream ms = new MemoryStream(Ascii85.Decode(entityData))) { BinaryReader reader = new BinaryReader(ms); string className = reader.ReadString(); Entity entity = worldForResolve.ClassRegistry.CreateEntity(className); entity.FromBytes(reader, false); entity.DidImportOrExport(startPos); double dx = entity.ServerPos.X - startPos.X; double dy = entity.ServerPos.Y - startPos.Y; double dz = entity.ServerPos.Z - startPos.Z; dx -= SizeX / 2; dz -= SizeZ / 2; Vec3d pos = new Vec3d(); // 90 deg: // xNew = -yOld // yNew = xOld // 180 deg: // xNew = -xOld // yNew = -yOld // 270 deg: // xNew = yOld // yNew = -xOld switch (angle) { case 90: pos.Set(-dz, dy, dx); break; case 180: pos.Set(-dx, dy, -dz); break; case 270: pos.Set(dz, dy, -dx); break; } pos.X += SizeX / 2; pos.Z += SizeZ / 2; entity.ServerPos.SetPos(startPos.X + pos.X, entity.ServerPos.Y, startPos.Z + pos.Z); entity.Pos.SetPos(startPos.X + pos.X, entity.Pos.Y, startPos.Z + pos.Z); entity.PositionBeforeFalling.Set(startPos.X + pos.X, entity.PositionBeforeFalling.Y, startPos.Z + pos.Z); EntitiesUnpacked.Add(entity); } } Pack(worldForResolve, startPos); }
public override void OnGameTick(float dt) { base.OnGameTick(dt); if (Itemstack != null) { if (!Collided && !Swimming && World.Side == EnumAppSide.Server) { getWindSpeedAccum += dt; if (getWindSpeedAccum > 0.25) { getWindSpeedAccum = 0; tmpPos.Set(Pos.XInt, Pos.YInt, Pos.ZInt); windSpeed = World.BlockAccessor.GetWindSpeedAt(tmpPos); windSpeed.X = Math.Max(0, Math.Abs(windSpeed.X) - windLoss) * Math.Sign(windSpeed.X); windSpeed.Y = Math.Max(0, Math.Abs(windSpeed.Y) - windLoss) * Math.Sign(windSpeed.Y); windSpeed.Z = Math.Max(0, Math.Abs(windSpeed.Z) - windLoss) * Math.Sign(windSpeed.Z); } float fac = GameMath.Clamp(1000f / Itemstack.Collectible.MaterialDensity, 1f, 10); SidedPos.Motion.X += windSpeed.X / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.X)), 0, 1); SidedPos.Motion.Y += windSpeed.Y / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.Y)), 0, 1); SidedPos.Motion.Z += windSpeed.Z / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.Z)), 0, 1); } Itemstack.Collectible.OnGroundIdle(this); if (FeetInLiquid && !InLava) { float temp = Itemstack.Collectible.GetTemperature(World, Itemstack); if (temp > 20) { Itemstack.Collectible.SetTemperature(World, Itemstack, Math.Max(20, temp - 5)); if (temp > 90) { SplashParticleProps.BasePos.Set(Pos.X, Pos.Y, Pos.Z); SplashParticleProps.AddVelocity.Set(0, 0, 0); SplashParticleProps.QuantityMul = 0.1f; World.SpawnParticles(SplashParticleProps); } if (temp > 200 && World.Side == EnumAppSide.Client && World.ElapsedMilliseconds - lastPlayedSizzlesTotalMs > 10000) { World.PlaySoundAt(new AssetLocation("sounds/sizzle"), this, null); lastPlayedSizzlesTotalMs = World.ElapsedMilliseconds; } } } /*if (!FeetInLiquid && !InLava && Api.World.Rand.NextDouble() < 0.1f && Api.World.Side == EnumAppSide.Server) * { * // Die on rainfall * WeatherSystemBase wsys; * wsys = api.ModLoader.GetModSystem<WeatherSystemBase>(); * BlockPos tmpPos = new BlockPos(Pos.X + 0.5, Pos.Y + 0.5, Pos.Z + 0.5); * double rainLevel = wsys.GetRainFall(tmpPos); * if (rainLevel > 0.04 && Api.World.Rand.NextDouble() < rainLevel * 5) * { * if (Api.World.BlockAccessor.GetRainMapHeightAt(Pos.X, Pos.Z) > Pos.Y) return; * * Api.World.PlaySoundAt(new AssetLocation("sounds/effect/extinguish"), Pos.X + 0.5, Pos.Y, Pos.Z + 0.5, null, false, 16); * * fuelBurnTime -= (float)rainLevel / 10f; * * if (Api.World.Rand.NextDouble() < rainLevel / 5f || fuelBurnTime <= 0) * { * setBlockState("cold"); * extinguishedTotalHours = -99; * canIgniteFuel = false; * fuelBurnTime = 0; * maxFuelBurnTime = 0; * } * * MarkDirty(true); * } * }*/ } else { Die(); } }
/// <summary> /// Places all the entities and blocks in the schematic at the position. /// </summary> /// <param name="blockAccessor"></param> /// <param name="worldForCollectibleResolve"></param> /// <param name="startPos"></param> public void PlaceEntitiesAndBlockEntities(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos) { BlockPos curPos = new BlockPos(); int schematicSeed = worldForCollectibleResolve.Rand.Next(); foreach (var val in BlockEntities) { uint index = val.Key; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z); BlockEntity be = blockAccessor.GetBlockEntity(curPos); // Block entities need to be manually initialized for world gen block access if (be == null && blockAccessor is IWorldGenBlockAccessor) { Block block = blockAccessor.GetBlock(curPos); if (block.EntityClass != null) { blockAccessor.SpawnBlockEntity(block.EntityClass, curPos); be = blockAccessor.GetBlockEntity(curPos); } } if (be != null) { Block block = blockAccessor.GetBlock(curPos); if (block.EntityClass != worldForCollectibleResolve.ClassRegistry.GetBlockEntityClass(be.GetType())) { worldForCollectibleResolve.Logger.Warning("Could not import block entity data for schematic at {0}. There is already {1}, expected {2}. Probably overlapping ruins.", curPos, be.GetType(), block.EntityClass); continue; } ITreeAttribute tree = DecodeBlockEntityData(val.Value); tree.SetInt("posx", curPos.X); tree.SetInt("posy", curPos.Y); tree.SetInt("posz", curPos.Z); be.FromTreeAttributes(tree, worldForCollectibleResolve); be.OnLoadCollectibleMappings(worldForCollectibleResolve, BlockCodes, ItemCodes, schematicSeed); be.Pos = curPos.Copy(); } } foreach (string entityData in Entities) { using (MemoryStream ms = new MemoryStream(Ascii85.Decode(entityData))) { BinaryReader reader = new BinaryReader(ms); string className = reader.ReadString(); Entity entity = worldForCollectibleResolve.ClassRegistry.CreateEntity(className); entity.FromBytes(reader, false); entity.DidImportOrExport(startPos); // Not ideal but whatever if (blockAccessor is IWorldGenBlockAccessor) { (blockAccessor as IWorldGenBlockAccessor).AddEntity(entity); } else { worldForCollectibleResolve.SpawnEntity(entity); } } } }
/// <summary> /// Updates the velocity vector according to the amount of passed time, gravity and terrain collision. /// </summary> /// <param name="pos"></param> /// <param name="motion"></param> /// <param name="size"></param> /// <returns></returns> public EnumCollideFlags UpdateMotion(Vec3d pos, Vec3f motion, float size) { particleCollBox.Set( pos.X - size / 2, pos.Y - 0 / 2, pos.Z - size / 2, pos.X + size / 2, pos.Y + size / 2, pos.Z + size / 2 ); motion.X = GameMath.Clamp(motion.X, -MotionCap, MotionCap); motion.Y = GameMath.Clamp(motion.Y, -MotionCap, MotionCap); motion.Z = GameMath.Clamp(motion.Z, -MotionCap, MotionCap); EnumCollideFlags flags = 0; minPos.Set( (int)(particleCollBox.X1 + Math.Min(0, motion.X)), (int)(particleCollBox.Y1 + Math.Min(0, motion.Y) - 1), // -1 for the extra high collision box of fences (int)(particleCollBox.Z1 + Math.Min(0, motion.Z)) ); maxPos.Set( (int)(particleCollBox.X2 + Math.Max(0, motion.X)), (int)(particleCollBox.Y2 + Math.Max(0, motion.Y)), (int)(particleCollBox.Z2 + Math.Max(0, motion.Z)) ); CollisionBoxList.Clear(); BlockAccess.WalkBlocks(minPos, maxPos, (cblock, bpos) => { Cuboidf[] collisionBoxes = cblock.GetParticleCollisionBoxes(BlockAccess, bpos); for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++) { CollisionBoxList.Add(collisionBoxes[i], bpos, cblock); } }, false); // Y - Collision (Vertical) EnumPushDirection pushDirection = EnumPushDirection.None; for (int i = 0; i < CollisionBoxList.Count; i++) { blockCollBox = CollisionBoxList.cuboids[i]; motion.Y = (float)blockCollBox.pushOutY(particleCollBox, motion.Y, ref pushDirection); if (pushDirection != EnumPushDirection.None) { flags |= EnumCollideFlags.CollideY; } } particleCollBox.Translate(0, motion.Y, 0); // X - Collision (Horizontal) for (int i = 0; i < CollisionBoxList.Count; i++) { blockCollBox = CollisionBoxList.cuboids[i]; motion.X = (float)blockCollBox.pushOutX(particleCollBox, motion.X, ref pushDirection); if (pushDirection != EnumPushDirection.None) { flags |= EnumCollideFlags.CollideX; } } particleCollBox.Translate(motion.X, 0, 0); // Z - Collision (Horizontal) for (int i = 0; i < CollisionBoxList.Count; i++) { blockCollBox = CollisionBoxList.cuboids[i]; motion.Z = (float)blockCollBox.pushOutZ(particleCollBox, motion.Z, ref pushDirection); if (pushDirection != EnumPushDirection.None) { flags |= EnumCollideFlags.CollideZ; } } return(flags); }
public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt) { IBlockAccessor blockAccess = entity.World.BlockAccessor; nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z); bool falling = pos.Motion.Y < 0; bool feetInLiquidBefore = entity.FeetInLiquid; bool onGroundBefore = entity.OnGround; bool swimmingBefore = entity.Swimming; double prevYMotion = pos.Motion.Y; controls.IsClimbing = false; if (!onGroundBefore && entity.Properties.CanClimb == true) { int height = (int)Math.Ceiling(entity.CollisionBox.Y2); entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z); for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int i = 0; i < collBoxes.Length; i++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = null; break; } } } for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++) { BlockFacing facing = BlockFacing.HORIZONTALS[i]; for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int j = 0; j < collBoxes.Length; j++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = facing; break; } } } } } if (controls.IsClimbing) { if (controls.WalkVector.Y == 0) { pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y; if (controls.Jump) { pos.Motion.Y = 0.04; } } nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z); } collisionTester.ApplyTerrainCollision(entity, pos, ref outposition, !(entity is EntityPlayer)); bool isStepping = HandleSteppingOnBlocks(pos, controls); HandleSneaking(pos, controls, dt); if (blockAccess.IsNotTraversable((int)(pos.X + pos.Motion.X), (int)pos.Y, (int)pos.Z)) { outposition.X = pos.X; } if (blockAccess.IsNotTraversable((int)pos.X, (int)(pos.Y + pos.Motion.Y), (int)pos.Z)) { outposition.Y = pos.Y; } if (blockAccess.IsNotTraversable((int)pos.X, (int)pos.Y, (int)(pos.Z + pos.Motion.Z))) { outposition.Z = pos.Z; } pos.SetPos(outposition); // Set the players motion to zero if he collided. if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0)) { pos.Motion.X = 0; } if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0)) { pos.Motion.Y = 0; } if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0)) { pos.Motion.Z = 0; } Block block = blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z); Block aboveblock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z); Block middleBlock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + entity.CollisionBox.Y1 + entity.CollisionBox.Y2 * 0.66f), (int)pos.Z); entity.OnGround = (entity.CollidedVertically && falling && !controls.IsClimbing) || isStepping; entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y); entity.Swimming = middleBlock.IsLiquid(); // Console.WriteLine(entity.World.Side + ": "+ entity.OnGround + " / " + pos.Y); if (!onGroundBefore && entity.OnGround) { entity.OnFallToGround(prevYMotion); } if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming)) { entity.OnCollideWithLiquid(); } if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming)) { entity.OnExitedLiquid(); } if (!falling || entity.OnGround || controls.IsClimbing) { entity.PositionBeforeFalling.Set(outposition); } Cuboidd testedEntityBox = collisionTester.entityBox; for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++) { for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++) { for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++) { collisionTester.tmpPos.Set(x, y, z); collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1); if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox)) { // Saves us a few cpu cycles if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z) { block.OnEntityInside(entity.World, entity, collisionTester.tmpPos); continue; } blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos); } } } } }
public void HandleBoyancy(Vec3d pos, Vec3f velocity, bool boyant, float gravityStrength, float deltatime, float height) { int xPrev = (int)pos.X; int yPrev = (int)pos.Y; int zPrev = (int)pos.Z; tmpPos.Set(xPrev, yPrev, zPrev); Block block = BlockAccess.GetBlock(tmpPos); Block prevBlock = block; if (block == null) { return; } if (boyant) { if (block.IsLiquid()) { tmpPos.Set(xPrev, (int)(pos.Y + 1), zPrev); block = BlockAccess.GetBlock(tmpPos); if (block == null) { return; } float waterY = (int)pos.Y + prevBlock.LiquidLevel / 8f + (block.IsLiquid() ? 9 / 8f : 0); float bottomSubmergedness = waterY - (float)pos.Y; float swimlineSubmergedness = GameMath.Clamp(bottomSubmergedness + height, 0, 1); float boyancyStrength = GameMath.Clamp(9 * swimlineSubmergedness, -1.25f, 1.25f); // was 3* before. Dunno why it has to be 9* now velocity.Y += gravityStrength * deltatime * boyancyStrength; float waterDrag = (float)GameMath.Clamp(30 * Math.Abs(velocity.Y) - 0.02f, 1, 1.25f); velocity.Y /= waterDrag; velocity.X *= 0.99f; velocity.Z *= 0.99f; if (prevBlock.PushVector != null && swimlineSubmergedness >= 0) { float factor = deltatime / (33f / 1000f); velocity.Add( (float)prevBlock.PushVector.X * 15 * factor, (float)prevBlock.PushVector.Y * 15 * factor, (float)prevBlock.PushVector.Z * 15 * factor ); } } } else { if (block.PushVector != null) { velocity.Add( (float)block.PushVector.X * 30 * deltatime, (float)block.PushVector.Y * 30 * deltatime, (float)block.PushVector.Z * 30 * deltatime ); } } }
// Requirements: // - ✔ Try to not move a lot vertically // - ✔ If territorial: Stay close to the spawn point // - ✔ If air habitat: Don't go above maxHeight blocks above surface // - ✔ If land habitat: Don't walk into water, prefer surface // - ~~If cave habitat: Prefer caves~~ // - ✔ If water habitat: Don't walk onto land // - ✔ Try not to fall from very large heights. Try not to fall from any large heights if entity has FallDamage // - ✔ Prefer preferredLightLevel // - ✔ If land habitat: Must be above a block the entity can stand on // - ✔ if failed searches is high, reduce wander range public Vec3d loadNextWanderTarget() { EnumHabitat habitat = entity.Properties.Habitat; bool canFallDamage = entity.Properties.FallDamage; bool territorial = StayCloseToSpawn; int tries = 9; Vec4d bestTarget = null; Vec4d curTarget = new Vec4d(); BlockPos tmpPos = new BlockPos(); if (FailedConsecutivePathfinds > 10) { WanderRangeMul = Math.Max(0.1f, WanderRangeMul * 0.9f); } else { WanderRangeMul = Math.Min(1, WanderRangeMul * 1.1f); if (rand.NextDouble() < 0.05) { WanderRangeMul = Math.Min(1, WanderRangeMul * 1.5f); } } float wRangeMul = WanderRangeMul; double dx, dy, dz; if (rand.NextDouble() < 0.05) { wRangeMul *= 3; } while (tries-- > 0) { dx = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; dy = wanderRangeVertical.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; dz = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul; curTarget.X = entity.ServerPos.X + dx; curTarget.Y = entity.ServerPos.Y + dy; curTarget.Z = entity.ServerPos.Z + dz; curTarget.W = 1; if (StayCloseToSpawn) { double distToEdge = curTarget.SquareDistanceTo(SpawnPosition) / (MaxDistanceToSpawn * MaxDistanceToSpawn); // Prefer staying close to spawn curTarget.W = 1 - distToEdge; } Block block; switch (habitat) { case EnumHabitat.Air: int rainMapY = world.BlockAccessor.GetRainMapHeightAt((int)curTarget.X, (int)curTarget.Z); // Don't fly above max height curTarget.Y = Math.Min(curTarget.Y, rainMapY + maxHeight); // Cannot be in water block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); if (block.IsLiquid()) { curTarget.W = 0; } break; case EnumHabitat.Land: curTarget.Y = moveDownToFloor((int)curTarget.X, curTarget.Y, (int)curTarget.Z); // No floor found if (curTarget.Y < 0) { curTarget.W = 0; } else { // Does not like water block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); if (block.IsLiquid()) { curTarget.W /= 2; } // Lets make a straight line plot to see if we would fall off a cliff bool stop = false; bool willFall = false; float angleHor = (float)Math.Atan2(dx, dz) + GameMath.PIHALF; Vec3d target1BlockAhead = curTarget.XYZ.Ahead(1, 0, angleHor); Vec3d startAhead = entity.ServerPos.XYZ.Ahead(1, 0, angleHor); // Otherwise they are forever stuck if they stand over the edge int prevY = (int)startAhead.Y; GameMath.BresenHamPlotLine2d((int)startAhead.X, (int)startAhead.Z, (int)target1BlockAhead.X, (int)target1BlockAhead.Z, (x, z) => { if (stop) { return; } double nowY = moveDownToFloor(x, prevY, z); // Not more than 4 blocks down if (nowY < 0 || prevY - nowY > 4) { willFall = true; stop = true; } // Not more than 2 blocks up if (nowY - prevY > 2) { stop = true; } prevY = (int)nowY; }); if (willFall) { curTarget.W = 0; } } break; case EnumHabitat.Sea: block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); if (!block.IsLiquid()) { curTarget.W = 0; } break; } if (curTarget.W > 0) { // Try to not hug the wall so much for (int i = 0; i < BlockFacing.HORIZONTALS.Length; i++) { BlockFacing face = BlockFacing.HORIZONTALS[i]; block = entity.World.BlockAccessor.GetBlock((int)curTarget.X + face.Normali.X, (int)curTarget.Y, (int)curTarget.Z + face.Normali.Z); if (block.SideSolid[face.Opposite.Index]) { curTarget.W *= 0.5; } } } if (preferredLightLevel != null) { tmpPos.Set((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z); int lightdiff = Math.Abs((int)preferredLightLevel - entity.World.BlockAccessor.GetLightLevel(tmpPos, EnumLightLevelType.MaxLight)); curTarget.W /= Math.Max(1, lightdiff); } if (bestTarget == null || curTarget.W > bestTarget.W) { bestTarget = new Vec4d(curTarget.X, curTarget.Y, curTarget.Z, curTarget.W); } } if (bestTarget.W > 0) { //double bla = bestTarget.Y; //bestTarget.Y += 1; //dx = bestTarget.X - entity.ServerPos.X; //dz = bestTarget.Z - entity.ServerPos.Z; //Vec3d sadf = bestTarget.XYZ.Ahead(1, 0, (float)Math.Atan2(dx, dz) + GameMath.PIHALF); /*(entity.Api as ICoreServerAPI).World.HighlightBlocks(world.AllOnlinePlayers[0], 10, new List<BlockPos>() { * new BlockPos((int)bestTarget.X, (int)bestTarget.Y, (int)bestTarget.Z) }, new List<int>() { ColorUtil.ColorFromRgba(0, 255, 0, 80) }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary); * (entity.Api as ICoreServerAPI).World.HighlightBlocks(world.AllOnlinePlayers[0], 11, new List<BlockPos>() { * new BlockPos((int)sadf.X, (int)sadf.Y, (int)sadf.Z) }, new List<int>() { ColorUtil.ColorFromRgba(0, 255, 255, 180) }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);*/ //bestTarget.Y = bla; FailedConsecutivePathfinds = Math.Max(FailedConsecutivePathfinds - 3, 0); return(bestTarget.XYZ); } FailedConsecutivePathfinds++; return(null); }
/// <summary> /// forceInitialPosY is for subdeposits /// </summary> /// <param name="chunks"></param> /// <param name="chunkX"></param> /// <param name="chunkZ"></param> /// <param name="offsetX"></param> /// <param name="offsetZ"></param> /// <param name="variant"></param> /// <param name="forceInitialPosY"></param> /// <returns></returns> Dictionary <Vec3i, DepositVariant> GenDeposit(IServerChunk[] chunks, int chunkX, int chunkZ, int offsetX, int offsetZ, DepositVariant variant, int?forceInitialPosY = null) { Dictionary <Vec3i, DepositVariant> SubDepositsToPlace = new Dictionary <Vec3i, DepositVariant>(); IMapChunk mapchunk = chunks[0].MapChunk; int radius = Math.Min(64, (int)variant.Radius.nextFloat(1, depositRand)); if (radius <= 0) { return(SubDepositsToPlace); } // Let's deform that perfect circle a bit (+/- 25%) float deform = GameMath.Clamp(depositRand.NextFloat() - 0.5f, -0.25f, 0.25f); int radiusX = radius - (int)(radius * deform); int radiusZ = radius + (int)(radius * deform); int posY; // No need to caluclate further if this deposit won't be part of this chunk if (radiusX + offsetX < 0 || radiusZ + offsetZ < 0 || offsetX - radiusX >= chunksize || offsetZ - radiusZ >= chunksize) { return(SubDepositsToPlace); } IMapChunk originMapchunk = null; int origPosY = 0; int lx = GameMath.Mod(offsetX, chunksize); int lz = GameMath.Mod(offsetZ, chunksize); if (variant.MaxY < 1 || variant.CheckClimate) { originMapchunk = api.WorldManager.GetMapChunk((chunkX * chunksize + offsetX) / chunksize, (chunkZ * chunksize + offsetZ) / chunksize); if (originMapchunk == null) { return(SubDepositsToPlace); // argh >.< } origPosY = originMapchunk.RainHeightMap[lz * chunksize + lx]; if ((float)origPosY / api.World.BlockAccessor.MapSizeY > variant.MaxY) { return(SubDepositsToPlace); } } // Check if suited for this area, climate wise if (variant.CheckClimate) { IntMap climateMap = api.World.BlockAccessor.GetMapRegion((chunkX * chunksize + offsetX) / regionSize, (chunkZ * chunksize + offsetZ) / regionSize).ClimateMap; float posXInRegionClimate = ((float)lx / regionSize - lx / regionSize) * noiseSizeClimate; float posZInRegionClimate = ((float)lz / regionSize - lz / regionSize) * noiseSizeClimate; int climate = climateMap.GetUnpaddedColorLerped(posXInRegionClimate, posZInRegionClimate); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, origPosY - TerraGenConfig.seaLevel); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, origPosY) / 255f; if (rainRel < variant.MinRain || rainRel > variant.MaxRain || temp < variant.MinTemp || temp > variant.MaxTemp) { return(SubDepositsToPlace); } } // Ok generate float th = variant.Thickness.nextFloat(1, depositRand); int thickness = (int)th + (depositRand.NextFloat() < th - (int)th ? 1 : 0); float xRadSqInv = 1f / (radiusX * radiusX); float zRadSqInv = 1f / (radiusZ * radiusZ); int blockIndex = 0; bool parentBlockOk = false; float depthf; bool shouldGenSurfaceDeposit = depositRand.NextFloat() > 0.35f && variant.SurfaceBlockCode != null; if (forceInitialPosY != null) { depthf = (float)forceInitialPosY / mapchunk.WorldGenTerrainHeightMap[offsetX * chunksize + offsetZ]; } else { depthf = variant.Depth.nextFloat(1, depositRand); } int depthi = (int)depthf; int topLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int topRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int botLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int botRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int yOff = 0; // Only generate inside this current chunk column int minx = GameMath.Clamp(offsetX - radiusX, 0, chunksize); int maxx = GameMath.Clamp(offsetX + radiusX, 0, chunksize); int minz = GameMath.Clamp(offsetZ - radiusZ, 0, chunksize); int maxz = GameMath.Clamp(offsetZ + radiusZ, 0, chunksize); float invChunkAreaSize = 1f / (chunksize * chunksize); for (int x = minx; x < maxx; x++) { float xSq = (x - offsetX) * (x - offsetX) * xRadSqInv; for (int z = minz; z < maxz; z++) { if (xSq + (z - offsetZ) * (z - offsetZ) * zRadSqInv > 1) { continue; } if (variant.Placement == EnumDepositPlacement.FollowSurfaceBelow) { posY = mapchunk.WorldGenTerrainHeightMap[z * chunksize + x] - depthi; } else if (variant.Placement == EnumDepositPlacement.FollowSurface) { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]) + yOff / 2; } else if (variant.Placement == EnumDepositPlacement.Straight) { posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]); } else { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = depthi + yOff; } // Some deposits may not appear all over cliffs if (variant.CheckClimate && Math.Abs(origPosY - posY) > variant.MaxYRoughness) { continue; } for (int y = 0; y < thickness; y++) { if (posY <= 1 || posY >= worldheight) { continue; } long index3d = ((posY % chunksize) * chunksize + z) * chunksize + x; ushort blockId = chunks[posY / chunksize].Blocks[index3d]; // Check if we are in mother material, but only if it has changed since last iteration (should reduce amount of these checks by 50-100%) parentBlockOk = false; for (int i = 0; i < variant.ParentBlockIds.Length; i++) { if (variant.ParentBlockIds[i] == blockId) { parentBlockOk = true; blockIndex = i; break; } } if (parentBlockOk) { if (variant.WithBlockCallback) { tmpPos.Set(chunkX * chunksize + x, posY, chunkZ * chunksize + z); blockTypes[variant.BlockIds[blockIndex]].TryPlaceBlockForWorldGen(blockAccessor, tmpPos, BlockFacing.UP); } else { chunks[posY / chunksize].Blocks[index3d] = variant.BlockIds[blockIndex]; } for (int i = 0; i < variant.ChildDeposits.Length; i++) { float rndVal = depositRand.NextFloat(); float quantity = variant.ChildDeposits[i].Quantity * invChunkAreaSize; if (quantity > rndVal) { Vec3i pos = new Vec3i(x, posY, z); if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], chunkX * chunksize + x, chunkZ * chunksize + z, quantity, rndVal)) { SubDepositsToPlace[pos] = variant.ChildDeposits[i]; } } } if (shouldGenSurfaceDeposit) { int surfaceY = mapchunk.RainHeightMap[z * chunksize + x]; int depth = surfaceY - posY; float chance = variant.SurfaceBlockChance * Math.Max(0, 1 - depth / 8f); if (depositRand.NextFloat() < chance) { index3d = (((surfaceY + 1) % chunksize) * chunksize + z) * chunksize + x; Block belowBlock = api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + z) * chunksize + x]]; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0) { chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = variant.SurfaceBlockIds[blockIndex]; } } } } posY--; } } } return(SubDepositsToPlace); }
public override bool ShouldExecute() { if (rand.NextDouble() > searchFrequency) { return(false); } reason = EnumRestReason.NoReason; float dayLightStrength = entity.World.Calendar.GetDayLightStrength(entity.Pos.X, entity.Pos.Z); if (cooldownUntilTotalHours < entity.World.Calendar.TotalHours) { reason = EnumRestReason.TakingABreak; } else if (dayLightStrength < 0.6) { // Hardcoded: Rest at night reason = EnumRestReason.Night; } else if (wsys?.WeatherDataSlowAccess.GetWindSpeed(entity.ServerPos.XYZ) > 0.75 || wsys?.GetPrecipitation(entity.ServerPos.XYZ) > 0.1) { // Hardcoded: Rest during heavy winds or during rain reason = EnumRestReason.Wind; } if (reason == EnumRestReason.NoReason) { return(false); } double dx = rand.NextDouble() * 4 - 2; double dz = rand.NextDouble() * 4 - 2; for (int i = 1; i >= 0; i--) { tmpPos.Set((int)(entity.ServerPos.X + dx), 0, (int)(entity.ServerPos.Z + dz)); tmpPos.Y = entity.World.BlockAccessor.GetTerrainMapheightAt(tmpPos) + i; Block block = entity.World.BlockAccessor.GetBlock(tmpPos); if (block.IsLiquid()) { return(false); } bool weak = block.VertexFlags?.WindMode == EnumWindBitMode.WeakWind || block.VertexFlags?.WindMode == EnumWindBitMode.TallBend; if (block.Attributes?.IsTrue("butterflyFeed") == true) { double topPos = block.Attributes["sitHeight"].AsDouble(block.TopMiddlePos.Y); entity.WatchedAttributes.SetDouble("windWaveIntensity", block.VertexFlags.WindMode != EnumWindBitMode.NoWind ? (weak ? topPos / 2 : topPos) : 0); MainTarget = tmpPos.ToVec3d().Add(block.TopMiddlePos.X, topPos, block.TopMiddlePos.Z); return(true); } if (block.SideSolid[BlockFacing.UP.Index]) { double topPos = block.TopMiddlePos.Y; entity.WatchedAttributes.SetDouble("windWaveIntensity", block.VertexFlags?.WindMode != EnumWindBitMode.NoWind ? (weak ? topPos / 2 : topPos) : 0); MainTarget = tmpPos.ToVec3d().Add(block.TopMiddlePos.X, topPos - 1, block.TopMiddlePos.Z); return(true); } } return(false); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { IMapChunk mapChunk = chunks[0].MapChunk; IntMap forestMap = mapChunk.MapRegion.ForestMap; IntMap shrubMap = mapChunk.MapRegion.ShrubMap; IntMap climateMap = mapChunk.MapRegion.ClimateMap; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; float facS = (float)shrubMap.InnerSize / regionChunkSize; shrubUpLeft = shrubMap.GetUnpaddedInt((int)(rlX * facS), (int)(rlZ * facS)); shrubUpRight = shrubMap.GetUnpaddedInt((int)(rlX * facS + facS), (int)(rlZ * facS)); shrubBotLeft = shrubMap.GetUnpaddedInt((int)(rlX * facS), (int)(rlZ * facS + facS)); shrubBotRight = shrubMap.GetUnpaddedInt((int)(rlX * facS + facS), (int)(rlZ * facS + facS)); // A region has 16 chunks // Size of the forest map is RegionSize / TerraGenConfig.forestMapScale => 32*16 / 32 = 16 pixel // rlX, rlZ goes from 0..16 pixel // facF = 16/16 = 1 // Get 4 pixels for chunkx, chunkz, chunkx+1 and chunkz+1 inside the map float facF = (float)forestMap.InnerSize / regionChunkSize; forestUpLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF)); forestUpRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF)); forestBotLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF)); forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF)); float facC = (float)climateMap.InnerSize / regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC)); heightmap = chunks[0].MapChunk.RainHeightMap; structuresIntersectingChunk.Clear(); api.World.BlockAccessor.WalkStructures(chunkBase.Set(chunkX * chunksize, 0, chunkZ * chunksize), chunkend.Set(chunkX * chunksize + chunksize, chunkMapSizeY * chunksize, chunkZ * chunksize + chunksize), (struc) => { if (struc.Code.StartsWith("trader")) { structuresIntersectingChunk.Add(struc); } }); if (TerraGenConfig.GenerateVegetation) { genPatches(chunkX, chunkZ, false); genShrubs(chunkX, chunkZ); genTrees(chunkX, chunkZ); genPatches(chunkX, chunkZ, true); } }
internal bool TryGenerateRuinAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int chunksize = blockAccessor.ChunkSize; int climate = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int num = rand.NextInt(schematicDatas.Length); int orient = rand.NextInt(4); BlockSchematicStructure schematic = schematicDatas[num][orient]; int widthHalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f); // Probe all 4 corners + center if they either touch the surface or are sightly below ground int centerY = blockAccessor.GetTerrainMapheightAt(pos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf); int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf); int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf); int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf); int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); int maxY = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY); int minY = GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY); int diff = Math.Abs(maxY - minY); if (diff > 3) { return(false); } pos.Y = minY; // Ensure not deeply submerged in water tmpPos.Set(pos.X - widthHalf, pos.Y + 1 + OffsetY, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1 + OffsetY, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1 + OffsetY, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1 + OffsetY, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } pos.Y--; if (!satisfiesMinDistance(pos, worldForCollectibleResolve)) { return(false); } if (isStructureAt(pos, worldForCollectibleResolve)) { return(false); } LastPlacedSchematicLocation.Set(pos.X, pos.Y, pos.Z, pos.X + schematic.SizeX, pos.Y + schematic.SizeY, pos.Z + schematic.SizeZ); LastPlacedSchematic = schematic; schematic.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids); return(true); }
void genPatches(int chunkX, int chunkZ, bool postPass) { int dx, dz, x, z; Block block; for (int i = 0; i < bpc.Patches.Length; i++) { BlockPatch blockPatch = bpc.Patches[i]; if (blockPatch.PostPass != postPass) { continue; } float chance = blockPatch.Chance * bpc.ChanceMultiplier.nextFloat(); while (chance-- > rnd.NextDouble()) { dx = rnd.Next(chunksize); dz = rnd.Next(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); // Place according to forest value float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize) / 255f; int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); //float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); if (bpc.IsPatchSuitableAt(blockPatch, block, api.WorldManager, climate, y, forestRel)) { int firstBlockId = 0; bool found = true; if (blockPatch.BlocksByRockType != null) { found = false; int dy = 1; while (dy < 5 && y - dy > 0) { string lastCodePart = blockAccessor.GetBlock(x, y - dy, z).LastCodePart(); if (RockBlockIdsByType.TryGetValue(lastCodePart, out firstBlockId)) { found = true; break; } dy++; } } if (found) { blockPatch.Generate(blockAccessor, rnd, x, y, z, firstBlockId); } } } } }
private Room FindRoomForPosition(BlockPos pos, ChunkRooms otherRooms) { QueueOfInt bfsQueue = new QueueOfInt(); int halfSize = (ARRAYSIZE - 1) / 2; int maxSize = halfSize + halfSize; bfsQueue.Enqueue(halfSize << 10 | halfSize << 5 | halfSize); int visitedIndex = (halfSize * ARRAYSIZE + halfSize) * ARRAYSIZE + halfSize; // Center node int iteration = ++this.iteration; currentVisited[visitedIndex] = iteration; int coolingWallCount = 0; int nonCoolingWallCount = 0; int skyLightCount = 0; int nonSkyLightCount = 0; int exitCount = 0; blockAccess.Begin(); bool allChunksLoaded = true; int minx = halfSize, miny = halfSize, minz = halfSize, maxx = halfSize, maxy = halfSize, maxz = halfSize; int posX = pos.X - halfSize; int posY = pos.Y - halfSize; int posZ = pos.Z - halfSize; BlockPos npos = new BlockPos(); BlockPos bpos = new BlockPos(); int dx, dy, dz; while (bfsQueue.Count > 0) { int compressedPos = bfsQueue.Dequeue(); dx = compressedPos >> 10; dy = (compressedPos >> 5) & 0x1f; dz = compressedPos & 0x1f; npos.Set(posX + dx, posY + dy, posZ + dz); bpos.Set(npos); if (dx < minx) { minx = dx; } else if (dx > maxx) { maxx = dx; } if (dy < miny) { miny = dy; } else if (dy > maxy) { maxy = dy; } if (dz < minz) { minz = dz; } else if (dz > maxz) { maxz = dz; } Block bBlock = blockAccess.GetBlock(bpos); foreach (BlockFacing facing in BlockFacing.ALLFACES) { facing.IterateThruFacingOffsets(npos); // This must be the first command in the loop, to ensure all facings will be properly looped through regardless of any 'continue;' statements // We cannot exit current block, if the facing is heat retaining (e.g. chiselled block with solid side) if (bBlock.Id != 0 && bBlock.GetHeatRetention(bpos, facing) != 0) { continue; } if (!blockAccess.IsValidPos(npos)) { nonCoolingWallCount++; continue; } Block nBlock = blockAccess.GetBlock(npos); allChunksLoaded &= blockAccess.LastChunkLoaded; int heatRetention = nBlock.GetHeatRetention(npos, facing.Opposite); // We hit a wall, no need to scan further if (heatRetention != 0) { if (heatRetention < 0) { coolingWallCount -= heatRetention; } else { nonCoolingWallCount += heatRetention; } continue; } // Compute the new dx, dy, dz offsets for npos dx = npos.X - posX; dy = npos.Y - posY; dz = npos.Z - posZ; // Only traverse within maxSize range, and overall room size must not exceed MAXROOMSIZE // If outside that, count as an exit and don't continue searching in this direction // Note: for performance, this switch statement ensures only one conditional check in each case on the dimension which has actually changed, instead of 6 conditionals or more bool outsideCube = false; switch (facing.Index) { case 0: // North if (dz < minz) { outsideCube = dz < 0 || maxz - minz >= MAXROOMSIZE; } break; case 1: // East if (dx > maxx) { outsideCube = dx > maxSize || maxx - minx >= MAXROOMSIZE; } break; case 2: // South if (dz > maxz) { outsideCube = dz > maxSize || maxz - minz >= MAXROOMSIZE; } break; case 3: // West if (dx < minx) { outsideCube = dx < 0 || maxx - minx >= MAXROOMSIZE; } break; case 4: // Up if (dy > maxy) { outsideCube = dy > maxSize || maxy - miny >= MAXROOMSIZE; } break; case 5: // Down if (dy < miny) { outsideCube = dy < 0 || maxy - miny >= MAXROOMSIZE; } break; } if (outsideCube) { exitCount++; continue; } visitedIndex = (dx * ARRAYSIZE + dy) * ARRAYSIZE + dz; if (currentVisited[visitedIndex] == iteration) { continue; // continue if block position was already visited } currentVisited[visitedIndex] = iteration; // We only need to check the skylight if it's a block position not already visited ... int skyLightIndex = dx * ARRAYSIZE + dz; if (skyLightXZChecked[skyLightIndex] < iteration) { skyLightXZChecked[skyLightIndex] = iteration; int light = blockAccess.GetLightLevel(npos, EnumLightLevelType.OnlySunLight); if (light >= api.World.SunBrightness - 1) { skyLightCount++; } else { nonSkyLightCount++; } } bfsQueue.Enqueue(dx << 10 | dy << 5 | dz); } } int sizex = maxx - minx + 1; int sizey = maxy - miny + 1; int sizez = maxz - minz + 1; byte[] posInRoom = new byte[(sizex * sizey * sizez + 7) / 8]; int volumeCount = 0; for (dx = 0; dx < sizex; dx++) { for (dy = 0; dy < sizey; dy++) { visitedIndex = ((dx + minx) * ARRAYSIZE + (dy + miny)) * ARRAYSIZE + minz; for (dz = 0; dz < sizez; dz++) { if (currentVisited[visitedIndex + dz] == iteration) { int index = (dy * sizez + dz) * sizex + dx; posInRoom[index / 8] = (byte)(posInRoom[index / 8] | (1 << (index % 8))); volumeCount++; } } } } bool isCellar = sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE; if (!isCellar && volumeCount <= ALTMAXCELLARVOLUME) { isCellar = sizex <= ALTMAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE || sizex <= MAXCELLARSIZE && sizey <= ALTMAXCELLARSIZE && sizez <= MAXCELLARSIZE || sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= ALTMAXCELLARSIZE; } return(new Room() { CoolingWallCount = coolingWallCount, NonCoolingWallCount = nonCoolingWallCount, SkylightCount = skyLightCount, NonSkylightCount = nonSkyLightCount, ExitCount = exitCount, AnyChunkUnloaded = allChunksLoaded ? 0 : 1, Location = new Cuboidi(posX + minx, posY + miny, posZ + minz, posX + maxx, posY + maxy, posZ + maxz), PosInRoom = posInRoom, IsSmallRoom = isCellar && exitCount == 0 }); }
/// <summary> /// Will place all blocks using the supplied replace mode. Note: If you use a revertable or bulk block accessor you will have to call PlaceBlockEntities() after the Commit() /// </summary> /// <param name="blockAccessor"></param> /// <param name="worldForCollectibleResolve"></param> /// <param name="startPos"></param> /// <param name="mode"></param> /// <param name="replaceMetaBlocks"></param> /// <returns></returns> public virtual int Place(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos, EnumReplaceMode mode, bool replaceMetaBlocks = true) { BlockPos curPos = new BlockPos(); int placed = 0; PlaceBlockDelegate handler = null; switch (mode) { case EnumReplaceMode.ReplaceAll: if (replaceMetaBlocks) { handler = PlaceReplaceAllReplaceMeta; } else { handler = PlaceReplaceAllKeepMeta; } for (int dx = 0; dx < SizeX; dx++) { for (int dy = 0; dy < SizeY; dy++) { for (int dz = 0; dz < SizeZ; dz++) { curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z); blockAccessor.SetBlock(0, curPos); } } } break; case EnumReplaceMode.Replaceable: if (replaceMetaBlocks) { handler = PlaceReplaceableReplaceMeta; } else { handler = PlaceReplaceableKeepMeta; } break; case EnumReplaceMode.ReplaceAllNoAir: if (replaceMetaBlocks) { handler = PlaceReplaceAllNoAirReplaceMeta; } else { handler = PlaceReplaceAllNoAirKeepMeta; } break; case EnumReplaceMode.ReplaceOnlyAir: if (replaceMetaBlocks) { handler = PlaceReplaceOnlyAirReplaceMeta; } else { handler = PlaceReplaceOnlyAirKeepMeta; } break; } for (int i = 0; i < Indices.Count; i++) { uint index = Indices[i]; int storedBlockid = BlockIds[i]; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); AssetLocation blockCode = BlockCodes[storedBlockid]; Block newBlock = blockAccessor.GetBlock(blockCode); if (newBlock == null || (replaceMetaBlocks && newBlock == undergroundBlock)) { continue; } curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z); Block oldBlock = blockAccessor.GetBlock(curPos); placed += handler(blockAccessor, curPos, oldBlock, newBlock); if (newBlock.LightHsv[2] > 0 && blockAccessor is IWorldGenBlockAccessor) { ((IWorldGenBlockAccessor)blockAccessor).ScheduleBlockLightUpdate(curPos.Copy(), oldBlock.BlockId, newBlock.BlockId); } } if (!(blockAccessor is IBlockAccessorRevertable)) { PlaceEntitiesAndBlockEntities(blockAccessor, worldForCollectibleResolve, startPos); } return(placed); }
public void EnsureMapFullyLoaded() { int chunksize = api.World.BlockAccessor.ChunkSize; nowVisible.Clear(); nowHidden.Clear(); Cuboidi worldBounds = CurrentViewBounds.ToCuboidi(); worldBounds.Div(chunksize); //worldBounds.GrowBy(1); BlockPos cur = new BlockPos().Set(worldBounds.X1, 0, worldBounds.Z1); // StringBuilder debug = new StringBuilder(); while (cur.X <= worldBounds.X2) { cur.Z = worldBounds.Z1; while (cur.Z <= worldBounds.Z2) { if (!worldBoundsBefore.ContainsOrTouches(cur)) { nowVisible.Add(new Vec2i(cur.X, cur.Z)); // debug.Append(string.Format("{0}/{1}, ", cur.X, cur.Z)); } cur.Z++; } cur.X++; } // if (nowVisible.Count > 0) Console.WriteLine("{0} chunks now visible: {1}", nowVisible.Count, debug.ToString()); cur.Set(worldBoundsBefore.X1, 0, worldBoundsBefore.Z1); while (cur.X <= worldBoundsBefore.X2) { cur.Z = worldBoundsBefore.Z1; while (cur.Z <= worldBoundsBefore.Z2) { if (!worldBounds.ContainsOrTouches(cur)) { nowHidden.Add(new Vec2i(cur.X, cur.Z)); } cur.Z++; } cur.X++; } worldBoundsBefore = worldBounds.Clone(); viewChanged(nowVisible, nowHidden); }
public bool TryGenerate(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, DidGenerate didGenerateStructure) { this.climateUpLeft = climateUpLeft; this.climateUpRight = climateUpRight; this.climateBotLeft = climateBotLeft; this.climateBotRight = climateBotRight; float cnt = QuantityStructures.nextFloat(); int minQuantity = (int)cnt; BlockPos schemPos = pos.Copy(); Cuboidi location = new Cuboidi(); rand.InitPositionSeed(pos.X, pos.Z); List <GeneratableStructure> generatables = new List <GeneratableStructure>(); while (cnt-- > 0) { if (cnt < 1 && rand.NextDouble() > cnt) { break; } int tries = 30; while (tries-- > 0) { schemPos.Set(pos); schemPos.Add(rand.NextInt(50) - 25, 0, rand.NextInt(50) - 25); schemPos.Y = blockAccessor.GetTerrainMapheightAt(schemPos); double rndVal = rand.NextDouble() * totalWeight; int i = 0; VillageSchematic schem = null; while (rndVal > 0) { schem = Schematics[i++]; rndVal -= schem.Weight; } BlockSchematicStructure struc = GetGeneratableStructure(schem, blockAccessor, worldForCollectibleResolve, schemPos); if (struc != null) { location.Set(schemPos.X, schemPos.Y, schemPos.Z, schemPos.X + struc.SizeX, schemPos.Y + struc.SizeY, schemPos.Z + struc.SizeZ); bool intersect = false; for (int k = 0; k < generatables.Count; k++) { if (location.IntersectsOrTouches(generatables[k].location)) { intersect = true; break; } } if (!intersect) { generatables.Add(new GeneratableStructure() { struc = struc, pos = schemPos.Copy(), location = location.Clone() }); } break; } } } if (generatables.Count >= minQuantity) { foreach (var val in generatables) { val.struc.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, val.pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids); didGenerateStructure(val.location, val.struc); } } return(true); }