コード例 #1
0
        private void Event_OnChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
        {
            //api.Logger.Notification("NowDirty @{0}/{1}", chunkCoord.X, chunkCoord.Z);

            lock (chunksToGenLock)
            {
                if (!mapSink.IsOpened)
                {
                    return;
                }

                tmpMccoord.Set(chunkCoord.X / MultiChunkMapComponent.ChunkLen, chunkCoord.Z / MultiChunkMapComponent.ChunkLen);
                tmpCoord.Set(chunkCoord.X, chunkCoord.Z);

                if (!loadedMapData.ContainsKey(tmpMccoord) && !curVisibleChunks.Contains(tmpCoord))
                {
                    return;
                }

                chunksToGen.Enqueue(new Vec2i(chunkCoord.X, chunkCoord.Z));
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X, chunkCoord.Z - 1));
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X - 1, chunkCoord.Z));
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X, chunkCoord.Z + 1));
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X + 1, chunkCoord.Z + 1));
            }
        }
コード例 #2
0
        // Returns the block pos that is adjacent to a hole
        BlockPos FindHoleInPit()
        {
            smokeLocations.Clear();

            HashSet <BlockPos> visitedPositions = new HashSet <BlockPos>();
            Queue <BlockPos>   bfsQueue         = new Queue <BlockPos>();

            bfsQueue.Enqueue(Pos);

            int firewoodBlockId    = Api.World.GetBlock(new AssetLocation("firewoodpile")).BlockId;
            int charcoalPitBlockId = Api.World.GetBlock(new AssetLocation("charcoalpit")).BlockId;

            int maxHalfSize = 6;


            while (bfsQueue.Count > 0)
            {
                BlockPos bpos       = bfsQueue.Dequeue();
                BlockPos bposGround = bpos.Copy();
                bposGround.Y = 0;

                int yMax = 0;
                smokeLocations.TryGetValue(bposGround, out yMax);
                smokeLocations[bposGround] = Math.Max(yMax, bpos.Y);


                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    BlockPos    npos  = bpos.AddCopy(facing);
                    IWorldChunk chunk = Api.World.BlockAccessor.GetChunkAtBlockPos(npos);
                    if (chunk == null)
                    {
                        continue;                // Maybe at the endge of the loaded chunk
                    }
                    Block nBlock = chunk.GetLocalBlockAtBlockPos(Api.World, npos);

                    if (!nBlock.SideSolid[facing.Opposite.Index] && nBlock.BlockId != firewoodBlockId && nBlock.BlockId != charcoalPitBlockId)
                    {
                        return(bpos);
                    }

                    // 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);
                    }
                }
            }

            return(null);
        }
コード例 #3
0
        private void Event_ChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
        {
            long           index3d = MapUtil.Index3dL(chunkCoord.X, chunkCoord.Y, chunkCoord.Z, chunkMapSizeX, chunkMapSizeZ);
            ChunkRooms     chunkrooms;
            Cuboidi        cuboid;
            FastSetOfLongs set = new FastSetOfLongs();

            set.Add(index3d);
            lock (roomsByChunkIndexLock)
            {
                roomsByChunkIndex.TryGetValue(index3d, out chunkrooms);
                if (chunkrooms != null)
                {
                    set.Add(index3d);
                    for (int i = 0; i < chunkrooms.Rooms.Count; i++)
                    {
                        cuboid = chunkrooms.Rooms[i].Location;
                        int x1 = cuboid.Start.X / chunksize;
                        int x2 = cuboid.End.X / chunksize;
                        int y1 = cuboid.Start.Y / chunksize;
                        int y2 = cuboid.End.Y / chunksize;
                        int z1 = cuboid.Start.Z / chunksize;
                        int z2 = cuboid.End.Z / chunksize;
                        set.Add(MapUtil.Index3dL(x1, y1, z1, chunkMapSizeX, chunkMapSizeZ));
                        if (z2 != z1)
                        {
                            set.Add(MapUtil.Index3dL(x1, y1, z2, chunkMapSizeX, chunkMapSizeZ));
                        }
                        if (y2 != y1)
                        {
                            set.Add(MapUtil.Index3dL(x1, y2, z1, chunkMapSizeX, chunkMapSizeZ));
                            if (z2 != z1)
                            {
                                set.Add(MapUtil.Index3dL(x1, y2, z2, chunkMapSizeX, chunkMapSizeZ));
                            }
                        }
                        if (x2 != x1)
                        {
                            set.Add(MapUtil.Index3dL(x2, y1, z1, chunkMapSizeX, chunkMapSizeZ));
                            if (z2 != z1)
                            {
                                set.Add(MapUtil.Index3dL(x2, y1, z2, chunkMapSizeX, chunkMapSizeZ));
                            }
                            if (y2 != y1)
                            {
                                set.Add(MapUtil.Index3dL(x2, y2, z1, chunkMapSizeX, chunkMapSizeZ));
                                if (z2 != z1)
                                {
                                    set.Add(MapUtil.Index3dL(x2, y2, z2, chunkMapSizeX, chunkMapSizeZ));
                                }
                            }
                        }
                    }
                }
                foreach (long index in set)
                {
                    roomsByChunkIndex.Remove(index);
                }
            }
        }
