From 4805dd800c4417468d6f0157d61f593ede1a3562 Mon Sep 17 00:00:00 2001 From: Boblet Date: Wed, 10 Sep 2025 16:30:13 +0200 Subject: [PATCH] the slow dance (it's actually rather fast) --- .../tileentity/RenderAssemblyFactory.java | 97 ++++-- .../TileEntityMachineAssemblyFactory.java | 283 ++++++++++++++++-- 2 files changed, 329 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/hbm/render/tileentity/RenderAssemblyFactory.java b/src/main/java/com/hbm/render/tileentity/RenderAssemblyFactory.java index 25cf3f70a..a303ef057 100644 --- a/src/main/java/com/hbm/render/tileentity/RenderAssemblyFactory.java +++ b/src/main/java/com/hbm/render/tileentity/RenderAssemblyFactory.java @@ -4,17 +4,28 @@ import org.lwjgl.opengl.GL11; import com.hbm.blocks.BlockDummyable; import com.hbm.blocks.ModBlocks; +import com.hbm.inventory.recipes.AssemblyMachineRecipes; +import com.hbm.inventory.recipes.loader.GenericRecipe; +import com.hbm.main.MainRegistry; import com.hbm.main.ResourceManager; import com.hbm.render.item.ItemRenderBase; import com.hbm.tileentity.machine.TileEntityMachineAssemblyFactory; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.item.EntityItem; import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.client.IItemRenderer; public class RenderAssemblyFactory extends TileEntitySpecialRenderer implements IItemRendererProvider { + + public static EntityItem dummy; @Override public void renderTileEntityAt(TileEntity tileEntity, double x, double y, double z, float interp) { @@ -36,25 +47,29 @@ public class RenderAssemblyFactory extends TileEntitySpecialRenderer implements ResourceManager.assembly_factory.renderPart("Base"); if(assemfac.frame) ResourceManager.assembly_factory.renderPart("Frame"); - double[] arm1 = new double[] {-30, -30, -30, -0.125}; - double[] arm2 = new double[] {-30, -30, -30, -0.125}; - double blade = (System.currentTimeMillis() / 1) % 360D; + double slide1 = assemfac.animations[0].getSlider(interp); + double slide2 = assemfac.animations[1].getSlider(interp); + double[] arm1 = assemfac.animations[0].striker.getPositions(interp); + double[] arm2 = assemfac.animations[0].saw.getPositions(interp); + double[] arm3 = assemfac.animations[1].striker.getPositions(interp); + double[] arm4 = assemfac.animations[1].saw.getPositions(interp); GL11.glPushMatrix(); { + GL11.glTranslated(0.5 - slide1, 0, 0); ResourceManager.assembly_factory.renderPart("Slider1"); GL11.glTranslated(0, 1.625, -0.9375); - GL11.glRotated(arm1[0], 1, 0, 0); + GL11.glRotated(-arm1[0], 1, 0, 0); GL11.glTranslated(0, -1.625, 0.9375); ResourceManager.assembly_factory.renderPart("ArmLower1"); GL11.glTranslated(0, 2.375, -0.9375); - GL11.glRotated(arm1[1], 1, 0, 0); + GL11.glRotated(-arm1[1], 1, 0, 0); GL11.glTranslated(0, -2.375, 0.9375); ResourceManager.assembly_factory.renderPart("ArmUpper1"); GL11.glTranslated(0, 2.375, -0.4375); - GL11.glRotated(arm1[2], 1, 0, 0); + GL11.glRotated(-arm1[2], 1, 0, 0); GL11.glTranslated(0, -2.375, 0.4375); ResourceManager.assembly_factory.renderPart("Head1"); GL11.glTranslated(0, arm1[3], 0); @@ -62,75 +77,119 @@ public class RenderAssemblyFactory extends TileEntitySpecialRenderer implements } GL11.glPopMatrix(); GL11.glPushMatrix(); { + GL11.glTranslated(-0.5 + slide1, 0, 0); ResourceManager.assembly_factory.renderPart("Slider2"); GL11.glTranslated(0, 1.625, 0.9375); - GL11.glRotated(-arm2[0], 1, 0, 0); + GL11.glRotated(arm2[0], 1, 0, 0); GL11.glTranslated(0, -1.625, -0.9375); ResourceManager.assembly_factory.renderPart("ArmLower2"); GL11.glTranslated(0, 2.375, 0.9375); - GL11.glRotated(-arm2[1], 1, 0, 0); + GL11.glRotated(arm2[1], 1, 0, 0); GL11.glTranslated(0, -2.375, -0.9375); ResourceManager.assembly_factory.renderPart("ArmUpper2"); GL11.glTranslated(0, 2.375, 0.4375); - GL11.glRotated(-arm2[2], 1, 0, 0); + GL11.glRotated(arm2[2], 1, 0, 0); GL11.glTranslated(0, -2.375, -0.4375); ResourceManager.assembly_factory.renderPart("Head2"); GL11.glTranslated(0, arm2[3], 0); ResourceManager.assembly_factory.renderPart("Striker2"); GL11.glTranslated(0, 1.625, 0.3125); - GL11.glRotated(-blade, 1, 0, 0); + GL11.glRotated(-arm2[4], 1, 0, 0); GL11.glTranslated(0, -1.625, -0.3125); ResourceManager.assembly_factory.renderPart("Blade2"); } GL11.glPopMatrix(); GL11.glPushMatrix(); { + GL11.glTranslated(-0.5 + slide2, 0, 0); ResourceManager.assembly_factory.renderPart("Slider3"); GL11.glTranslated(0, 1.625, 0.9375); - GL11.glRotated(-arm2[0], 1, 0, 0); + GL11.glRotated(arm3[0], 1, 0, 0); GL11.glTranslated(0, -1.625, -0.9375); ResourceManager.assembly_factory.renderPart("ArmLower3"); GL11.glTranslated(0, 2.375, 0.9375); - GL11.glRotated(-arm2[1], 1, 0, 0); + GL11.glRotated(arm3[1], 1, 0, 0); GL11.glTranslated(0, -2.375, -0.9375); ResourceManager.assembly_factory.renderPart("ArmUpper3"); GL11.glTranslated(0, 2.375, 0.4375); - GL11.glRotated(-arm2[2], 1, 0, 0); + GL11.glRotated(arm3[2], 1, 0, 0); GL11.glTranslated(0, -2.375, -0.4375); ResourceManager.assembly_factory.renderPart("Head3"); - GL11.glTranslated(0, arm2[3], 0); + GL11.glTranslated(0, arm3[3], 0); ResourceManager.assembly_factory.renderPart("Striker3"); } GL11.glPopMatrix(); GL11.glPushMatrix(); { + GL11.glTranslated(0.5 - slide2, 0, 0); ResourceManager.assembly_factory.renderPart("Slider4"); GL11.glTranslated(0, 1.625, -0.9375); - GL11.glRotated(arm1[0], 1, 0, 0); + GL11.glRotated(-arm4[0], 1, 0, 0); GL11.glTranslated(0, -1.625, 0.9375); ResourceManager.assembly_factory.renderPart("ArmLower4"); GL11.glTranslated(0, 2.375, -0.9375); - GL11.glRotated(arm1[1], 1, 0, 0); + GL11.glRotated(-arm4[1], 1, 0, 0); GL11.glTranslated(0, -2.375, 0.9375); ResourceManager.assembly_factory.renderPart("ArmUpper4"); GL11.glTranslated(0, 2.375, -0.4375); - GL11.glRotated(arm1[2], 1, 0, 0); + GL11.glRotated(-arm4[2], 1, 0, 0); GL11.glTranslated(0, -2.375, 0.4375); ResourceManager.assembly_factory.renderPart("Head4"); - GL11.glTranslated(0, arm1[3], 0); + GL11.glTranslated(0, arm4[3], 0); ResourceManager.assembly_factory.renderPart("Striker4"); GL11.glTranslated(0, 1.625, -0.3125); - GL11.glRotated(blade, 1, 0, 0); + GL11.glRotated(-arm4[4], 1, 0, 0); GL11.glTranslated(0, -1.625, 0.3125); ResourceManager.assembly_factory.renderPart("Blade4"); } GL11.glPopMatrix(); + + if(MainRegistry.proxy.me().getDistanceSq(tileEntity.xCoord + 0.5, tileEntity.yCoord + 1, tileEntity.zCoord + 0.5) < 35 * 35) { + + for(int i = 0; i < 4; i++) { + + GL11.glPushMatrix(); + GL11.glTranslated(1.5 - i, 0, 0); + + GL11.glRotated(90, 0, 1, 0); + GL11.glTranslated(0, 1.0625, 0); + + GenericRecipe recipe = AssemblyMachineRecipes.INSTANCE.recipeNameMap.get(assemfac.assemblerModule[i].recipe); + if(recipe != null) { + ItemStack stack = recipe.getIcon(); + stack.stackSize = 1; + + if(stack.getItemSpriteNumber() == 0 && stack.getItem() instanceof ItemBlock) { + if(RenderBlocks.renderItemIn3d(Block.getBlockFromItem(stack.getItem()).getRenderType())) { + GL11.glTranslated(0, -0.0625, 0); + } else { + GL11.glTranslated(0, -0.125, 0); + GL11.glScaled(0.5, 0.5, 0.5); + } + } else { + GL11.glRotated(-90, 1, 0, 0); + GL11.glTranslated(0, -0.25, 0); + } + + GL11.glScaled(1.25, 1.25, 1.25); + + if(dummy == null || dummy.worldObj != tileEntity.getWorldObj()) dummy = new EntityItem(tileEntity.getWorldObj(), 0, 0, 0, stack); + dummy.setEntityItemStack(stack); + dummy.hoverStart = 0.0F; + + RenderItem.renderInFrame = true; + RenderManager.instance.renderEntityWithPosYaw(dummy, 0.0D, 0.0D, 0.0D, 0.0F, 0.0F); + RenderItem.renderInFrame = false; + } + GL11.glPopMatrix(); + } + } GL11.glShadeModel(GL11.GL_FLAT); GL11.glPopMatrix(); diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAssemblyFactory.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAssemblyFactory.java index a978e5536..0133331ac 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAssemblyFactory.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineAssemblyFactory.java @@ -25,7 +25,6 @@ import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.IUpgradeInfoProvider; import com.hbm.tileentity.TileEntityMachineBase; import com.hbm.tileentity.TileEntityProxyDyn.IProxyDelegateProvider; -import com.hbm.tileentity.machine.TileEntityMachineAssemblyMachine.AssemblerArm.ArmActionState; import com.hbm.util.BobMathUtil; import com.hbm.util.fauxpointtwelve.DirPos; import com.hbm.util.i18n.I18nUtil; @@ -61,6 +60,7 @@ public class TileEntityMachineAssemblyFactory extends TileEntityMachineBase impl public boolean frame = false; private AudioWrapper audio; + public TragicYuri[] animations; public ModuleMachineAssembler[] assemblerModule; public UpgradeManagerNT upgradeManager = new UpgradeManagerNT(this); @@ -70,6 +70,9 @@ public class TileEntityMachineAssemblyFactory extends TileEntityMachineBase impl public TileEntityMachineAssemblyFactory() { super(60); + animations = new TragicYuri[2]; + for(int i = 0; i < animations.length; i++) animations[i] = new TragicYuri(); + this.inputTanks = new FluidTank[4]; this.outputTanks = new FluidTank[4]; for(int i = 0; i < 4; i++) { @@ -183,6 +186,8 @@ public class TileEntityMachineAssemblyFactory extends TileEntityMachineBase impl this.networkPackNT(100); } else { + for(TragicYuri animation : animations) animation.update(true || didProcess[0] ||didProcess[1] ||didProcess[2] ||didProcess[3]); + if(worldObj.getTotalWorldTime() % 20 == 0) { frame = !worldObj.getBlock(xCoord, yCoord + 3, zCoord).isAir(worldObj, xCoord, yCoord + 3, zCoord); } @@ -410,51 +415,265 @@ public class TileEntityMachineAssemblyFactory extends TileEntityMachineBase impl @Override public FluidTank[] getAllTanks() { return TileEntityMachineAssemblyFactory.this.getAllTanks(); } } - public static class TragicYuri { + /** + * Carriage consisting of two arms - a striker and a saw + * Movement of both arms is inverted, one pedestal can only be serviced by one arm at a time + * + * @author hbm + */ + public class TragicYuri { - } - - public static class AssemblerArm { - - public double[] angles = new double[4]; - public double[] prevAngles = new double[4]; - public double[] targetAngles = new double[4]; - public double[] speed = new double[4]; - public double sawAngle; - public double prevSawAngle; + public AssemblerArm striker; + public AssemblerArm saw; Random rand = new Random(); - ArmActionState state = ArmActionState.ASSUME_POSITION; - int actionDelay = 0; - boolean saw = false; + YuriState state = YuriState.WORKING; + double slider = 0; + double prevSlider = 0; + boolean direction = false; + int timeUntilReposition; - public AssemblerArm() { - this.resetSpeed(); + public TragicYuri() { + striker = new AssemblerArm(); + saw = new AssemblerArm().yepThatsASaw(); + timeUntilReposition = 200; } - private void resetSpeed() { - speed[0] = 15; //Pivot - speed[1] = 15; //Arm - speed[2] = 15; //Piston - speed[3] = 0.5; //Striker + public void update(boolean working) { + this.prevSlider = this.slider; + + if(working) switch(state) { + case WORKING: { + timeUntilReposition--; + if(timeUntilReposition <= 0) { + state = YuriState.RETIRING; + } + } break; + case RETIRING: { + if(striker.state == ArmState.WAIT && saw.state == ArmState.WAIT) { // only progress as soon as both arms are done moving + state = YuriState.SLIDING; + direction = !direction; + if(!muffled) MainRegistry.proxy.playSoundClient(xCoord, yCoord, zCoord, "hbm:block.assemblerStart", getVolume(0.25F), 1.25F + worldObj.rand.nextFloat() * 0.25F); + } + } break; + case SLIDING: { + double sliderSpeed = 1D / 20D; // 20 ticks for transit + if(direction) { + slider += sliderSpeed; + if(slider >= 1) { + slider = 1; + state = YuriState.WORKING; + } + } else { + slider -= sliderSpeed; + if(slider <= 0) { + slider = 0; + state = YuriState.WORKING; + } + } + if(state == YuriState.WORKING) timeUntilReposition = 140 + rand.nextInt(161); // 7 to 15 seconds + } break; + } + + striker.updateArm(working); + saw.updateArm(working); } - public double[] getPositions(float interp) { - return new double[] { - BobMathUtil.interp(this.prevAngles[0], this.angles[0], interp), - BobMathUtil.interp(this.prevAngles[1], this.angles[1], interp), - BobMathUtil.interp(this.prevAngles[2], this.angles[2], interp), - BobMathUtil.interp(this.prevAngles[3], this.angles[3], interp), - BobMathUtil.interp(this.prevSawAngle, this.sawAngle, interp) - }; + public double getSlider(float interp) { + return this.prevSlider + (this.slider - this.prevSlider) * interp; + } + + // there's a ton of way to make this more optimized/readable/professional/scrungular but i don't care i am happy this crap works at all + public class AssemblerArm { // more fucking nesting!!!11 + + public double[] angles = new double[4]; + public double[] prevAngles = new double[4]; + public double[] targetAngles = new double[4]; + public double[] speed = new double[4]; + public double sawAngle; + public double prevSawAngle; + + ArmState state = ArmState.REPOSITION; + int actionDelay = 0; + boolean saw = false; + + public AssemblerArm() { + this.resetSpeed(); + this.chooseNewArmPoistion(); + } + + public AssemblerArm yepThatsASaw() { this.saw = true; this.chooseNewArmPoistion(); return this; } + + private void resetSpeed() { + speed[0] = 15; //Pivot + speed[1] = 15; //Arm + speed[2] = 15; //Piston + speed[3] = saw ? 0.125 : 0.5; //Striker + } + + public void updateArm(boolean working) { + resetSpeed(); + + for(int i = 0; i < angles.length; i++) { + prevAngles[i] = angles[i]; + } + + prevSawAngle = sawAngle; + + if(!working) return; + + if(state == ArmState.CUT || state == ArmState.EXTEND) { + this.sawAngle += 45D; + } + + if(actionDelay > 0) { + actionDelay--; + return; + } + + switch(state) { + // Move. If done moving, set a delay and progress to EXTEND + case REPOSITION: { + if(move()) { + actionDelay = 2; + state = ArmState.EXTEND; + targetAngles[3] = saw ? -0.375D : -0.75D; + } + } break; + case EXTEND: + if(move()) { + + if(saw) { + state = ArmState.CUT; + targetAngles[2] = -targetAngles[2]; + } else { + state = ArmState.RETRACT; + targetAngles[3] = 0D; + if(!muffled) MainRegistry.proxy.playSoundClient(xCoord, yCoord, zCoord, "hbm:block.assemblerStrike", getVolume(0.5F), 1F); + } + } + break; + case CUT: { + speed[2] = Math.abs(targetAngles[2] / 20D); + if(move()) { + state = ArmState.RETRACT; + targetAngles[3] = 0D; + } + } break; + case RETRACT: + if(move()) { + actionDelay = 2 + rand.nextInt(5); + chooseNewArmPoistion(); + state = TragicYuri.this.state == YuriState.RETIRING ? ArmState.RETIRE : ArmState.REPOSITION; + } + break; + case RETIRE: { + this.targetAngles[0] = 0; + this.targetAngles[1] = 0; + this.targetAngles[2] = 0; + this.targetAngles[3] = 0; + + if(move()) { + actionDelay = 2 + rand.nextInt(5); + chooseNewArmPoistion(); + state = ArmState.WAIT; + } + } break; + case WAIT: { + if(TragicYuri.this.state == YuriState.WORKING) this.state = ArmState.REPOSITION; + } break; + } + } + + public void chooseNewArmPoistion() { + + double[][] pos = !saw ? new double[][] { + // striker + {10, 10, -10}, + {15, 15, -15}, + {25, 10, -15}, + {30, 0, -10}, + {-10, 10, 0}, + {-20, 30, -15} + } : new double[][] { + // saw + {-15, 15, -10}, + {-15, 15, -15}, + {-15, 15, 10}, + {-15, 15, 15}, + {-15, 15, 2}, + {-15, 15, -2} + }; + + int chosen = rand.nextInt(pos.length); + this.targetAngles[0] = pos[chosen][0]; + this.targetAngles[1] = pos[chosen][1]; + this.targetAngles[2] = pos[chosen][2]; + } + + private boolean move() { + boolean didMove = false; + + for(int i = 0; i < angles.length; i++) { + if(angles[i] == targetAngles[i]) + continue; + + didMove = true; + + double angle = angles[i]; + double target = targetAngles[i]; + double turn = speed[i]; + double delta = Math.abs(angle - target); + + if(delta <= turn) { + angles[i] = targetAngles[i]; + continue; + } + + if(angle < target) { + angles[i] += turn; + } else { + angles[i] -= turn; + } + } + + return !didMove; + } + + public double[] getPositions(float interp) { + return new double[] { + BobMathUtil.interp(this.prevAngles[0], this.angles[0], interp), + BobMathUtil.interp(this.prevAngles[1], this.angles[1], interp), + BobMathUtil.interp(this.prevAngles[2], this.angles[2], interp), + BobMathUtil.interp(this.prevAngles[3], this.angles[3], interp), + BobMathUtil.interp(this.prevSawAngle, this.sawAngle, interp) + }; + } } } + /* + * Arms cycle through REPOSITION -> EXTEND -> CUT (if saw) -> RETRACT + * If transit is planned, the carriage's state will change to RETIRING + * If the carriage is RETIRING, each arm will enter RETIRE state after RETRACT + * Once the arm has returned to null position, it changes to WAIT + * If both arms WAIT, the carriage switches to SLIDING + * Once transit is done, carriage returns to WORKING + * If the carriage is WORKING, any arm that is in the WAIT state will return to REPOSITION + */ + public static enum YuriState { - WORKING, RETIRING, SLIDING + WORKING, + RETIRING, // waiting for arms to enter WAITING state + SLIDING // transit to next position } public static enum ArmState { - REPOSITION, EXTEND, CUT, RETRACT, RETIRE + REPOSITION, + EXTEND, + CUT, + RETRACT, + RETIRE, // return to null position for carriage transit + WAIT // either waiting for or in the middle of carriage transit } }