/// <summary>
        /// Deletes the given tile entity from it's chunk and creates a new one based on the tile entity type
        /// </summary>
        private void RecreateTileEntity([NotNull] TileEntity tileEntity)
        {
            var chunk = tileEntity.GetChunk();

            // Prevent further errors on client updates; crucial when removing power item!
            tileEntity.SetDisableModifiedCheck(true);

            // Remove corrupt tile entity
            chunk.RemoveTileEntity(World, tileEntity);

            // Remove power item
            var tePowered = tileEntity as TileEntityPowered;
            var powerItem = tePowered?.GetPowerItem();

            if (powerItem != null)
            {
                PowerManager.Instance.RemovePowerNode(powerItem);
            }

            // Create new tile entity
            var newTileEntity = TileEntity.Instantiate(tileEntity.GetTileEntityType(), chunk);

            newTileEntity.localChunkPos = tileEntity.localChunkPos;
            chunk.AddTileEntity(newTileEntity);

            // Recreate power item if necessary
            var newPowered = newTileEntity as TileEntityPowered;

            if (newPowered != null)
            {
                // Restore old PowerItemType and TriggerType values
                if (tePowered != null)
                {
                    newPowered.PowerItemType = tePowered.PowerItemType;
                }

                // fancy new C#7 syntax, isn't it? :)
                if (tileEntity is TileEntityPoweredTrigger teTrigger && newPowered is TileEntityPoweredTrigger newTrigger)
                {
                    newTrigger.TriggerType = teTrigger.TriggerType;
                }

                // Create power item according to PowerItemType and TriggerType
                newPowered.InitializePowerData();

                // Wires to the corrupt block are cut and not restored. We could try to reattach everything, but meh...
            }

            var newPowerItem = newPowered?.GetPowerItem();

            Log.Debug($"[{tileEntity.ToWorldPos()}] Replaced old {tileEntity.GetType()} with new {newTileEntity.GetType()}" +
                      $"{(newPowerItem != null ? " and new power item " + newPowerItem.GetType() : "")}.");
        }
        internal void Read(BinaryReader reader)
        {
            Utils.VerifyVersion(reader.ReadByte(), SaveVersionConstants.ENTITY_CREATION_DATA);

            entityClass = new Value <int>(reader.ReadInt32());

            id       = new Value <int>(reader.ReadInt32());
            lifetime = new Value <float>(reader.ReadSingle());

            pos = new Vector3D <float> {
                x = new Value <float>(reader.ReadSingle()),
                y = new Value <float>(reader.ReadSingle()),
                z = new Value <float>(reader.ReadSingle())
            };

            rot = new Vector3D <float> {
                x = new Value <float>(reader.ReadSingle()),
                y = new Value <float>(reader.ReadSingle()),
                z = new Value <float>(reader.ReadSingle())
            };

            onGround = new Value <bool>(reader.ReadBoolean());

            bodyDamage = new BodyDamage(reader);

            if (reader.ReadBoolean())
            {
                stats = new EntityStats(reader);
            }

            deathTime = new Value <short>(reader.ReadInt16());

            if (reader.ReadBoolean())
            {
                int tileEntityType = reader.ReadInt32();
                lootContainer = TileEntity.Instantiate((TileEntityType)(tileEntityType));
                lootContainer.Read(reader);
            }

            homePosition = new Vector3D <int> {
                x = new Value <int>(reader.ReadInt32()),
                y = new Value <int>(reader.ReadInt32()),
                z = new Value <int>(reader.ReadInt32())
            };
            homeRange = new Value <short>(reader.ReadInt16());

            spawnerSource = (EnumSpawnerSource)reader.ReadByte();

            if (entityClass.Get() == Utils.GetMonoHash("item"))
            {
                belongsPlayerId = new Value <int>(reader.ReadInt32());
                itemStack.Read(reader);

                reader.ReadSByte();
            }

            else if (entityClass.Get() == Utils.GetMonoHash("fallingBlock"))
            {
                blockValue  = new Value <uint>(reader.ReadUInt32());
                textureFull = new Value <long>(reader.ReadInt64());
            }

            else if (entityClass.Get() == Utils.GetMonoHash("fallingTree"))
            {
                blockPosition = new Vector3D <int> {
                    x = new Value <int>(reader.ReadInt32()),
                    y = new Value <int>(reader.ReadInt32()),
                    z = new Value <int>(reader.ReadInt32())
                };

                fallTreeDir = new Vector3D <float> {
                    x = new Value <float>(reader.ReadSingle()),
                    y = new Value <float>(reader.ReadSingle()),
                    z = new Value <float>(reader.ReadSingle())
                };
            }

            else if ((entityClass.Get() == Utils.GetMonoHash("playerMale")) || (entityClass.Get() == Utils.GetMonoHash("playerFemale")))
            {
                holdingItem = new ItemValue(reader);
                teamNumber  = new Value <byte>(reader.ReadByte());
                entityName  = new Value <string>(reader.ReadString());
                skinTexture = new Value <string>(reader.ReadString());

                if (reader.ReadBoolean())
                {
                    playerProfile = PlayerProfile.Read(reader);
                }
                else
                {
                    playerProfile = null;
                }
            }

            //num2
            ushort entityDataLength = reader.ReadUInt16();

            if (entityDataLength > 0)
            {
                byte[] buffer = reader.ReadBytes(entityDataLength);
                entityData = new MemoryStream(buffer);
            }

            if (reader.ReadBoolean())
            {
                int tileEntityType = reader.ReadInt32();
                traderData = (TileEntityTrader)TileEntity.Instantiate((TileEntityType)(tileEntityType));
                traderData.Read(reader);
            }
        }