コード例 #4
0
        private void Event_DidPlaceBlock(IServerPlayer byPlayer, int oldblockId, BlockSelection blockSel, ItemStack withItemStack)
        {
            IMapChunk mapchunk = api.World.BlockAccessor.GetMapChunkAtBlockPos(blockSel.Position);

            if (mapchunk == null)
            {
                return;
            }

            int lx = blockSel.Position.X % chunksize;
            int lz = blockSel.Position.Z % chunksize;

            int y  = mapchunk.RainHeightMap[lz * chunksize + lx];
            int ly = y % chunksize;


            IWorldChunk chunk = api.World.BlockAccessor.GetChunkAtBlockPos(blockSel.Position.X, y, blockSel.Position.Z);

            if (chunk == null)
            {
                return;
            }

            chunk.Unpack();
            int blockId = chunk.Blocks[(ly * chunksize + lz) * chunksize + lx];

            if (blockId == 0)
            {
                int cx = blockSel.Position.X / chunksize;
                int cz = blockSel.Position.Z / chunksize;
                api.World.Logger.Notification("Huh. Found air block in rain map at chunk pos {0}/{1}. That seems invalid, will regenerate rain map", cx, cz);
                rebuildRainmap(cx, cz);
            }
        }
コード例 #5
0
        private void Event_ChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
        {
            if (allNetworksFullyLoaded || reason == EnumChunkDirtyReason.MarkedDirty)
            {
                return;
            }

            allNetworksFullyLoaded = true;
            nowFullyLoaded.Clear();

            foreach (var network in data.networksById.Values)
            {
                if (network.fullyLoaded)
                {
                    continue;
                }
                allNetworksFullyLoaded = false;

                if (network.inChunks.ContainsKey(chunkCoord))
                {
                    testFullyLoaded(network);
                    if (network.fullyLoaded)
                    {
                        nowFullyLoaded.Add(network);
                    }
                }
            }

            for (int i = 0; i < nowFullyLoaded.Count; i++)
            {
                RebuildNetwork(nowFullyLoaded[i]);
            }
        }
コード例 #6
0
        private void onChunkData(ChunkReinforcementData msg)
        {
            IWorldChunk chunk = api.World.BlockAccessor.GetChunk(msg.chunkX, msg.chunkY, msg.chunkZ);

            if (chunk != null)
            {
                chunk.SetModdata("reinforcements", msg.Data);
            }
        }
