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