예제 #3
0
        private static void LoadTileEntities(string prefabName, Vector3i pos1, Vector3i pos2, int rotate)
        {
            var filePath = Path.Combine(Constants.PrefabsFolder, prefabName + Export.TileEntityFileExtension);
            var world    = GameManager.Instance.World;
            int tileEntitiyCount;

            using (var reader = new BinaryReader(new FileStream(filePath, FileMode.Open)))
            {
                // File header
                var fileName   = prefabName + Export.TileEntityFileExtension;
                var fileMarker = reader.ReadString();
                if (fileMarker != Export.TileEntityFileMarker)                              // [string]  constant "7DTD-TE"
                {
                    throw new FriendlyMessageException($"File {fileName} is not a valid tile entity file for 7DTD.");
                }

                var fileVersion = reader.ReadInt32();                                       // [Int32]   file version number
                if (fileVersion != Export.TileEntityFileVersion)
                {
                    throw new FriendlyMessageException($"File format version of {fileName} is {fileVersion} but only {Export.TileEntityFileVersion} is supported.");
                }

                var originalPos1 = NetworkUtils.ReadVector3i(reader);                       // [Vector3i] original area worldPos1
                // ReSharper disable once UnusedVariable
                var originalPos2 = NetworkUtils.ReadVector3i(reader);                       // [Vector3i] original area worldPos2
                var posDelta     = pos1 - originalPos1;

                // See Assembly-CSharp::Chunk.read() -> search "tileentity.read"
                tileEntitiyCount = reader.ReadInt32();                                      // [Int32]   number of tile entities
                for (int i = 0; i < tileEntitiyCount; i++)
                {
                    var posInPrefab = NetworkUtils.ReadVector3i(reader);                    // [3xInt32] position relative to prefab
                    posInPrefab = RotatePosition(posInPrefab, pos2 - pos1, rotate);

                    var posInWorld = pos1 + posInPrefab;
                    var posInChunk = World.toBlock(posInWorld);
                    var chunk      = world.GetChunkFromWorldPos(posInWorld) as Chunk;
                    if (chunk == null)
                    {
                        throw new FriendlyMessageException(Resources.ErrorAreaTooFarAway);
                    }

                    var tileEntityType = (TileEntityType)reader.ReadByte();                 // [byte]    TileEntityType enum
                    var tileEntity     = chunk.GetTileEntity(posInChunk);

                    // Create new tile entity if Prefab import didn't create it yet; it's only created for some blocks apparently
                    if (tileEntity == null)
                    {
                        tileEntity = TileEntity.Instantiate(tileEntityType, chunk);
                        tileEntity.localChunkPos = posInChunk;
                        chunk.AddTileEntity(tileEntity);
                        Log.Debug($"Tile entity at position {posInWorld} was not created by Prefab import, therefore a new one was created and added: {tileEntity.ToStringBetter()}");
                    }

                    // Make sure we are dealing with the correct type; you never know...
                    if (tileEntity.GetTileEntityType() != tileEntityType)
                    {
                        throw new ApplicationException($"Tile entity {tileEntity.GetType()} [{tileEntity.ToWorldPos()}] has wrong type {tileEntity.GetTileEntityType()} when it should have {tileEntityType}.");
                    }

                    LoadTileEntity(reader, tileEntity, posDelta);                             // [dynamic] tile entity data depending on type

                    // Make sure localChunkPos was adjusted correctly during read
                    if (tileEntity.localChunkPos != posInChunk)
                    {
                        throw new ApplicationException($"Tile entity {tileEntity.GetType()} ({tileEntity.GetTileEntityType()} should have localChunkPos {posInChunk} but has {tileEntity.localChunkPos} instead.");
                    }

                    var tileEntityPowered = tileEntity as TileEntityPowered;
                    if (tileEntityPowered != null)
                    {
                        var powerItem = tileEntityPowered.GetPowerItem();
                        if (powerItem == null)
                        {
                            throw new ApplicationException("For imported TileEntityPowered no PowerItem was created during TileEntityPowered.read.");
                        }

                        LoadPowerItem(reader, powerItem, posDelta);
                    }
                }
            }

            Log.Out($"Imported {tileEntitiyCount} tile entities for prefab {prefabName} into area {pos1} to {pos2}.");
        }