コード例 #7
0
        // Custom implementation for mixed generating/loaded chunk access, since we can spawn entities just fine in either loaded or still generating chunks
        public bool IsColliding(Cuboidf entityBoxRel, Vec3d pos)
        {
            BlockPos       blockPos = new BlockPos();
            IBlockAccessor blockAccess;
            int            chunksize = wgenBlockAccessor.ChunkSize;

            Cuboidd entityCuboid  = entityBoxRel.ToDouble().Translate(pos);
            Vec3d   blockPosAsVec = new Vec3d();

            int minX = (int)(entityBoxRel.X1 + pos.X);
            int minY = (int)(entityBoxRel.Y1 + pos.Y);
            int minZ = (int)(entityBoxRel.Z1 + pos.Z);
            int maxX = (int)Math.Ceiling(entityBoxRel.X2 + pos.X);
            int maxY = (int)Math.Ceiling(entityBoxRel.Y2 + pos.Y);
            int maxZ = (int)Math.Ceiling(entityBoxRel.Z2 + pos.Z);

            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x <= maxX; x++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        blockAccess = wgenBlockAccessor;
                        IWorldChunk chunk = wgenBlockAccessor.GetChunkAtBlockPos(x, y, z);
                        if (chunk == null)
                        {
                            chunk       = api.World.BlockAccessor.GetChunkAtBlockPos(x, y, z);
                            blockAccess = api.World.BlockAccessor;
                        }
                        if (chunk == null)
                        {
                            return(true);
                        }

                        chunk.Unpack();

                        int   index = ((y % chunksize) * chunksize + (z % chunksize)) * chunksize + (x % chunksize);
                        Block block = api.World.Blocks[chunk.Blocks[index]];

                        blockPos.Set(x, y, z);
                        blockPosAsVec.Set(x, y, z);

                        Cuboidf[] collisionBoxes = block.GetCollisionBoxes(blockAccess, blockPos);
                        for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                        {
                            Cuboidf collBox = collisionBoxes[i];
                            if (collBox != null && entityCuboid.Intersects(collBox, blockPosAsVec))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
コード例 #8
0
        private void Event_ChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
        {
            long index3d = MapUtil.Index3dL(chunkCoord.X, chunkCoord.Y, chunkCoord.Z, chunkMapSizeX, chunkMapSizeZ);

            lock (roomsByChunkIndexLock)
            {
                roomsByChunkIndex.Remove(index3d);
            }
        }
コード例 #9
0
        Dictionary <int, BlockReinforcement> getOrCreateReinforcmentsAt(BlockPos pos)
        {
            byte[] data;

            IWorldChunk chunk = api.World.BlockAccessor.GetChunkAtBlockPos(pos);

            if (chunk == null)
            {
                return(null);
            }

            data = chunk.GetModdata("reinforcements");

            Dictionary <int, BlockReinforcement> reinforcmentsOfChunk = null;

            if (data != null)
            {
                try
                {
                    reinforcmentsOfChunk = SerializerUtil.Deserialize <Dictionary <int, BlockReinforcement> >(data);
                } catch (Exception)
                {
                    try
                    {
                        api.World.Logger.Warning("Failed reading block reinforcments at block position, maybe old format. Will attempt to convert.");

                        Dictionary <int, BlockReinforcementOld> old = SerializerUtil.Deserialize <Dictionary <int, BlockReinforcementOld> >(data);
                        reinforcmentsOfChunk = new Dictionary <int, BlockReinforcement>();
                        foreach (var val in old)
                        {
                            reinforcmentsOfChunk[val.Key] = val.Value.Update();
                        }
                        saveReinforcments(reinforcmentsOfChunk, pos);

                        api.World.Logger.Warning("Ok, converted");
                    } catch (Exception e2)
                    {
                        api.World.Logger.Error("Failed reading block reinforcments at block position {0}, will discard, sorry. Exception: {1}", pos, e2);
                    }

                    reinforcmentsOfChunk = new Dictionary <int, BlockReinforcement>();
                }
            }
            else
            {
                reinforcmentsOfChunk = new Dictionary <int, BlockReinforcement>();
            }

            return(reinforcmentsOfChunk);
        }
コード例 #10
0
        private void Event_OnChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
        {
            if (reason == EnumChunkDirtyReason.NewlyCreated || !mapSink.IsOpened)
            {
                return;
            }

            if (!loadedMapData.ContainsKey(new Vec2i(chunkCoord.X, chunkCoord.Z)))
            {
                return;
            }

            lock (chunksToGenLock)
            {
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X, chunkCoord.Z));
            }
        }
コード例 #11
0
        private void Event_OnChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, bool isNewChunk)
        {
            if (isNewChunk || !mapSink.IsOpened)
            {
                return;
            }

            if (!loadedMapData.ContainsKey(new Vec2i(chunkCoord.X, chunkCoord.Z)))
            {
                return;
            }

            lock (chunksToGenLock)
            {
                chunksToGen.Enqueue(new Vec2i(chunkCoord.X, chunkCoord.Z));
            }
        }
コード例 #12
0
        public virtual void PlaceDecors(IBlockAccessor blockAccessor, BlockPos startPos, bool synchronize)
        {
            BlockPos curPos = new BlockPos();

            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];
                storedBlockid &= 0xFFFFFF;

                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)
                {
                    continue;
                }

                curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z);

                IWorldChunk chunk = blockAccessor.GetChunkAtBlockPos(curPos);
                if (chunk == null)
                {
                    continue;
                }
                if (synchronize)
                {
                    blockAccessor.MarkChunkDecorsModified(curPos);
                }
                chunk.SetDecor(blockAccessor, newBlock, curPos, face);
                chunk.MarkModified();
            }
        }
