Block baseBlockFromBlockType(BlockType blockType, AssetLocation fullcode, OrderedDictionary <string, string> variant) { BlockType typedBlockType = new BlockType() { Code = blockType.Code, VariantGroups = blockType.VariantGroups, Variant = new OrderedDictionary <string, string>(variant), Enabled = blockType.Enabled, jsonObject = blockType.jsonObject.DeepClone() as JObject }; try { solveByType(typedBlockType.jsonObject, fullcode.Path, variant); } catch (Exception e) { api.Server.Logger.Error("Exception thrown while trying to resolve *byType properties of typed block {0}. Will ignore most of the attributes. Exception thrown: {1}", typedBlockType.Code, e); } try { JsonUtil.PopulateObject(typedBlockType, typedBlockType.jsonObject.ToString(), fullcode.Domain); } catch (Exception e) { api.Server.Logger.Error("Exception thrown while trying to populate/load json data of the typed block {0}. Will ignore most of the attributes. Exception thrown: {1}", typedBlockType.Code, e); } typedBlockType.jsonObject = null; Block block; if (api.ClassRegistry.GetBlockClass(typedBlockType.Class) == null) { api.Server.Logger.Error("Block with code {0} has defined a block class {1}, no such class registered. Will ignore.", typedBlockType.Code, typedBlockType.Class); block = new Block(); } else { block = api.ClassRegistry.CreateBlock(typedBlockType.Class); } if (typedBlockType.EntityClass != null) { if (api.ClassRegistry.GetBlockEntity(typedBlockType.EntityClass) != null) { block.EntityClass = typedBlockType.EntityClass; } else { api.Server.Logger.Error("Block with code {0} has defined a block entity class {1}, no such class registered. Will ignore.", typedBlockType.Code, typedBlockType.EntityClass); } } block.Code = fullcode; block.VariantStrict = typedBlockType.Variant; block.Variant = new RelaxedReadOnlyDictionary <string, string>(typedBlockType.Variant); block.Class = typedBlockType.Class; block.LiquidSelectable = typedBlockType.LiquidSelectable; block.LiquidCode = typedBlockType.LiquidCode; block.BlockEntityBehaviors = (BlockEntityBehaviorType[])typedBlockType.EntityBehaviors?.Clone() ?? new BlockEntityBehaviorType[0]; block.WalkSpeedMultiplier = typedBlockType.WalkspeedMultiplier; block.DragMultiplier = typedBlockType.DragMultiplier; block.Durability = typedBlockType.Durability; block.DamagedBy = (EnumItemDamageSource[])typedBlockType.DamagedBy?.Clone(); block.Tool = typedBlockType.Tool; block.DrawType = typedBlockType.DrawType; block.Replaceable = typedBlockType.Replaceable; block.Fertility = typedBlockType.Fertility; block.LightAbsorption = typedBlockType.LightAbsorption; block.LightTraversable = new bool[] { typedBlockType.LightAbsorption < 2, typedBlockType.LightAbsorption < 2, typedBlockType.LightAbsorption < 2 }; if (typedBlockType.LightTraversable != null) { foreach (var val in typedBlockType.LightTraversable) { if (val.Key == "ns") { block.LightTraversable[2] = val.Value; } if (val.Key == "ud") { block.LightTraversable[1] = val.Value; } if (val.Key == "we") { block.LightTraversable[0] = val.Value; } } } block.LightHsv = typedBlockType.LightHsv; block.VertexFlags = typedBlockType.VertexFlags?.Clone() ?? new VertexFlags(0); block.Frostable = typedBlockType.Frostable; block.Resistance = typedBlockType.Resistance; block.BlockMaterial = typedBlockType.BlockMaterial; block.Shape = typedBlockType.Shape?.Clone(); block.Lod0Shape = typedBlockType.Lod0Shape?.Clone(); block.ShapeInventory = typedBlockType.ShapeInventory?.Clone(); block.TexturesInventory = typedBlockType.TexturesInventory; block.Textures = typedBlockType.Textures; block.ClimateColorMap = typedBlockType.ClimateColorMap; block.SeasonColorMap = typedBlockType.SeasonColorMap; block.Ambientocclusion = typedBlockType.Ambientocclusion; block.CollisionBoxes = typedBlockType.CollisionBoxes == null ? null : (Cuboidf[])typedBlockType.CollisionBoxes.Clone(); block.SelectionBoxes = typedBlockType.SelectionBoxes == null ? null : (Cuboidf[])typedBlockType.SelectionBoxes.Clone(); block.MaterialDensity = typedBlockType.MaterialDensity; block.GuiTransform = typedBlockType.GuiTransform; block.FpHandTransform = typedBlockType.FpHandTransform; block.TpHandTransform = typedBlockType.TpHandTransform; block.GroundTransform = typedBlockType.GroundTransform; block.RenderPass = typedBlockType.RenderPass; block.ParticleProperties = typedBlockType.ParticleProperties; block.Climbable = typedBlockType.Climbable; block.RainPermeable = typedBlockType.RainPermeable; block.SnowCoverage = typedBlockType.SnowCoverage; block.FaceCullMode = typedBlockType.FaceCullMode; block.Drops = typedBlockType.Drops; block.MaxStackSize = typedBlockType.MaxStackSize; block.MatterState = typedBlockType.MatterState; if (typedBlockType.Attributes != null) { block.Attributes = typedBlockType.Attributes.Clone(); } block.NutritionProps = typedBlockType.NutritionProps; block.TransitionableProps = typedBlockType.TransitionableProps; block.GrindingProps = typedBlockType.GrindingProps; block.LiquidLevel = typedBlockType.LiquidLevel; block.AttackPower = typedBlockType.AttackPower; block.MiningSpeed = typedBlockType.MiningSpeed; block.ToolTier = typedBlockType.ToolTier; block.RequiredMiningTier = typedBlockType.RequiredMiningTier; block.HeldSounds = typedBlockType.HeldSounds?.Clone(); block.AttackRange = typedBlockType.AttackRange; if (typedBlockType.Sounds != null) { block.Sounds = typedBlockType.Sounds.Clone(); } block.RandomDrawOffset = typedBlockType.RandomDrawOffset; block.RandomizeRotations = typedBlockType.RandomizeRotations; block.RandomizeAxes = typedBlockType.RandomizeAxes; block.CombustibleProps = typedBlockType.CombustibleProps; block.StorageFlags = (EnumItemStorageFlags)typedBlockType.StorageFlags; block.RenderAlphaTest = typedBlockType.RenderAlphaTest; block.HeldTpHitAnimation = typedBlockType.HeldTpHitAnimation; block.HeldRightTpIdleAnimation = typedBlockType.HeldRightTpIdleAnimation; block.HeldLeftTpIdleAnimation = typedBlockType.HeldLeftTpIdleAnimation; block.HeldTpUseAnimation = typedBlockType.HeldTpUseAnimation; block.CreativeInventoryStacks = typedBlockType.CreativeInventoryStacks == null ? null : (CreativeTabAndStackList[])typedBlockType.CreativeInventoryStacks.Clone(); block.AllowSpawnCreatureGroups = (string[])typedBlockType.AllowSpawnCreatureGroups.Clone(); // BlockType net only sends the collisionboxes at an accuracy of 1/10000 so we have to make sure they are the same server and client side if (block.CollisionBoxes != null) { for (int i = 0; i < block.CollisionBoxes.Length; i++) { block.CollisionBoxes[i].RoundToFracsOfOne10thousand(); } } if (block.SelectionBoxes != null) { for (int i = 0; i < block.SelectionBoxes.Length; i++) { block.SelectionBoxes[i].RoundToFracsOfOne10thousand(); } } typedBlockType.InitBlock(api.ClassRegistry, api.World.Logger, block, variant); return(block); }