private Vec3i findFreeMetalVoxel() { SmithingRecipe recipe = SelectedRecipe; int ymax = recipe.QuantityLayers; for (int y = 5; y >= 0; y--) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { bool requireMetalHere = y >= ymax ? false : recipe.Voxels[x, y, z]; EnumVoxelMaterial mat = (EnumVoxelMaterial)Voxels[x, y, z]; if (!requireMetalHere && mat == EnumVoxelMaterial.Metal) { return(new Vec3i(x, y, z)); } } } } return(null); }
private void spawnParticles(Vec3i voxelPos, EnumVoxelMaterial voxelMat, IPlayer byPlayer) { float temp = workItemStack.Collectible.GetTemperature(Api.World, workItemStack); if (voxelMat == EnumVoxelMaterial.Metal && temp > 800) { bigMetalSparks.MinPos = Pos.ToVec3d().AddCopy(voxelPos.X / 16f, voxYOff + voxelPos.Y / 16f + 0.0625f, voxelPos.Z / 16f); bigMetalSparks.AddPos.Set(1 / 16f, 0, 1 / 16f); bigMetalSparks.VertexFlags = (byte)GameMath.Clamp((int)(temp - 700) / 2, 32, 128); Api.World.SpawnParticles(bigMetalSparks, byPlayer); smallMetalSparks.MinPos = Pos.ToVec3d().AddCopy(voxelPos.X / 16f, voxYOff + voxelPos.Y / 16f + 0.0625f, voxelPos.Z / 16f); smallMetalSparks.VertexFlags = (byte)GameMath.Clamp((int)(temp - 770) / 3, 32, 128); smallMetalSparks.AddPos.Set(1 / 16f, 0, 1 / 16f); Api.World.SpawnParticles(smallMetalSparks, byPlayer); } if (voxelMat == EnumVoxelMaterial.Slag) { slagPieces.Color = workItemStack.Collectible.GetRandomColor(Api as ICoreClientAPI, workItemStack); slagPieces.MinPos = Pos.ToVec3d().AddCopy(voxelPos.X / 16f, voxYOff + voxelPos.Y / 16f + 0.0625f, voxelPos.Z / 16f); Api.World.SpawnParticles(slagPieces, byPlayer); } }
void onHelveHitSuccess(EnumVoxelMaterial mat, Vec3i usableMetalVoxel, int x, int y, int z) { if (Api.World.Side == EnumAppSide.Client) { spawnParticles(new Vec3i(x, y, z), mat == EnumVoxelMaterial.Empty ? EnumVoxelMaterial.Metal : mat, null); if (usableMetalVoxel != null) { spawnParticles(usableMetalVoxel, EnumVoxelMaterial.Metal, null); } } RegenMeshAndSelectionBoxes(); CheckIfFinished(null); }
private void RegenOutlineMesh(bool[,,] recipeToOutlineVoxels, byte[,,] voxels) { recipeOutlineMeshRef?.Dispose(); MeshData recipeOutlineMesh = new MeshData(24, 36, false, false, true, false); recipeOutlineMesh.SetMode(EnumDrawMode.Lines); int greenCol = (170 << 24) | (100 << 16) | (200 << 8) | (100); int orangeCol = (220 << 24) | (75 << 16) | (0 << 8) | (47); MeshData greenVoxelMesh = LineMeshUtil.GetCube(greenCol); MeshData orangeVoxelMesh = LineMeshUtil.GetCube(orangeCol); for (int i = 0; i < greenVoxelMesh.xyz.Length; i++) { greenVoxelMesh.xyz[i] = greenVoxelMesh.xyz[i] / 32f + 1 / 32f; orangeVoxelMesh.xyz[i] = orangeVoxelMesh.xyz[i] / 32f + 1 / 32f; } MeshData voxelMeshOffset = greenVoxelMesh.Clone(); int yMax = recipeToOutlineVoxels.GetLength(1); for (int x = 0; x < 16; x++) { for (int y = 0; y < 6; y++) { for (int z = 0; z < 16; z++) { bool requireMetalHere = y >= yMax ? false : recipeToOutlineVoxels[x, y, z]; EnumVoxelMaterial mat = (EnumVoxelMaterial)voxels[x, y, z]; if (requireMetalHere && mat == EnumVoxelMaterial.Metal) { continue; } if (!requireMetalHere && mat == EnumVoxelMaterial.Empty) { continue; } float px = x / 16f; float py = 10 / 16f + y / 16f; float pz = z / 16f; for (int i = 0; i < greenVoxelMesh.xyz.Length; i += 3) { voxelMeshOffset.xyz[i] = px + greenVoxelMesh.xyz[i]; voxelMeshOffset.xyz[i + 1] = py + greenVoxelMesh.xyz[i + 1]; voxelMeshOffset.xyz[i + 2] = pz + greenVoxelMesh.xyz[i + 2]; } voxelMeshOffset.Rgba = (requireMetalHere && mat == EnumVoxelMaterial.Empty) ? greenVoxelMesh.Rgba : orangeVoxelMesh.Rgba; recipeOutlineMesh.AddMeshData(voxelMeshOffset); } } } recipeOutlineMeshRef = api.Render.UploadMesh(recipeOutlineMesh); }
public virtual void OnHelveHammerHit() { if (workItemStack == null || !CanWorkCurrent) { return; } SmithingRecipe recipe = SelectedRecipe; if (recipe == null) { return; } var mode = (workItemStack.Collectible as IAnvilWorkable).GetHelveWorkableMode(workItemStack, this); if (mode == EnumHelveWorkableMode.NotWorkable) { return; } rotation = 0; int ymax = recipe.QuantityLayers; Vec3i usableMetalVoxel; if (mode == EnumHelveWorkableMode.TestSufficientVoxelsWorkable) { usableMetalVoxel = findFreeMetalVoxel(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 6; y++) { bool requireMetalHere = y >= ymax ? false : recipe.Voxels[x, y, z]; EnumVoxelMaterial mat = (EnumVoxelMaterial)Voxels[x, y, z]; if (mat == EnumVoxelMaterial.Slag) { Voxels[x, y, z] = (byte)EnumVoxelMaterial.Empty; onHelveHitSuccess(mat, null, x, y, z); return; } if (requireMetalHere && usableMetalVoxel != null && mat == EnumVoxelMaterial.Empty) { Voxels[x, y, z] = (byte)EnumVoxelMaterial.Metal; Voxels[usableMetalVoxel.X, usableMetalVoxel.Y, usableMetalVoxel.Z] = (byte)EnumVoxelMaterial.Empty; onHelveHitSuccess(mat, usableMetalVoxel, x, y, z); return; } } } } if (usableMetalVoxel != null) { Voxels[usableMetalVoxel.X, usableMetalVoxel.Y, usableMetalVoxel.Z] = (byte)EnumVoxelMaterial.Empty; onHelveHitSuccess(EnumVoxelMaterial.Metal, null, usableMetalVoxel.X, usableMetalVoxel.Y, usableMetalVoxel.Z); return; } } else { for (int y = 5; y >= 0; y--) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { bool requireMetalHere = y >= ymax ? false : recipe.Voxels[x, y, z]; EnumVoxelMaterial mat = (EnumVoxelMaterial)Voxels[x, y, z]; if (requireMetalHere && mat == EnumVoxelMaterial.Metal) { continue; } if (!requireMetalHere && mat == EnumVoxelMaterial.Empty) { continue; } if (requireMetalHere && mat == EnumVoxelMaterial.Empty) { Voxels[x, y, z] = (byte)EnumVoxelMaterial.Metal; } else { Voxels[x, y, z] = (byte)EnumVoxelMaterial.Empty; } onHelveHitSuccess(mat == EnumVoxelMaterial.Empty ? EnumVoxelMaterial.Metal : mat, null, x, y, z); return; } } } } }
internal void OnUseOver(IPlayer byPlayer, Vec3i voxelPos, BlockSelection blockSel) { if (voxelPos == null) { return; } if (SelectedRecipe == null) { ditchWorkItemStack(); return; } // Send a custom network packet for server side, because // serverside blockselection index is inaccurate if (Api.Side == EnumAppSide.Client) { SendUseOverPacket(byPlayer, voxelPos); } ItemSlot slot = byPlayer.InventoryManager.ActiveHotbarSlot; if (slot.Itemstack == null || !CanWorkCurrent) { return; } int toolMode = slot.Itemstack.Collectible.GetToolMode(slot, byPlayer, blockSel); float yaw = GameMath.Mod(byPlayer.Entity.Pos.Yaw, 2 * GameMath.PI); EnumVoxelMaterial voxelMat = (EnumVoxelMaterial)Voxels[voxelPos.X, voxelPos.Y, voxelPos.Z]; if (voxelMat != EnumVoxelMaterial.Empty) { spawnParticles(voxelPos, voxelMat, byPlayer); switch (toolMode) { case 0: OnHit(voxelPos); break; case 1: OnUpset(voxelPos, BlockFacing.NORTH.FaceWhenRotatedBy(0, yaw - GameMath.PIHALF, 0)); break; case 2: OnUpset(voxelPos, BlockFacing.EAST.FaceWhenRotatedBy(0, yaw - GameMath.PIHALF, 0)); break; case 3: OnUpset(voxelPos, BlockFacing.SOUTH.FaceWhenRotatedBy(0, yaw - GameMath.PIHALF, 0)); break; case 4: OnUpset(voxelPos, BlockFacing.WEST.FaceWhenRotatedBy(0, yaw - GameMath.PIHALF, 0)); break; case 5: OnSplit(voxelPos); break; } RegenMeshAndSelectionBoxes(); Api.World.BlockAccessor.MarkBlockDirty(Pos); Api.World.BlockAccessor.MarkBlockEntityDirty(Pos); slot.Itemstack.Collectible.DamageItem(Api.World, byPlayer.Entity, slot); if (!HasAnyMetalVoxel()) { workItemStack = null; return; } } CheckIfFinished(byPlayer); MarkDirty(); }
public static MeshData GenMesh(ICoreClientAPI capi, ItemStack workitemStack, byte[,,] voxels, out int textureId) { textureId = 0; if (workitemStack == null) { return(null); } MeshData workItemMesh = new MeshData(24, 36, false); workItemMesh.CustomBytes = new CustomMeshDataPartByte() { Conversion = DataConversion.NormalizedFloat, Count = workItemMesh.VerticesCount, InterleaveSizes = new int[] { 1 }, Instanced = false, InterleaveOffsets = new int[] { 0 }, InterleaveStride = 1, Values = new byte[workItemMesh.VerticesCount] }; TextureAtlasPosition tposMetal; TextureAtlasPosition tposSlag; if (workitemStack.Collectible.FirstCodePart() == "ironbloom") { tposSlag = capi.BlockTextureAtlas.GetPosition(capi.World.GetBlock(new AssetLocation("anvil-copper")), "ironbloom"); tposMetal = capi.BlockTextureAtlas.GetPosition(capi.World.GetBlock(new AssetLocation("ingotpile")), "iron"); } else { tposMetal = capi.BlockTextureAtlas.GetPosition(capi.World.GetBlock(new AssetLocation("ingotpile")), workitemStack.Collectible.LastCodePart()); tposSlag = tposMetal; } MeshData metalVoxelMesh = CubeMeshUtil.GetCubeOnlyScaleXyz(1 / 32f, 1 / 32f, new Vec3f(1 / 32f, 1 / 32f, 1 / 32f)); CubeMeshUtil.SetXyzFacesAndPacketNormals(metalVoxelMesh); metalVoxelMesh.CustomBytes = new CustomMeshDataPartByte() { Conversion = DataConversion.NormalizedFloat, Count = metalVoxelMesh.VerticesCount, Values = new byte[metalVoxelMesh.VerticesCount] }; textureId = tposMetal.atlasTextureId; metalVoxelMesh.XyzFaces = (byte[])CubeMeshUtil.CubeFaceIndices.Clone(); metalVoxelMesh.XyzFacesCount = 6; //metalVoxelMesh.ColorMapIds = new int[6]; //metalVoxelMesh.TintsCount = 6; for (int i = 0; i < metalVoxelMesh.Rgba.Length; i++) { metalVoxelMesh.Rgba[i] = 255; } //metalVoxelMesh.Rgba2 = null; MeshData slagVoxelMesh = metalVoxelMesh.Clone(); for (int i = 0; i < metalVoxelMesh.Uv.Length; i++) { if (i % 2 > 0) { metalVoxelMesh.Uv[i] = tposMetal.y1 + metalVoxelMesh.Uv[i] * 2f / capi.BlockTextureAtlas.Size.Height; slagVoxelMesh.Uv[i] = tposSlag.y1 + slagVoxelMesh.Uv[i] * 2f / capi.BlockTextureAtlas.Size.Height; } else { metalVoxelMesh.Uv[i] = tposMetal.x1 + metalVoxelMesh.Uv[i] * 2f / capi.BlockTextureAtlas.Size.Width; slagVoxelMesh.Uv[i] = tposSlag.x1 + slagVoxelMesh.Uv[i] * 2f / capi.BlockTextureAtlas.Size.Width; } } MeshData metVoxOffset = metalVoxelMesh.Clone(); MeshData slagVoxOffset = slagVoxelMesh.Clone(); for (int x = 0; x < 16; x++) { for (int y = 0; y < 6; y++) { for (int z = 0; z < 16; z++) { EnumVoxelMaterial mat = (EnumVoxelMaterial)voxels[x, y, z]; if (mat == EnumVoxelMaterial.Empty) { continue; } float px = x / 16f; float py = 10 / 16f + y / 16f; float pz = z / 16f; MeshData mesh = mat == EnumVoxelMaterial.Metal ? metalVoxelMesh : slagVoxelMesh; MeshData meshVoxOffset = mat == EnumVoxelMaterial.Metal ? metVoxOffset : slagVoxOffset; for (int i = 0; i < mesh.xyz.Length; i += 3) { meshVoxOffset.xyz[i] = px + mesh.xyz[i]; meshVoxOffset.xyz[i + 1] = py + mesh.xyz[i + 1]; meshVoxOffset.xyz[i + 2] = pz + mesh.xyz[i + 2]; } float textureSize = 32f / capi.BlockTextureAtlas.Size.Width; float offsetX = px * textureSize; float offsetY = (py * 32f) / capi.BlockTextureAtlas.Size.Width; float offsetZ = pz * textureSize; for (int i = 0; i < mesh.Uv.Length; i += 2) { meshVoxOffset.Uv[i] = mesh.Uv[i] + GameMath.Mod(offsetX + offsetY, textureSize); meshVoxOffset.Uv[i + 1] = mesh.Uv[i + 1] + GameMath.Mod(offsetZ + offsetY, textureSize); } for (int i = 0; i < meshVoxOffset.CustomBytes.Values.Length; i++) { byte glowSub = (byte)GameMath.Clamp(10 * (Math.Abs(x - 8) + Math.Abs(z - 8) + Math.Abs(y - 2)), 100, 250); meshVoxOffset.CustomBytes.Values[i] = (mat == EnumVoxelMaterial.Metal) ? (byte)0 : glowSub; } workItemMesh.AddMeshData(meshVoxOffset); } } } return(workItemMesh); }