コード例 #13
0
        void saveReinforcments(Dictionary <int, BlockReinforcement> reif, BlockPos pos)
        {
            int chunksize = api.World.BlockAccessor.ChunkSize;
            int chunkX    = pos.X / chunksize;
            int chunkY    = pos.Y / chunksize;
            int chunkZ    = pos.Z / chunksize;

            byte[] data = SerializerUtil.Serialize(reif);

            IWorldChunk chunk = api.World.BlockAccessor.GetChunk(chunkX, chunkY, chunkZ);

            chunk.SetModdata("reinforcements", data);

            // Todo: Send only to players that have this chunk in their loaded range
            serverChannel?.BroadcastPacket(new ChunkReinforcementData()
            {
                chunkX = chunkX, chunkY = chunkY, chunkZ = chunkZ, Data = data
            });
        }
コード例 #14
0
        public static int GetSunlight(this IBlockAccessor blockAcessor, int posX, int posY, int posZ)
        {
            IWorldAccessor world    = (blockAcessor as BlockAccessorBase).GetField <BlockAccessorBase, IWorldAccessor>("worldAccessor");
            WorldMap       worldMap = (blockAcessor as BlockAccessorBase).GetField <BlockAccessorBase, WorldMap>("worldmap");

            IWorldChunk chunkAtBlockPos = blockAcessor.GetChunkAtBlockPos(posX, posY, posZ);

            if (chunkAtBlockPos == null || !worldMap.IsValidPos(posX, posY, posZ))
            {
                return(world.SunBrightness);
            }
            chunkAtBlockPos.Unpack();
            int chunkSize = blockAcessor.ChunkSize;
            int index     = (posY % chunkSize * chunkSize + posZ % chunkSize) * chunkSize + posX % chunkSize;
            int num       = (int)chunkAtBlockPos.Light[index];
            int val2      = num >> 5 & 31;
            int val1      = num & 31;

            return((int)Math.Round((double)val1 * (double)world.Calendar.GetDayLightStrength(posX, posZ)));
        }
コード例 #15
0
        private void Event_ChunkDirty(Vec3i chunkCoord, IWorldChunk chunk, bool isNewChunk)
        {
            long index3d = MapUtil.Index3dL(chunkCoord.X, chunkCoord.Y, chunkCoord.Z, chunkMapSizeX, chunkMapSizeZ);

            CellarsByChunkIndex.Remove(index3d);
        }
コード例 #16
0
        public override int GetLightAbsorption(IWorldChunk chunk, BlockPos pos)
        {
            BlockEntityMicroBlock bec = chunk?.GetLocalBlockEntityAtBlockPos(pos) as BlockEntityMicroBlock;

            return(bec?.GetLightAbsorption() ?? 0);
        }
コード例 #17
0
        void ConvertPit()
        {
            Dictionary <BlockPos, Vec3i> quantityPerColumn = new Dictionary <BlockPos, Vec3i>();

            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;

            Vec3i curQuantityAndYMinMax;

            while (bfsQueue.Count > 0)
            {
                BlockPos bpos = bfsQueue.Dequeue();

                BlockPos bposGround = bpos.Copy();
                bposGround.Y = 0;

                if (quantityPerColumn.TryGetValue(bposGround, out curQuantityAndYMinMax))
                {
                    curQuantityAndYMinMax.Y = Math.Min(curQuantityAndYMinMax.Y, bpos.Y);
                    curQuantityAndYMinMax.Z = Math.Max(curQuantityAndYMinMax.Z, bpos.Y);
                }
                else
                {
                    curQuantityAndYMinMax = quantityPerColumn[bposGround] = new Vec3i(0, bpos.Y, bpos.Y);
                }

                BlockEntityFirewoodPile be = Api.World.BlockAccessor.GetBlockEntity(bpos) as BlockEntityFirewoodPile;
                if (be != null)
                {
                    curQuantityAndYMinMax.X += be.OwnStackSize;
                }

                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)
                    {
                        IWorldChunk chunk = Api.World.BlockAccessor.GetChunkAtBlockPos(npos);
                        if (chunk == null)
                        {
                            return;                // Maybe at the endge of the loaded chunk, in which case return before changing any blocks and it can be converted next tick instead
                        }
                        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));

                int maxY = val.Value.Z;
                while (lpos.Y <= maxY)
                {
                    Block nBlock = Api.World.BlockAccessor.GetBlock(lpos);
                    if (nBlock.BlockId == firewoodBlockId)  //test for the possibility someone had contiguous firewood both above and below a soil block for example
                    {
                        if (charCoalQuantity > 0)
                        {
                            Block charcoalBlock = Api.World.GetBlock(new AssetLocation("charcoalpile-" + GameMath.Clamp(charCoalQuantity, 1, 8)));
                            Api.World.BlockAccessor.SetBlock(charcoalBlock.BlockId, lpos);
                            charCoalQuantity -= 8;
                        }
                        else
                        {
                            //Set any free blocks still in this column (y <= maxY) to air
                            Api.World.BlockAccessor.SetBlock(0, lpos);
                        }
                    }
                    lpos.Up();
                }
            }

            Api.World.BlockAccessor.SetBlock(0, Pos);
        }