예제 #4
0
        public void Read(BinaryReader reader)
        {
            entityCreationDataVersion = new Value <byte>(reader.ReadByte());
            entityClass = new Value <int>(reader.ReadInt32());

            id       = new Value <int>(reader.ReadInt32());
            lifetime = new Value <float>(reader.ReadSingle());

            pos   = new Vector3D <float>();
            pos.x = new Value <float>(reader.ReadSingle());
            pos.y = new Value <float>(reader.ReadSingle());
            pos.z = new Value <float>(reader.ReadSingle());

            rot   = new Vector3D <float>();
            rot.x = new Value <float>(reader.ReadSingle());
            rot.y = new Value <float>(reader.ReadSingle());
            rot.z = new Value <float>(reader.ReadSingle());

            onGround = new Value <bool>(reader.ReadBoolean());

            bodyDamage = new BodyDamage();
            bodyDamage.Read(reader);

            bool isStatsNotNull = reader.ReadBoolean();

            if (isStatsNotNull)
            {
                stats = new EntityStats();
                stats.Read(reader);
            }

            deathTime = new Value <int>((int)reader.ReadInt16());


            bool tileEntityNotNull = reader.ReadBoolean();

            if (tileEntityNotNull)
            {
                type          = new Value <int>(reader.ReadInt32());
                lootContainer = TileEntity.Instantiate((TileEntityType)(type.Get()));
                lootContainer.Read(reader);
            }

            homePosition   = new Vector3D <int>();
            homePosition.x = new Value <int>(reader.ReadInt32());
            homePosition.y = new Value <int>(reader.ReadInt32());
            homePosition.z = new Value <int>(reader.ReadInt32());

            unknownD      = new Value <int>((int)reader.ReadInt16());
            spawnerSource = (EnumSpawnerSource)reader.ReadByte();

            if (entityClass.Get() == Utils.GetMonoHash("item"))
            {
                belongsPlayerId = new Value <int>(reader.ReadInt32());
                itemStack.Read(reader);

                reader.ReadSByte();
            }

            else if (entityClass.Get() == Utils.GetMonoHash("fallingBlock"))
            {
                blockValueRawData = new Value <uint>(reader.ReadUInt32());
            }

            else if (entityClass.Get() == Utils.GetMonoHash("fallingTree"))
            {
                blockPosition   = new Vector3D <int>();
                blockPosition.x = new Value <int>(reader.ReadInt32());
                blockPosition.y = new Value <int>(reader.ReadInt32());
                blockPosition.z = new Value <int>(reader.ReadInt32());

                fallTreeDir   = new Vector3D <float>();
                fallTreeDir.x = new Value <float>(reader.ReadSingle());
                fallTreeDir.y = new Value <float>(reader.ReadSingle());
                fallTreeDir.z = new Value <float>(reader.ReadSingle());
            }

            else if ((entityClass.Get() == Utils.GetMonoHash("playerMale")) || (entityClass.Get() == Utils.GetMonoHash("playerFemale")))
            {
                holdingItem = new ItemValue();
                holdingItem.Read(reader);
                teamNumber  = new Value <int>((int)reader.ReadByte());
                entityName  = new Value <string>(reader.ReadString());
                skinTexture = new Value <string>(reader.ReadString());

                bool isPlayerProfileNotNull = reader.ReadBoolean();
                if (isPlayerProfileNotNull)
                {
                    playerProfile = PlayerProfile.Read(reader);
                }
                else
                {
                    playerProfile = null;
                }
            }

            //num2
            int entityDataLength = (int)reader.ReadUInt16();

            if (entityDataLength > 0)
            {
                byte[] buffer = reader.ReadBytes(entityDataLength);
                entityData = new MemoryStream(buffer);
            }

            isTraderEntity = new Value <bool>(reader.ReadBoolean());
        }