コード例 #18
0
        protected virtual void HandleTeleportingServer(float dt)
        {
            toremove.Clear();

            bool wasTeleporting = somebodyIsTeleporting;

            somebodyIsTeleporting &= tpingEntities.Count > 0;
            var sapi = Api as ICoreServerAPI;

            foreach (var val in tpingEntities)
            {
                if (val.Value.Entity.Teleporting)
                {
                    continue;
                }

                val.Value.SecondsPassed += Math.Min(0.5f, dt);

                if (Api.World.ElapsedMilliseconds - val.Value.LastCollideMs > 100)
                {
                    // Make sure its not just server lag
                    Block block = Api.World.CollisionTester.GetCollidingBlock(Api.World.BlockAccessor, val.Value.Entity.SelectionBox, val.Value.Entity.Pos.XYZ, true);
                    if (!(block is BlockStaticTranslocator))
                    {
                        toremove.Add(val.Key);
                        continue;
                    }
                }

                if (val.Value.SecondsPassed > 0.1 && !somebodyIsTeleporting)
                {
                    somebodyIsTeleporting = true;
                    MarkDirty();
                }

                if (val.Value.SecondsPassed > 1.5 && tpTarget != null)
                {
                    // Preload the chunk
                    IWorldChunk chunk = Api.World.BlockAccessor.GetChunkAtBlockPos(tpTarget);
                    if (chunk != null)
                    {
                        chunk.MapChunk.MarkFresh();
                    }
                    else
                    {
                        sapi.WorldManager.LoadChunkColumnPriority((int)tpTarget.X / Api.World.BlockAccessor.ChunkSize, (int)tpTarget.Z / Api.World.BlockAccessor.ChunkSize, new ChunkLoadOptions()
                        {
                            KeepLoaded = false
                        });
                    }
                }

                if (val.Value.SecondsPassed > TeleportWarmupSec && tpTarget != null)
                {
                    val.Value.Entity.TeleportTo(tpTarget.ToVec3d().Add(-0.3, 1, -0.3)); // Fugly, need some better exit pos thing
                    toremove.Add(val.Key);

                    Entity e = val.Value.Entity;
                    if (e is EntityPlayer)
                    {
                        Api.World.Logger.Debug("Teleporting player {0} to {1}", (e as EntityPlayer).GetBehavior <EntityBehaviorNameTag>().DisplayName, tpTarget);
                    }
                    else
                    {
                        Api.World.Logger.Debug("Teleporting entity {0} to {1}", e.Code, tpTarget);
                    }

                    didTeleport(val.Value.Entity);

                    somebodyIsTeleporting = false;
                    somebodyDidTeleport   = true;


                    MarkDirty();
                }
            }

            foreach (long entityid in toremove)
            {
                tpingEntities.Remove(entityid);
            }

            if (wasTeleporting && !somebodyIsTeleporting)
            {
                MarkDirty();
            }
        }
コード例 #19
0
        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);
        }
コード例 #20
0
        /// <summary>
        /// This performs a entity search inside a spacially partioned search grid thats refreshed every 16ms.
        /// This can be a lot faster for when there are thousands of entities on a small space. It is used by EntityBehaviorRepulseAgents to improve performance, because otherwise when spawning 1000 creatures nearby, it has to do 1000x1000 = 1mil search operations every frame
        /// A small search grid allows us to ignore most of those during the search.
        /// </summary>
        /// <param name="centerPos"></param>
        /// <param name="radius"></param>
        /// <param name="callback">Return false to stop the walk</param>
        public void WalkEntities(Vec3d centerPos, double radius, ActionConsumable <Entity> callback)
        {
            int mingx = (int)((centerPos.X - radius) / gridSizeInBlocks);
            int maxgx = (int)((centerPos.X + radius) / gridSizeInBlocks);
            //int mingy = (int)((centerPos.Y - radius) / gridSizeInBlocks);
            //int maxgy = (int)((centerPos.Y + radius) / gridSizeInBlocks);

            int mincy = (int)((centerPos.Y - radius) / chunkSize);
            int maxcy = (int)((centerPos.Y + radius) / chunkSize);

            int mingz = (int)((centerPos.Z - radius) / gridSizeInBlocks);
            int maxgz = (int)((centerPos.Z + radius) / gridSizeInBlocks);

            double radiusSq = radius * radius;

            long                 indexBefore    = -1;
            IWorldChunk          chunk          = null;
            EntityPartitionChunk partitionChunk = null;

            int gridXMax = api.World.BlockAccessor.MapSizeX / gridSizeInBlocks;
            //int gridYMax = api.World.BlockAccessor.MapSizeY / gridSizeInBlocks;
            int gridZMax = api.World.BlockAccessor.MapSizeZ / gridSizeInBlocks;

            int cyTop = api.World.BlockAccessor.MapSizeY / chunkSize;

            for (int gridX = mingx; gridX <= maxgx; gridX++)
            {
                //for (int gridY = mingy; gridY <= maxgy; gridY++)
                for (int cy = mincy; cy <= maxcy; cy++)
                {
                    for (int gridZ = mingz; gridZ <= maxgz; gridZ++)
                    {
                        if (gridX < 0 || cy < 0 || gridZ < 0 || gridX >= gridXMax || cy >= cyTop || gridZ >= gridZMax)
                        {
                            continue;
                        }

                        int cx = gridX * gridSizeInBlocks / chunkSize;
                        //int cy = gridY * gridSizeInBlocks / chunkSize;
                        int cz = gridZ * gridSizeInBlocks / chunkSize;

                        long index3d = MapUtil.Index3dL(cx, cy, cz, chunkMapSizeX, chunkMapSizeZ);

                        if (index3d != indexBefore)
                        {
                            chunk = api.World.BlockAccessor.GetChunk(cx, cy, cz);
                            Partitions.TryGetValue(index3d, out partitionChunk);
                            indexBefore = index3d;
                        }

                        if (chunk == null || chunk.Entities == null || partitionChunk == null)
                        {
                            continue;
                        }

                        int lgx = gridX % partitionsLength;
                        int lgz = gridZ % partitionsLength;

                        List <Entity> entities = partitionChunk.Entities[lgz * partitionsLength + lgx];

                        for (int i = 0; i < entities.Count; i++)
                        {
                            double distSq = entities[i].SidedPos.SquareDistanceTo(centerPos);
                            if (distSq <= radiusSq && !callback(entities[i]))
                            {
                                return;
                            }
                        }
                    }
                }
            }
        }
コード例 #21
0
        void HandleTeleporting(float dt)
        {
            toremove.Clear();

            bool wasTeleporting = somebodyIsTeleporting;

            somebodyIsTeleporting &= tpingEntities.Count > 0;

            foreach (var val in tpingEntities)
            {
                if (val.Value.Entity.Teleporting)
                {
                    continue;
                }

                val.Value.SecondsPassed += Math.Min(0.5f, dt);

                if (Api.World.ElapsedMilliseconds - val.Value.LastCollideMs > 100)
                {
                    // Make sure its not just server lag
                    Block block = Api.World.CollisionTester.GetCollidingBlock(Api.World.BlockAccessor, val.Value.Entity.CollisionBox, val.Value.Entity.Pos.XYZ, true);
                    if (!(block is BlockStaticTranslocator))
                    {
                        toremove.Add(val.Key);
                        continue;
                    }
                }

                if (val.Value.SecondsPassed > 0.1 && !somebodyIsTeleporting)
                {
                    somebodyIsTeleporting = true;
                    MarkDirty();
                }

                if (val.Value.SecondsPassed > 1.5 && tpLocation != null)
                {
                    // Preload the chunk
                    IWorldChunk chunk = sapi.World.BlockAccessor.GetChunkAtBlockPos(tpLocation);
                    if (chunk != null)
                    {
                        chunk.MapChunk.MarkFresh();
                    }
                    else
                    {
                        sapi.WorldManager.LoadChunkColumnPriority((int)tpLocation.X / Api.World.BlockAccessor.ChunkSize, (int)tpLocation.Z / Api.World.BlockAccessor.ChunkSize, new ChunkLoadOptions()
                        {
                            KeepLoaded = false
                        });
                    }
                }

                if (val.Value.SecondsPassed > 4.4 && tpLocation != null)
                {
                    val.Value.Entity.TeleportTo(tpLocation.ToVec3d().Add(-0.3, 1, -0.3)); // Fugly, need some better exit pos thing

                    Entity e = val.Value.Entity;
                    if (e is EntityPlayer)
                    {
                        Api.World.Logger.Debug("Teleporting player {0} to {1}", (e as EntityPlayer).GetBehavior <EntityBehaviorNameTag>().DisplayName, tpLocation);
                        manager.DidTranslocateServer((e as EntityPlayer).Player as IServerPlayer);
                    }
                    else
                    {
                        Api.World.Logger.Debug("Teleporting entity {0} to {1}", e.Code, tpLocation);
                    }

                    toremove.Add(val.Key);

                    activated             = false;
                    somebodyIsTeleporting = false;
                    somebodyDidTeleport   = true;

                    ownBlock.teleportParticles.MinPos.Set(Pos.X, Pos.Y, Pos.Z);
                    ownBlock.teleportParticles.AddPos.Set(1, 1.8, 1);
                    ownBlock.teleportParticles.MinVelocity.Set(-1, -1, -1);
                    ownBlock.teleportParticles.AddVelocity.Set(2, 2, 2);
                    ownBlock.teleportParticles.MinQuantity = 150;
                    ownBlock.teleportParticles.AddQuantity = 0.5f;


                    int r = 53;
                    int g = 221;
                    int b = 172;
                    ownBlock.teleportParticles.Color = (r << 16) | (g << 8) | (b << 0) | (100 << 24);

                    ownBlock.teleportParticles.BlueEvolve    = null;
                    ownBlock.teleportParticles.RedEvolve     = null;
                    ownBlock.teleportParticles.GreenEvolve   = null;
                    ownBlock.teleportParticles.MinSize       = 0.1f;
                    ownBlock.teleportParticles.MaxSize       = 0.2f;
                    ownBlock.teleportParticles.SizeEvolve    = null;
                    ownBlock.teleportParticles.OpacityEvolve = EvolvingNatFloat.create(EnumTransformFunction.QUADRATIC, -10f);


                    Api.World.SpawnParticles(ownBlock.teleportParticles);


                    MarkDirty();
                }
            }

            foreach (long entityid in toremove)
            {
                tpingEntities.Remove(entityid);
            }

            if (wasTeleporting && !somebodyIsTeleporting)
            {
                MarkDirty();
            }
        }
コード例 #22
0
        /// <summary>
        /// Same as <see cref="WalkEntities(Vec3d, double, API.Common.Action{Entity})"/> but does no exact radius distance check, walks all entities that it finds in the grid
        /// </summary>
        /// <param name="centerPos"></param>
        /// <param name="radius"></param>
        /// <param name="callback"></param>
        public void WalkEntityPartitions(Vec3d centerPos, double radius, API.Common.Action <Entity> callback)
        {
            int mingx = (int)((centerPos.X - radius) / gridSizeInBlocks);
            int maxgx = (int)((centerPos.X + radius) / gridSizeInBlocks);

            /*int mingy = (int)((centerPos.Y - radius) / gridSizeInBlocks);
            *  int maxgy = (int)((centerPos.Y + radius) / gridSizeInBlocks);*/

            int mincy = (int)((centerPos.Y - radius) / chunkSize);
            int maxcy = (int)((centerPos.Y + radius) / chunkSize);

            int mingz = (int)((centerPos.Z - radius) / gridSizeInBlocks);
            int maxgz = (int)((centerPos.Z + radius) / gridSizeInBlocks);


            int                  cxBefore = -99, cyBefore = -99, czBefore = -99;
            IWorldChunk          chunk          = null;
            EntityPartitionChunk partitionChunk = null;

            int gridXMax = api.World.BlockAccessor.MapSizeX / gridSizeInBlocks;
            //int gridYMax = api.World.BlockAccessor.MapSizeX / gridSizeInBlocks;
            int gridZMax = api.World.BlockAccessor.MapSizeX / gridSizeInBlocks;

            int cyTop = api.World.BlockAccessor.MapSizeY / chunkSize;

            for (int gridX = mingx; gridX <= maxgx; gridX++)
            {
                for (int cy = mincy; cy <= maxcy; cy++)
                //for (int gridY = mingy; gridY <= maxgy; gridY++)
                {
                    for (int gridZ = mingz; gridZ <= maxgz; gridZ++)
                    {
                        if (gridX < 0 || cy < 0 || gridZ < 0 || gridX >= gridXMax || cy >= cyTop || gridZ >= gridZMax)
                        {
                            continue;
                        }

                        int cx = gridX * gridSizeInBlocks / chunkSize;
                        //int cy = gridY * gridSizeInBlocks / chunkSize;
                        int cz = gridZ * gridSizeInBlocks / chunkSize;

                        long index3d = MapUtil.Index3dL(cx, cy, cz, chunkMapSizeX, chunkMapSizeZ);

                        if (cx != cxBefore || cy != cyBefore || cz != czBefore)
                        {
                            chunk = api.World.BlockAccessor.GetChunk(cx, cy, cz);
                            Partitions.TryGetValue(index3d, out partitionChunk);
                        }
                        if (chunk == null || chunk.Entities == null || partitionChunk == null)
                        {
                            continue;
                        }

                        cxBefore = cx;
                        cyBefore = cy;
                        czBefore = cz;

                        int lgx = gridX % partitionsLength;
                        int lgz = gridZ % partitionsLength;

                        List <Entity> entities = partitionChunk.Entities[lgz * partitionsLength + lgx];
                        for (int i = 0; i < entities.Count; i++)
                        {
                            callback(entities[i]);
                        }
                    }
                }
            }
        }
コード例 #23
0
        private void WalkEntities(Vec3d centerPos, double radius, ActionConsumable <Entity> callback, RangeTestDelegate onRangeTest)
        {
            int gridXMax = api.World.BlockAccessor.MapSizeX / gridSizeInBlocks - 1;
            int cyTop    = api.World.BlockAccessor.MapSizeY / chunkSize - 1;
            int gridZMax = api.World.BlockAccessor.MapSizeZ / gridSizeInBlocks - 1;

            int mingx = (int)GameMath.Clamp((centerPos.X - radius) / gridSizeInBlocks, 0, gridXMax);
            int maxgx = (int)GameMath.Clamp((centerPos.X + radius) / gridSizeInBlocks, 0, gridXMax);

            int mincy = (int)GameMath.Clamp((centerPos.Y - radius) / chunkSize, 0, cyTop);
            int maxcy = (int)GameMath.Clamp((centerPos.Y + radius) / chunkSize, 0, cyTop);

            int mingz = (int)GameMath.Clamp((centerPos.Z - radius) / gridSizeInBlocks, 0, gridZMax);
            int maxgz = (int)GameMath.Clamp((centerPos.Z + radius) / gridSizeInBlocks, 0, gridZMax);

            double radiusSq = radius * radius;

            long                 indexBefore    = -1;
            IWorldChunk          chunk          = null;
            EntityPartitionChunk partitionChunk = null;

            for (int gridX = mingx; gridX <= maxgx; gridX++)
            {
                int cx  = gridX * gridSizeInBlocks / chunkSize;
                int lgx = gridX % partitionsLength;

                for (int gridZ = mingz; gridZ <= maxgz; gridZ++)
                {
                    int cz  = gridZ * gridSizeInBlocks / chunkSize;
                    int lgz = gridZ % partitionsLength;
                    lgz = lgz * partitionsLength + lgx;

                    for (int cy = mincy; cy <= maxcy; cy++)
                    {
                        long index3d = MapUtil.Index3dL(cx, cy, cz, chunkMapSizeX, chunkMapSizeZ);

                        if (index3d != indexBefore)
                        {
                            indexBefore = index3d;
                            chunk       = api.World.BlockAccessor.GetChunk(cx, cy, cz);
                            if (chunk == null || chunk.Entities == null)
                            {
                                continue;
                            }
                            Partitions.TryGetValue(index3d, out partitionChunk);
                        }
                        else if (chunk == null || chunk.Entities == null)
                        {
                            continue;
                        }

                        if (partitionChunk == null)
                        {
                            continue;
                        }

                        List <Entity> entities = partitionChunk.Entities[lgz];

                        for (int i = 0; i < entities.Count; i++)
                        {
                            if (onRangeTest(entities[i], centerPos, radiusSq) && !callback(entities[i]))
                            {
                                return;
                            }
                        }
                    }
                }
            }
        }