Repository: FlansMods/FlansMod Branch: 1.12.2 Commit: 71ba7ed065d9 Files: 783 Total size: 10.6 MB Directory structure: gitextract_nyisj3dr/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── crash_report.md │ │ └── feature_request.md │ └── workflows/ │ └── gradle.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.bat ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── src/ └── main/ ├── java/ │ └── com/ │ └── flansmod/ │ ├── api/ │ │ ├── IControllable.java │ │ └── IExplodeable.java │ ├── apocalypse/ │ │ ├── client/ │ │ │ ├── ClientProxyApocalypse.java │ │ │ └── model/ │ │ │ ├── ModelBuggy.java │ │ │ ├── ModelGroundSkeleton.java │ │ │ ├── ModelGunRack.java │ │ │ ├── ModelNukeDrop.java │ │ │ ├── ModelPowerCube.java │ │ │ ├── ModelSkullBoss.java │ │ │ ├── ModelSkullDrone.java │ │ │ ├── ModelSlumpedSkeleton.java │ │ │ ├── ModelTeleporter.java │ │ │ ├── RenderFakePlayer.java │ │ │ ├── RenderNukeDrop.java │ │ │ ├── RenderPowerCube.java │ │ │ ├── RenderSkullBoss.java │ │ │ ├── RenderSkullDrone.java │ │ │ ├── RenderSurvivor.java │ │ │ └── RenderTeleporter.java │ │ └── common/ │ │ ├── ApocalypseData.java │ │ ├── CommonProxyApocalypse.java │ │ ├── FlansModApocalypse.java │ │ ├── FlansModLootGenerator.java │ │ ├── PropertyFloat.java │ │ ├── blocks/ │ │ │ ├── BlockPowerCube.java │ │ │ ├── BlockStatic.java │ │ │ ├── BlockSulphur.java │ │ │ ├── BlockSulphuricAcid.java │ │ │ └── TileEntityPowerCube.java │ │ ├── entity/ │ │ │ ├── EntityAIGoSomewhere.java │ │ │ ├── EntityAIMecha.java │ │ │ ├── EntityFakePlayer.java │ │ │ ├── EntityFlansModShooter.java │ │ │ ├── EntityFlyByPlane.java │ │ │ ├── EntityNukeDrop.java │ │ │ ├── EntitySkullBoss.java │ │ │ ├── EntitySkullDrone.java │ │ │ ├── EntitySkuller.java │ │ │ ├── EntitySurvivor.java │ │ │ └── EntityTeleporter.java │ │ ├── items/ │ │ │ └── ItemSulphuricAcidBucket.java │ │ ├── network/ │ │ │ └── PacketApocalypseCountdown.java │ │ └── world/ │ │ ├── BiomeApocalypse.java │ │ ├── BiomeDecoratorApocalypse.java │ │ ├── BiomeDesertCanyon.java │ │ ├── BiomeProviderApocalypse.java │ │ ├── BiomeSulphurPits.java │ │ ├── ChunkProviderApocalypse.java │ │ ├── GenLayerApocalypse.java │ │ ├── GenLayerBiomes.java │ │ ├── TeleporterApocalypse.java │ │ ├── WorldGenSulphurPool.java │ │ ├── WorldProviderApocalypse.java │ │ └── buildings/ │ │ ├── MapGenAbandonedVillage.java │ │ ├── StructureAbandonedVillagePieces.java │ │ ├── WorldGenAbandonedPortal.java │ │ ├── WorldGenBossPillar.java │ │ ├── WorldGenDeadTree.java │ │ ├── WorldGenDyeFactory.java │ │ ├── WorldGenFlan.java │ │ ├── WorldGenResearchLab.java │ │ ├── WorldGenRoads.java │ │ ├── WorldGenRunway.java │ │ └── WorldGenSkeleton.java │ ├── client/ │ │ ├── ClientProxy.java │ │ ├── ClientRenderHooks.java │ │ ├── EntityCamera.java │ │ ├── FlansModClient.java │ │ ├── MovingSoundDriveable.java │ │ ├── TileEntitySpawnerRenderer.java │ │ ├── debug/ │ │ │ ├── EntityDebugAABB.java │ │ │ ├── EntityDebugColor.java │ │ │ ├── EntityDebugDot.java │ │ │ ├── EntityDebugVector.java │ │ │ ├── RenderDebugAABB.java │ │ │ ├── RenderDebugDot.java │ │ │ └── RenderDebugVector.java │ │ ├── gui/ │ │ │ ├── GuiArmourBox.java │ │ │ ├── GuiDriveableController.java │ │ │ ├── GuiDriveableCrafting.java │ │ │ ├── GuiDriveableFuel.java │ │ │ ├── GuiDriveableInventory.java │ │ │ ├── GuiDriveableMenu.java │ │ │ ├── GuiDriveableRepair.java │ │ │ ├── GuiGunBox.java │ │ │ ├── GuiGunModTable.java │ │ │ ├── GuiMechaInventory.java │ │ │ ├── GuiPaintjobTable.java │ │ │ ├── config/ │ │ │ │ ├── ModGuiConfig.java │ │ │ │ └── ModGuiFactory.java │ │ │ └── teams/ │ │ │ ├── EnumLoadoutSlot.java │ │ │ ├── GuiBaseEditor.java │ │ │ ├── GuiChooseLoadout.java │ │ │ ├── GuiEditLoadout.java │ │ │ ├── GuiLandingPage.java │ │ │ ├── GuiMissionResults.java │ │ │ ├── GuiOpenRewardBox.java │ │ │ ├── GuiTeamScores.java │ │ │ ├── GuiTeamSelect.java │ │ │ ├── GuiTeamsBase.java │ │ │ └── GuiVoting.java │ │ ├── handlers/ │ │ │ ├── ClientEventHandler.java │ │ │ ├── FlansModResourceHandler.java │ │ │ ├── KeyInputHandler.java │ │ │ └── MouseInputHandler.java │ │ ├── model/ │ │ │ ├── AnimTankTrack.java │ │ │ ├── AnimTrackLink.java │ │ │ ├── CustomItemRenderType.java │ │ │ ├── CustomItemRenderer.java │ │ │ ├── EnumAnimationType.java │ │ │ ├── EnumMeleeAnimation.java │ │ │ ├── GunAnimations.java │ │ │ ├── InstantBulletRenderer.java │ │ │ ├── ModelAAGun.java │ │ │ ├── ModelAttachment.java │ │ │ ├── ModelBomb.java │ │ │ ├── ModelBullet.java │ │ │ ├── ModelCustomArmour.java │ │ │ ├── ModelDefaultMuzzleFlash.java │ │ │ ├── ModelDriveable.java │ │ │ ├── ModelFlagpole.java │ │ │ ├── ModelGun.java │ │ │ ├── ModelItemHolder.java │ │ │ ├── ModelMG.java │ │ │ ├── ModelMecha.java │ │ │ ├── ModelMechaTool.java │ │ │ ├── ModelMuzzleFlash.java │ │ │ ├── ModelNull.java │ │ │ ├── ModelPlane.java │ │ │ ├── ModelVehicle.java │ │ │ ├── RenderAAGun.java │ │ │ ├── RenderBullet.java │ │ │ ├── RenderFlag.java │ │ │ ├── RenderFlagpole.java │ │ │ ├── RenderGrenade.java │ │ │ ├── RenderGun.java │ │ │ ├── RenderGunItem.java │ │ │ ├── RenderItemHolder.java │ │ │ ├── RenderMG.java │ │ │ ├── RenderMecha.java │ │ │ ├── RenderNull.java │ │ │ ├── RenderParachute.java │ │ │ ├── RenderPlane.java │ │ │ └── RenderVehicle.java │ │ ├── teams/ │ │ │ └── ClientTeamsData.java │ │ ├── tmt/ │ │ │ ├── Angle3D.java │ │ │ ├── Bone.java │ │ │ ├── Coord2D.java │ │ │ ├── ModelPool.java │ │ │ ├── ModelPoolEntry.java │ │ │ ├── ModelPoolObjEntry.java │ │ │ ├── ModelRendererTurbo.java │ │ │ ├── PositionTextureVertex.java │ │ │ ├── PositionTransformVertex.java │ │ │ ├── Shape2D.java │ │ │ ├── Shape3D.java │ │ │ ├── TextureGroup.java │ │ │ ├── TexturedPolygon.java │ │ │ ├── TmtTessellator.java │ │ │ ├── TransformGroup.java │ │ │ └── TransformGroupBone.java │ │ └── util/ │ │ ├── FlansKeyConflictContext.java │ │ └── WorldRenderer.java │ ├── common/ │ │ ├── BlockFlansWorkbench.java │ │ ├── BlockItemHolder.java │ │ ├── CommonGuiHandler.java │ │ ├── CommonProxy.java │ │ ├── CommonTickHandler.java │ │ ├── ContentManager.java │ │ ├── CraftingInstance.java │ │ ├── CreativeTabFlan.java │ │ ├── EntityItemCustomRender.java │ │ ├── FlansHooks.java │ │ ├── FlansMod.java │ │ ├── FlansModExplosion.java │ │ ├── IFlansModContentProvider.java │ │ ├── ItemBlockManyNames.java │ │ ├── ItemHolderType.java │ │ ├── ModuloHelper.java │ │ ├── PlayerData.java │ │ ├── PlayerHandler.java │ │ ├── RotatedAxes.java │ │ ├── TileEntityItemHolder.java │ │ ├── driveables/ │ │ │ ├── CollisionBox.java │ │ │ ├── CollisionSurface.java │ │ │ ├── ContainerDriveableInventory.java │ │ │ ├── ContainerDriveableMenu.java │ │ │ ├── DriveableData.java │ │ │ ├── DriveablePart.java │ │ │ ├── DriveablePosition.java │ │ │ ├── DriveableType.java │ │ │ ├── EntityDamageSourceCollision.java │ │ │ ├── EntityDriveable.java │ │ │ ├── EntityPlane.java │ │ │ ├── EntitySeat.java │ │ │ ├── EntityVehicle.java │ │ │ ├── EntityWheel.java │ │ │ ├── EnumDriveablePart.java │ │ │ ├── EnumPlaneMode.java │ │ │ ├── EnumWeaponType.java │ │ │ ├── ItemPlane.java │ │ │ ├── ItemVehicle.java │ │ │ ├── PilotGun.java │ │ │ ├── PlaneType.java │ │ │ ├── Propeller.java │ │ │ ├── Seat.java │ │ │ ├── ShootPoint.java │ │ │ ├── VehicleType.java │ │ │ ├── collisions/ │ │ │ │ ├── CollisionPlane.java │ │ │ │ ├── CollisionShapeBox.java │ │ │ │ ├── CollisionTest.java │ │ │ │ └── RidingEntityPosition.java │ │ │ └── mechas/ │ │ │ ├── ContainerMechaInventory.java │ │ │ ├── EntityMecha.java │ │ │ ├── EnumMechaItemType.java │ │ │ ├── EnumMechaSlotType.java │ │ │ ├── EnumMechaToolType.java │ │ │ ├── ItemMecha.java │ │ │ ├── ItemMechaAddon.java │ │ │ ├── MechaInventory.java │ │ │ ├── MechaItemType.java │ │ │ ├── MechaType.java │ │ │ └── SlotMecha.java │ │ ├── enchantments/ │ │ │ ├── EnchantmentDuelist.java │ │ │ ├── EnchantmentJuggernaut.java │ │ │ ├── EnchantmentLumberjack.java │ │ │ ├── EnchantmentModule.java │ │ │ ├── EnchantmentNimble.java │ │ │ ├── EnchantmentSharpshooter.java │ │ │ ├── EnchantmentSteady.java │ │ │ ├── GloveType.java │ │ │ └── ItemGlove.java │ │ ├── eventhandlers/ │ │ │ └── PlayerDeathEventListener.java │ │ ├── guns/ │ │ │ ├── AAGunType.java │ │ │ ├── AttachmentType.java │ │ │ ├── BulletType.java │ │ │ ├── ContainerGunModTable.java │ │ │ ├── EntityAAGun.java │ │ │ ├── EntityBullet.java │ │ │ ├── EntityDamageSourceFlan.java │ │ │ ├── EntityGrenade.java │ │ │ ├── EntityMG.java │ │ │ ├── EntityShootable.java │ │ │ ├── EnumAttachmentType.java │ │ │ ├── EnumFireMode.java │ │ │ ├── EnumSecondaryFunction.java │ │ │ ├── EnumSpreadPattern.java │ │ │ ├── FireableGun.java │ │ │ ├── FiredShot.java │ │ │ ├── GrenadeType.java │ │ │ ├── GunType.java │ │ │ ├── IScope.java │ │ │ ├── InventoryGunModTable.java │ │ │ ├── InventoryHelper.java │ │ │ ├── ItemAAGun.java │ │ │ ├── ItemAttachment.java │ │ │ ├── ItemBullet.java │ │ │ ├── ItemGrenade.java │ │ │ ├── ItemGun.java │ │ │ ├── ItemShootable.java │ │ │ ├── Paintjob.java │ │ │ ├── ShootBulletHandler.java │ │ │ ├── ShootableType.java │ │ │ ├── ShotHandler.java │ │ │ ├── SlotGun.java │ │ │ ├── boxes/ │ │ │ │ ├── BlockGunBox.java │ │ │ │ ├── BoxType.java │ │ │ │ ├── ContainerGunBox.java │ │ │ │ └── GunBoxType.java │ │ │ └── raytracing/ │ │ │ ├── EnumHitboxType.java │ │ │ ├── FlansModRaytracer.java │ │ │ ├── PlayerHitbox.java │ │ │ └── PlayerSnapshot.java │ │ ├── network/ │ │ │ ├── PacketAAGunAngles.java │ │ │ ├── PacketAddSingleRewardBoxInstance.java │ │ │ ├── PacketBase.java │ │ │ ├── PacketBaseEdit.java │ │ │ ├── PacketBlockHitEffect.java │ │ │ ├── PacketBreakSound.java │ │ │ ├── PacketBulletTrail.java │ │ │ ├── PacketBuyArmour.java │ │ │ ├── PacketBuyWeapon.java │ │ │ ├── PacketCraftDriveable.java │ │ │ ├── PacketDriveableControl.java │ │ │ ├── PacketDriveableDamage.java │ │ │ ├── PacketDriveableGUI.java │ │ │ ├── PacketDriveableKey.java │ │ │ ├── PacketDriveableKeyHeld.java │ │ │ ├── PacketFlak.java │ │ │ ├── PacketGunAnimation.java │ │ │ ├── PacketGunFire.java │ │ │ ├── PacketGunPaint.java │ │ │ ├── PacketHandler.java │ │ │ ├── PacketHitMarker.java │ │ │ ├── PacketKillMessage.java │ │ │ ├── PacketLoadoutData.java │ │ │ ├── PacketMGFire.java │ │ │ ├── PacketMGMount.java │ │ │ ├── PacketMechaControl.java │ │ │ ├── PacketOpenRewardBox.java │ │ │ ├── PacketPlaneControl.java │ │ │ ├── PacketPlaySound.java │ │ │ ├── PacketReload.java │ │ │ ├── PacketRepairDriveable.java │ │ │ ├── PacketRequestDebug.java │ │ │ ├── PacketRoundFinished.java │ │ │ ├── PacketSeatUpdates.java │ │ │ ├── PacketTeamInfo.java │ │ │ ├── PacketTeamSelect.java │ │ │ ├── PacketVehicleControl.java │ │ │ ├── PacketVoteCast.java │ │ │ └── PacketVoting.java │ │ ├── paintjob/ │ │ │ ├── BlockPaintjobTable.java │ │ │ ├── ContainerPaintjobTable.java │ │ │ ├── IPaintableItem.java │ │ │ ├── PaintableType.java │ │ │ └── TileEntityPaintjobTable.java │ │ ├── parts/ │ │ │ ├── EnumPartCategory.java │ │ │ ├── ItemPart.java │ │ │ └── PartType.java │ │ ├── teams/ │ │ │ ├── ArmourBoxType.java │ │ │ ├── ArmourType.java │ │ │ ├── BlockArmourBox.java │ │ │ ├── BlockSpawner.java │ │ │ ├── CommandTeams.java │ │ │ ├── EntityConnectingLine.java │ │ │ ├── EntityFlag.java │ │ │ ├── EntityFlagpole.java │ │ │ ├── EntityGunItem.java │ │ │ ├── EntityTeamItem.java │ │ │ ├── Gametype.java │ │ │ ├── GametypeCTF.java │ │ │ ├── GametypeDM.java │ │ │ ├── GametypeTDM.java │ │ │ ├── GametypeZombies.java │ │ │ ├── IPlayerClass.java │ │ │ ├── ITeamBase.java │ │ │ ├── ITeamObject.java │ │ │ ├── ItemFlagpole.java │ │ │ ├── ItemOpStick.java │ │ │ ├── ItemRewardBox.java │ │ │ ├── ItemTeamArmour.java │ │ │ ├── LoadoutPool.java │ │ │ ├── PermanentBaseData.java │ │ │ ├── PlayerClass.java │ │ │ ├── PlayerClassCustom.java │ │ │ ├── PlayerLoadout.java │ │ │ ├── PlayerRankData.java │ │ │ ├── RewardBox.java │ │ │ ├── RewardBoxInstance.java │ │ │ ├── RoundFinishedData.java │ │ │ ├── Team.java │ │ │ ├── TeamsManager.java │ │ │ ├── TeamsManagerClassic.java │ │ │ ├── TeamsManagerRanked.java │ │ │ ├── TeamsMap.java │ │ │ ├── TeamsRound.java │ │ │ └── TileEntitySpawner.java │ │ ├── tools/ │ │ │ ├── EntityParachute.java │ │ │ ├── ItemTool.java │ │ │ └── ToolType.java │ │ ├── types/ │ │ │ ├── EnumPaintjobRarity.java │ │ │ ├── EnumType.java │ │ │ ├── IFlanItem.java │ │ │ ├── InfoType.java │ │ │ └── TypeFile.java │ │ ├── util/ │ │ │ └── BlockUtil.java │ │ └── vector/ │ │ ├── Matrix.java │ │ ├── Matrix2f.java │ │ ├── Matrix3f.java │ │ ├── Matrix4f.java │ │ ├── ReadableVector.java │ │ ├── ReadableVector2f.java │ │ ├── ReadableVector3f.java │ │ ├── ReadableVector4f.java │ │ ├── Vector.java │ │ ├── Vector2f.java │ │ ├── Vector3f.java │ │ ├── Vector3i.java │ │ ├── Vector4f.java │ │ ├── WritableVector2f.java │ │ ├── WritableVector3f.java │ │ └── WritableVector4f.java │ ├── mechaparts/ │ │ └── common/ │ │ └── MechaPartsPackMod.java │ ├── modernweapons/ │ │ ├── client/ │ │ │ └── model/ │ │ │ ├── Model1887.java │ │ │ ├── Model2xScope.java │ │ │ ├── Model4xScope.java │ │ │ ├── Model8xScope.java │ │ │ ├── ModelA10.java │ │ │ ├── ModelA91.java │ │ │ ├── ModelAA12.java │ │ │ ├── ModelACOG.java │ │ │ ├── ModelACR.java │ │ │ ├── ModelADAR15.java │ │ │ ├── ModelAK47.java │ │ │ ├── ModelAK74.java │ │ │ ├── ModelAN94.java │ │ │ ├── ModelASH12.java │ │ │ ├── ModelAT4.java │ │ │ ├── ModelAUG.java │ │ │ ├── ModelAbrams.java │ │ │ ├── ModelAmmoBag.java │ │ │ ├── ModelApacheAH64.java │ │ │ ├── ModelB4CrossBow.java │ │ │ ├── ModelB52.java │ │ │ ├── ModelBarrett.java │ │ │ ├── ModelBinoculars.java │ │ │ ├── ModelBizon.java │ │ │ ├── ModelBlackHawk.java │ │ │ ├── ModelBlackHawkUH60.java │ │ │ ├── ModelBulletFlash1.java │ │ │ ├── ModelC4.java │ │ │ ├── ModelChallengerII.java │ │ │ ├── ModelCharmBase.java │ │ │ ├── ModelCharmBasePanel.java │ │ │ ├── ModelCharmBaseSight.java │ │ │ ├── ModelChinook.java │ │ │ ├── ModelClaymore.java │ │ │ ├── ModelCloakerGoggles.java │ │ │ ├── ModelCobra.java │ │ │ ├── ModelColdWarE2.java │ │ │ ├── ModelDeployableBag.java │ │ │ ├── ModelDesertEagle.java │ │ │ ├── ModelDevotionX55.java │ │ │ ├── ModelDragunov.java │ │ │ ├── ModelEC665.java │ │ │ ├── ModelEMP4.java │ │ │ ├── ModelElDiablo.java │ │ │ ├── ModelExecutioner.java │ │ │ ├── ModelExoskeletonBody.java │ │ │ ├── ModelExoskeletonBoots.java │ │ │ ├── ModelExoskeletonHelmet.java │ │ │ ├── ModelExoskeletonLegs.java │ │ │ ├── ModelF22.java │ │ │ ├── ModelFAMAS.java │ │ │ ├── ModelFMG.java │ │ │ ├── ModelFNSCAR.java │ │ │ ├── ModelFS10.java │ │ │ ├── ModelFlamethrower.java │ │ │ ├── ModelFlareGun.java │ │ │ ├── ModelFlashlight.java │ │ │ ├── ModelForegrip.java │ │ │ ├── ModelG3.java │ │ │ ├── ModelG36.java │ │ │ ├── ModelGAU19.java │ │ │ ├── ModelGL1.java │ │ │ ├── ModelGL6.java │ │ │ ├── ModelGalil.java │ │ │ ├── ModelGlock.java │ │ │ ├── ModelHCAR.java │ │ │ ├── ModelHCOG.java │ │ │ ├── ModelHESatchel.java │ │ │ ├── ModelHK416.java │ │ │ ├── ModelHind.java │ │ │ ├── ModelHindMI24.java │ │ │ ├── ModelHoneyBadger.java │ │ │ ├── ModelHumvee.java │ │ │ ├── ModelJudge.java │ │ │ ├── ModelJury.java │ │ │ ├── ModelKCASmart50.java │ │ │ ├── ModelKCASmartcarbine.java │ │ │ ├── ModelKCASmartpistol.java │ │ │ ├── ModelKCAWolverineIV.java │ │ │ ├── ModelKrissVector.java │ │ │ ├── ModelL86.java │ │ │ ├── ModelL96.java │ │ │ ├── ModelLDCIGScope.java │ │ │ ├── ModelLeopard2A6.java │ │ │ ├── ModelLittleBird.java │ │ │ ├── ModelLittleBirdMH6.java │ │ │ ├── ModelLongBarrel.java │ │ │ ├── ModelM1014.java │ │ │ ├── ModelM14.java │ │ │ ├── ModelM16A4.java │ │ │ ├── ModelM1911.java │ │ │ ├── ModelM21.java │ │ │ ├── ModelM249.java │ │ │ ├── ModelM40A3.java │ │ │ ├── ModelM60E4.java │ │ │ ├── ModelM72LAW.java │ │ │ ├── ModelM9.java │ │ │ ├── ModelMIM23.java │ │ │ ├── ModelMIM23Rocket.java │ │ │ ├── ModelMLRS6.java │ │ │ ├── ModelMP5.java │ │ │ ├── ModelMP7.java │ │ │ ├── ModelMTAR.java │ │ │ ├── ModelMWParachute.java │ │ │ ├── ModelMakarov.java │ │ │ ├── ModelMastiff1218.java │ │ │ ├── ModelMedicBag.java │ │ │ ├── ModelMiniUzi.java │ │ │ ├── ModelMinigun.java │ │ │ ├── ModelMolotov.java │ │ │ ├── ModelMuzzleBreak.java │ │ │ ├── ModelNTW20.java │ │ │ ├── ModelP90.java │ │ │ ├── ModelPAW20.java │ │ │ ├── ModelPanzerfaust3.java │ │ │ ├── ModelPeaceKeeper.java │ │ │ ├── ModelPistolFlashlight.java │ │ │ ├── ModelPr3.java │ │ │ ├── ModelPredator37mm.java │ │ │ ├── ModelProximityMine.java │ │ │ ├── ModelQuickReloadGrip.java │ │ │ ├── ModelR700.java │ │ │ ├── ModelR870.java │ │ │ ├── ModelRPD.java │ │ │ ├── ModelRPG.java │ │ │ ├── ModelRPGRocket.java │ │ │ ├── ModelRPK.java │ │ │ ├── ModelRaptorF22.java │ │ │ ├── ModelRedDot.java │ │ │ ├── ModelRiotShield.java │ │ │ ├── ModelRocket.java │ │ │ ├── ModelRoundGrenade.java │ │ │ ├── ModelSG550.java │ │ │ ├── ModelSIGP226.java │ │ │ ├── ModelSIGP232.java │ │ │ ├── ModelSPAS.java │ │ │ ├── ModelSU25.java │ │ │ ├── ModelSentryGun.java │ │ │ ├── ModelShockAbsorbentStock.java │ │ │ ├── ModelSideWinder7.java │ │ │ ├── ModelSilencer.java │ │ │ ├── ModelSkorpion.java │ │ │ ├── ModelStinger.java │ │ │ ├── ModelStingerMissile.java │ │ │ ├── ModelSuperHeavyBoots.java │ │ │ ├── ModelSuperHeavyChest.java │ │ │ ├── ModelSuperHeavyHelmet.java │ │ │ ├── ModelSuperHeavyLegs.java │ │ │ ├── ModelT90.java │ │ │ ├── ModelTiger665.java │ │ │ ├── ModelTornado.java │ │ │ ├── ModelTornadoGR4.java │ │ │ ├── ModelTripleTake.java │ │ │ ├── ModelUSP.java │ │ │ ├── ModelUnderBarrelLaser.java │ │ │ ├── ModelVoltV3.java │ │ │ └── ModelW1200.java │ │ └── common/ │ │ └── ModernWeaponsPackMod.java │ ├── nerf/ │ │ ├── client/ │ │ │ └── model/ │ │ │ ├── ModelDisc.java │ │ │ └── ModelVulcan.java │ │ └── common/ │ │ └── NerfPackMod.java │ ├── simple/ │ │ └── common/ │ │ └── SimplePartsPackMod.java │ ├── steampunk/ │ │ └── common/ │ │ └── SteampunkPackMod.java │ ├── titan/ │ │ ├── client/ │ │ │ └── model/ │ │ │ ├── ModelCircularSaw.java │ │ │ ├── ModelDrill.java │ │ │ ├── ModelExcavator.java │ │ │ ├── ModelProtoTitan.java │ │ │ ├── ModelRocketPack.java │ │ │ └── ModelZeroTitan.java │ │ └── common/ │ │ └── TitanPackMod.java │ ├── utility/ │ │ ├── client/ │ │ │ └── model/ │ │ │ └── ModelTunnelBore.java │ │ └── common/ │ │ └── UtilityPackMod.java │ ├── ww2/ │ │ ├── client/ │ │ │ └── model/ │ │ │ ├── Model105leFH18B2.java │ │ │ ├── Model50Cal.java │ │ │ ├── ModelAmericanBoots.java │ │ │ ├── ModelAmericanChest.java │ │ │ ├── ModelAmericanHelmet.java │ │ │ ├── ModelAmericanPants.java │ │ │ ├── ModelAmmoBag.java │ │ │ ├── ModelB1.java │ │ │ ├── ModelBAR.java │ │ │ ├── ModelBF109.java │ │ │ ├── ModelBMWR75.java │ │ │ ├── ModelBazooka.java │ │ │ ├── ModelBinoculars.java │ │ │ ├── ModelBofors.java │ │ │ ├── ModelBren.java │ │ │ ├── ModelBrowning.java │ │ │ ├── ModelC96.java │ │ │ ├── ModelCamel.java │ │ │ ├── ModelChaffee.java │ │ │ ├── ModelChiHa.java │ │ │ ├── ModelChiNu.java │ │ │ ├── ModelChurchill.java │ │ │ ├── ModelColt.java │ │ │ ├── ModelCromwell.java │ │ │ ├── ModelCrusader.java │ │ │ ├── ModelDP28.java │ │ │ ├── ModelFg42.java │ │ │ ├── ModelFlak88.java │ │ │ ├── ModelFlakvierling.java │ │ │ ├── ModelFlamethrower.java │ │ │ ├── ModelFokker.java │ │ │ ├── ModelFragGrenade.java │ │ │ ├── ModelFragGrenade2.java │ │ │ ├── ModelFury.java │ │ │ ├── ModelG43.java │ │ │ ├── ModelGermanBoots.java │ │ │ ├── ModelGermanChest.java │ │ │ ├── ModelGermanHelmet.java │ │ │ ├── ModelGermanPants.java │ │ │ ├── ModelGothaGV.java │ │ │ ├── ModelGreaseGun.java │ │ │ ├── ModelGreyhound.java │ │ │ ├── ModelHellcat.java │ │ │ ├── ModelIS2.java │ │ │ ├── ModelJeep.java │ │ │ ├── ModelKV1.java │ │ │ ├── ModelKar98k.java │ │ │ ├── ModelKar98kSniper.java │ │ │ ├── ModelKubel.java │ │ │ ├── ModelLancaster.java │ │ │ ├── ModelLeeenfield.java │ │ │ ├── ModelLeeenfieldS.java │ │ │ ├── ModelLuchs.java │ │ │ ├── ModelLuger.java │ │ │ ├── ModelM10.java │ │ │ ├── ModelM157MM.java │ │ │ ├── ModelM1Carbine.java │ │ │ ├── ModelM1Garand.java │ │ │ ├── ModelM3A1GreaseGun.java │ │ │ ├── ModelM3Halftrack.java │ │ │ ├── ModelM45Quad.java │ │ │ ├── ModelM8Smoke.java │ │ │ ├── ModelMG34.java │ │ │ ├── ModelMG42.java │ │ │ ├── ModelMaus.java │ │ │ ├── ModelMine.java │ │ │ ├── ModelMosin.java │ │ │ ├── ModelMosinSniper.java │ │ │ ├── ModelMp40.java │ │ │ ├── ModelMp44.java │ │ │ ├── ModelMustang.java │ │ │ ├── ModelPIAT.java │ │ │ ├── ModelPPSH.java │ │ │ ├── ModelPak40.java │ │ │ ├── ModelPanzer.java │ │ │ ├── ModelPanzerIILuchs.java │ │ │ ├── ModelPanzerfaust.java │ │ │ ├── ModelPanzerschreck.java │ │ │ ├── ModelS100.java │ │ │ ├── ModelSASJeep.java │ │ │ ├── ModelSTG44.java │ │ │ ├── ModelSU112.java │ │ │ ├── ModelSdkFz2.java │ │ │ ├── ModelSdkFz222.java │ │ │ ├── ModelSdkFz251.java │ │ │ ├── ModelSherman.java │ │ │ ├── ModelSpitfire.java │ │ │ ├── ModelSpringfield.java │ │ │ ├── ModelSpringfieldSniper.java │ │ │ ├── ModelSten.java │ │ │ ├── ModelStickGrenade.java │ │ │ ├── ModelStickGrenade2.java │ │ │ ├── ModelStuG.java │ │ │ ├── ModelT34.java │ │ │ ├── ModelT3485.java │ │ │ ├── ModelTT33.java │ │ │ ├── ModelThompson.java │ │ │ ├── ModelTiger.java │ │ │ ├── ModelTiger131.java │ │ │ ├── ModelTigerII.java │ │ │ ├── ModelTrenchgun.java │ │ │ ├── ModelType100.java │ │ │ ├── ModelType14.java │ │ │ ├── ModelType38.java │ │ │ ├── ModelType38sniper.java │ │ │ ├── ModelType4HoRo.java │ │ │ ├── ModelType99.java │ │ │ ├── ModelUC2Pdr.java │ │ │ ├── ModelWW2Parachute.java │ │ │ ├── ModelWebley.java │ │ │ ├── ModelYak9.java │ │ │ ├── ModelZF4Scope.java │ │ │ ├── ModelZero.java │ │ │ ├── Modelvickersk.java │ │ │ └── ModelvickerskGO.java │ │ └── common/ │ │ └── WW2PackMod.java │ ├── yeolde/ │ │ ├── client/ │ │ │ └── model/ │ │ │ ├── ModelArrow.java │ │ │ ├── ModelBiplane.java │ │ │ ├── ModelNetherGrip.java │ │ │ ├── ModelRock.java │ │ │ └── ModelTwoSeatBiplane.java │ │ └── common/ │ │ └── YeOldePackMod.java │ └── zombie/ │ ├── client/ │ │ └── model/ │ │ ├── ModelApron.java │ │ ├── ModelBaseballBat.java │ │ ├── ModelBearTrap.java │ │ ├── ModelCoat.java │ │ ├── ModelColtPython.java │ │ ├── ModelCombatKnife.java │ │ ├── ModelDoubleBarrelledShotgun.java │ │ ├── ModelDustbinLidChestplate.java │ │ ├── ModelFlareGun.java │ │ ├── ModelFleshLump.java │ │ ├── ModelGlock17.java │ │ ├── ModelM4Carbine.java │ │ ├── ModelMP5K.java │ │ ├── ModelMachete.java │ │ ├── ModelOlympia.java │ │ ├── ModelPanHelmet.java │ │ ├── ModelPoliceHat.java │ │ ├── ModelRiotShield.java │ │ ├── ModelSamuraiSword.java │ │ ├── ModelScrewdriver.java │ │ ├── ModelSledgehammer.java │ │ ├── ModelSurgicalAxe.java │ │ └── ModelWinchesterModel70.java │ └── common/ │ └── ZombiePackMod.java └── resources/ ├── LICENSE.txt ├── RedstoneFlux API - LICENSE - LGPLv3.txt ├── assets/ │ ├── flansmod/ │ │ ├── blockstates/ │ │ │ ├── flansworkbench.json │ │ │ ├── gunpowderblock.json │ │ │ ├── paintjobtable.json │ │ │ └── teamsspawner.json │ │ ├── lang/ │ │ │ ├── de_de.lang │ │ │ ├── en_us.lang │ │ │ ├── es_es.lang │ │ │ ├── fr_fr.lang │ │ │ ├── pl_pl.lang │ │ │ ├── pt_br.lang │ │ │ ├── ru_ru.lang │ │ │ ├── zh_TW.lang │ │ │ └── zh_cn.lang │ │ ├── models/ │ │ │ ├── block/ │ │ │ │ ├── flansworkbench_guns.json │ │ │ │ ├── flansworkbench_parts.json │ │ │ │ ├── flansworkbench_vehicles.json │ │ │ │ ├── gunpowderblock.json │ │ │ │ ├── paintjobtable.json │ │ │ │ ├── teamsspawner_items.json │ │ │ │ ├── teamsspawner_players.json │ │ │ │ └── teamsspawner_vehicles.json │ │ │ └── item/ │ │ │ ├── crosshairsymbol.json │ │ │ ├── custom.json │ │ │ ├── flagpole.json │ │ │ ├── flansworkbench_guns.json │ │ │ ├── flansworkbench_item.json │ │ │ ├── flansworkbench_parts.json │ │ │ ├── flansworkbench_vehicles.json │ │ │ ├── gunpowderblock.json │ │ │ ├── opstick.json │ │ │ ├── opstick_connecting.json │ │ │ ├── opstick_destruction.json │ │ │ ├── opstick_mapping.json │ │ │ ├── opstick_ownership.json │ │ │ ├── paintjobtable.json │ │ │ ├── rainbowpaintcan.json │ │ │ ├── teamsspawner_items.json │ │ │ ├── teamsspawner_players.json │ │ │ └── teamsspawner_vehicles.json │ │ ├── sounds/ │ │ │ ├── skullboss_laugh.ogg │ │ │ ├── skullboss_spawn.ogg │ │ │ └── unlocknotch.ogg │ │ └── sounds.json │ └── flansmodapocalypse/ │ ├── blockstates/ │ │ ├── blocklabstone.json │ │ ├── blockpowercube.json │ │ ├── blocksulphur.json │ │ └── blocksulphuricacid.json │ ├── lang/ │ │ ├── en_us.lang │ │ ├── fr_fr.lang │ │ └── ru_ru.lang │ ├── models/ │ │ ├── block/ │ │ │ ├── blocklabstone.json │ │ │ ├── blockpowercube.json │ │ │ ├── blocksulphur.json │ │ │ └── blocksulphuricacid.json │ │ └── item/ │ │ ├── blocklabstone.json │ │ ├── blockpowercube.json │ │ ├── blocksulphur.json │ │ ├── blocksulphuricacid.json │ │ └── flansulphur.json │ └── textures/ │ └── blocks/ │ ├── sulphuricacidflowing.png.mcmeta │ └── sulphuricacidstill.png.mcmeta ├── mcmod.info └── pack.mcmeta ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 indent_style = tab trim_trailing_whitespace = false [*.java] insert_final_newline = true [*.{info,mcmeta,json}] indent_style = space indent_size = 2 [*.gradle] indent_style = space indent_size = 4 ================================================ FILE: .gitattributes ================================================ # Text * text eol=lf *.java text eol=lf *.json text eol=lf *.md text eol=lf *.txt text eol=lf *.sh text eol=lf *.bat text eol=crlf # Binary *.png binary *.jpg binary *.jpeg binary *.jar binary *.ogg binary ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** **To Reproduce** Steps to reproduce the behaviour: 1. 2. 3. 4. **Expected behaviour** **Screenshots** **Versions (please complete the following information)** - Forge: - Flan's Mod: **Additional context** ================================================ FILE: .github/ISSUE_TEMPLATE/crash_report.md ================================================ --- name: Crash report about: Create a report to help us improve title: '' labels: crash assignees: '' --- **To Reproduce** Steps to reproduce the crash: 1. 2. 3. 4. **Screenshots** **Versions (please complete the following information)** - Forge: - Flan's Mod: **Crash Log** **Additional context** ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Describe the solution you'd like** **Describe alternatives you've considered** **Additional context** ================================================ FILE: .github/workflows/gradle.yml ================================================ name: Java CI with Gradle on: [ push, pull_request ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build - name: Upload build artifacts uses: actions/upload-artifact@v1 with: name: build-artifacts path: build/output/ ================================================ FILE: .gitignore ================================================ # Build and Bins .gradle/ build/ bin/ out/ run/* src/main/java/com/flansmod/leaderboards/* # IDEs .classpath .project .settings/ eclipse/ .idea/ *.iml *.ipr *.iws # System Thumbs.db .DS_Store # Flan's Mod !run/Flan/ # Flan's Scripts upload.bat *.launch ================================================ FILE: LICENSE.txt ================================================ THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(g) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; to Distribute and Publicly Perform the Work including as incorporated in Collections; and, to Distribute and Publicly Perform Adaptations. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section 4(e). 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested. You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. For the avoidance of doubt: Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. ================================================ FILE: README.md ================================================ [![GitHub release](https://img.shields.io/github/v/tag/FlansMods/FlansMod.svg?include_prereleases&sort=semver&color=brightgreen)](https://GitHub.com//FlansMods/FlansMod/releases/) [![Github all releases](https://img.shields.io/github/downloads/FlansMods/FlansMod/total.svg)](https://GitHub.com/FlansMods/FlansMod/releases/) [![GitHub forks](https://img.shields.io/github/forks/FlansMods/FlansMod.svg?color=brightgreen)](https://GitHub.com/FlansMods/FlansMod/network/) [![GitHub forks](https://img.shields.io/github/stars/FlansMods/FlansMod.svg?color=brightgreen)](https://GitHub.com/FlansMods/FlansMod/stargazers/) [![GitHub contributors](https://img.shields.io/github/contributors/FlansMods/FlansMod.svg)](https://GitHub.com/FlansMods/FlansMod/graphs/contributors/) # [Flan's Mod](https://www.flansmod.com/) This is the offical Github repository of the minecraft modification Flan's Mod. ## Installation If you just want use the Mod, just head over to [this](https://github.com/FlansMods/FlansMod/wiki/Installing-FlansMod) page in the wiki, everything is explained there. ## Issues If you encounter any issues while using Flan's Mod, see this [page](https://github.com/FlansMods/FlansMod/wiki/Issue-Reporting) ## Development If you want to contribute to this project, feel free to pitch in and submit a pull request. If you plan larger changes, please talk first to other contributers as there might be hidden problems. Instructions on how to build FlansMod are below ### Building 1. Download/clone this repository 1. Run the build command for your system in the repository - Linux/Mac: `./gradlew build` - Windows: `gradlew.bat build` 1. Built files are found in the directory `./build/output` This GitHub environment is to be treated maturely -- do not release any of this source code without prior permission from jamioflan. ================================================ FILE: build.bat ================================================ gradlew build pause ================================================ FILE: build.gradle ================================================ buildscript { dependencies { classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' } repositories { jcenter() maven { // location of the maven that hosts the forge files name = "Forge maven" url = "http://files.minecraftforge.net/maven" } } } apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'com.github.johnrengelman.shadow' version = version_major + "." + version_minor + "." + version_patch + version_extra group = "com.flansmod" archivesBaseName = "Flan's Mod" apocalypseVersion = apocalypseVersion + version_extra sourceCompatibility = targetCompatibility = '1.8' compileJava { sourceCompatibility = targetCompatibility = '1.8' } dependencies { compile "io.vavr:vavr:0.10.2" shadow "io.vavr:vavr:0.10.2" } minecraft { version = minecraft_version + "-" + forge_version runDir = "run" replace "@ALLOWED_VERSIONS@", "[5.10.0, 5.11)" replace "@VERSION@", project.version replaceIn "FlansMod.java" replaceIn "ModernWeaponsPackMod.java" replaceIn "TitanPackMod.java" replaceIn "SimplePartsPackMod.java" replaceIn "NerfPackMod.java" replaceIn "MechaPartsPackMod.java" replaceIn "UtilityPackMod.java" replaceIn "WW2PackMod.java" replaceIn "YeOldePackMod.java" replaceIn "ZombiePackMod.java" replace "@ALLOWED_VERSIONS_APOCALYPSE@", "[1.4, 1.5)" replace "@VERSION_APOCALYPSE@", project.apocalypseVersion replaceIn "FlansModApocalypse.java" mappings = "stable_39" //if this is required, it should be enabled locally for selected runs. These runs will take about 10 seconds longer makeObfSourceJar = false } processResources { // this will ensure that this task is redone when the versions change. inputs.property "version", project.version inputs.property "apocalypseversion", project.apocalypseVersion inputs.property "mcversion", project.minecraft.version // replace stuff in mcmod.info, nothing else from(sourceSets.main.resources.srcDirs) { include 'mcmod.info' // replace version and mcversion expand 'version': project.version, 'apocalypseversion': project.apocalypseVersion, 'mcversion': project.minecraft.version } // copy everything else except the mcmod.info from(sourceSets.main.resources.srcDirs) { exclude 'mcmod.info' } } version = "${project.minecraft.version}-${project.version}" task mechaParts(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/mechaparts/' } from 'run/Flan/Mecha Parts Pack' baseName = 'Mecha Parts' appendix = 'Content Pack' } task modernWeapons(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/modernweapons/' } from 'run/Flan/Modern Weapons Pack' baseName = 'Modern Warfare' appendix = 'Content Pack' } task nerf(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/nerf/' } from 'run/Flan/Nerf Pack' baseName = 'Nerf' appendix = 'Content Pack' } task simpleParts(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/simple/' } from 'run/Flan/Parts Pack' baseName = 'Simple Parts' appendix = 'Content Pack' } task titan(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/titan/' } from 'run/Flan/Titan Pack' baseName = 'Titan' appendix = 'Content Pack' } task utility(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/utility/' } from 'run/Flan/Utility Pack' baseName = 'Utility' appendix = 'Content Pack' } task ww2(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/ww2/' } from 'run/Flan/WW2 Pack' baseName = 'WW2' appendix = 'Content Pack' } task yeOlde(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/yeolde/' } from 'run/Flan/Ye Olde Pack' baseName = 'Ye Olde' appendix = 'Content Pack' } task zombie(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/zombie/' } from 'run/Flan/Zombie Pack' baseName = 'Zombie' appendix = 'Content Pack' } task apoc(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/apocalypse/' } from 'run/Flan/Apocalypse Pack' baseName = 'Apocalypse' appendix = 'Content Pack' } task leaderboards(type: Jar) { from(zipTree("${destinationDir}/${archiveName}")) { include 'com/flansmod/leaderboards/' } baseName = 'Leaderboards' appendix = 'Content Pack' } task contentPacks() { dependsOn mechaParts dependsOn modernWeapons dependsOn nerf dependsOn simpleParts dependsOn titan dependsOn utility dependsOn ww2 dependsOn yeOlde dependsOn zombie dependsOn apoc dependsOn leaderboards } task clearOutput(type: Delete) { delete 'build/output/' } task outputJar(type: Jar) { destinationDir = new File("build/output/mods/") from(zipTree("build/libs/${archivesBaseName}-${version}-all.jar")) { exclude '**/apocalypse/' exclude '**/modernweapons/' exclude '**/nerf/' exclude '**/titan/' exclude '**/utility/' exclude '**/ww2/' exclude '**/yeolde/' exclude '**/zombie/' exclude '**/simple/' exclude '**/mechaparts/' exclude '**/steampunk/' exclude '**/leaderboards/' } } task outputPacks(type: Copy) { from('build/libs/') { include "**/*${version}.jar" exclude "**/Flan's Mod*.jar" } into 'build/output/mods/' } shadowJar { configurations = [project.configurations.shadow] } reobf { shadowJar { mappingType = "SEARGE" } } tasks.reobfShadowJar.mustRunAfter shadowJar build { dependsOn reobfShadowJar dependsOn contentPacks dependsOn clearOutput dependsOn outputJar dependsOn outputPacks } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Wed Jun 03 12:06:43 BST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip ================================================ FILE: gradle.properties ================================================ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G forge_version = 14.23.5.2838 minecraft_version = 1.12.2 jei_version = 4.16.1.1000 version_major = 5 version_minor = 10 version_patch = 0 version_extra = apocalypseVersion = 1.4.0 ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=$(save "$@") # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then cd "$(dirname "$0")" fi exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: src/main/java/com/flansmod/api/IControllable.java ================================================ package com.flansmod.api; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.driveables.EntitySeat; public interface IControllable { /** * This is fired every tick. * * @param deltaX change in X of the mouse. * @param deltaY change in Y of the mouse. */ void onMouseMoved(int deltaX, int deltaY); /** * @param key the keycode of the key. see @link:KeyInputHandler * @return boolean to indicate it this key was handled. */ boolean pressKey(int key, EntityPlayer player, boolean isOnEvent); boolean serverHandleKeyPress(int key, EntityPlayer player); void updateKeyHeldState(int key, boolean held); /** * @return riddenByEntity */ Entity getControllingEntity(); boolean isDead(); /** * @return The player's view roll */ float getPlayerRoll(); float getPrevPlayerRoll(); /** * @return The player's 3rd person view distance */ float getCameraDistance(); @SideOnly(Side.CLIENT) EntityLivingBase getCamera(); EntitySeat getSeat(EntityLivingBase living); } ================================================ FILE: src/main/java/com/flansmod/api/IExplodeable.java ================================================ package com.flansmod.api; /** * Implement this interface if an entity is able to explode. Other modders will be able to check if * an entity instanceof this, and if so, call the explode() method. * * @author AidanBrady */ public interface IExplodeable { /** * Explode the entity completely. */ void explode(); } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/ClientProxyApocalypse.java ================================================ package com.flansmod.apocalypse.client; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import com.flansmod.apocalypse.client.model.RenderSkullDrone; import com.flansmod.apocalypse.client.model.RenderFakePlayer; import com.flansmod.apocalypse.client.model.RenderNukeDrop; import com.flansmod.apocalypse.client.model.RenderPowerCube; import com.flansmod.apocalypse.client.model.RenderSkullBoss; import com.flansmod.apocalypse.client.model.RenderSurvivor; import com.flansmod.apocalypse.client.model.RenderTeleporter; import com.flansmod.apocalypse.common.CommonProxyApocalypse; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.blocks.BlockSulphuricAcid; import com.flansmod.apocalypse.common.blocks.TileEntityPowerCube; import com.flansmod.apocalypse.common.entity.EntityAIMecha; import com.flansmod.apocalypse.common.entity.EntitySkullDrone; import com.flansmod.apocalypse.common.entity.EntityFakePlayer; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntitySkullBoss; import com.flansmod.apocalypse.common.entity.EntitySurvivor; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.model.RenderMecha; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.FlansMod; public class ClientProxyApocalypse extends CommonProxyApocalypse { private static final String FLUID_MODEL_PATH = "flansmodapocalypse:fluid"; public static int apocalypseCountdown = 0; @Override public void preInit(FMLPreInitializationEvent event) { super.preInit(event); MinecraftForge.EVENT_BUS.register(this); ((BlockSulphuricAcid)FlansModApocalypse.blockSulphuricAcid).registerRenderer(); RenderingRegistry.registerEntityRenderingHandler(EntitySurvivor.class, new RenderSurvivor.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityFakePlayer.class,new RenderFakePlayer.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityTeleporter.class, new RenderTeleporter.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityAIMecha.class, new RenderMecha.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityNukeDrop.class, new RenderNukeDrop.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntitySkullBoss.class, new RenderSkullBoss.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntitySkullDrone.class, new RenderSkullDrone.Factory()); } @Override public void init(FMLInitializationEvent event) { super.init(event); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityPowerCube.class, new RenderPowerCube()); } @Override public void postInit(FMLPostInitializationEvent event) { //FlansMod.getPacketHandler().registerPacket(PacketApocalypseCountdown.class); } @SubscribeEvent public void registerSoundEvents(RegistryEvent.Register event) { event.getRegistry().register(FlansModResourceHandler.getSoundEvent("skullboss_laugh")); event.getRegistry().register(FlansModResourceHandler.getSoundEvent("skullboss_spawn")); } public static void updateApocalypseCountdownTimer(int i) { apocalypseCountdown = i; } @SubscribeEvent public void registerModels(ModelRegistryEvent event) { ModelLoader.setCustomModelResourceLocation(FlansModApocalypse.sulphur, 0, new ModelResourceLocation(FlansModApocalypse.MODID + ":flansulphur", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansModApocalypse.itemBlockSulphur, 0, new ModelResourceLocation(FlansModApocalypse.MODID + ":blocksulphur", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansModApocalypse.itemBlockPowerCube, 0, new ModelResourceLocation(FlansModApocalypse.MODID + ":blockpowercube", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansModApocalypse.itemBlockLabStone, 0, new ModelResourceLocation(FlansModApocalypse.MODID + ":blocklabstone", "inventory")); } /** * Tick hook for client logic */ @SubscribeEvent public void tick(TickEvent.ClientTickEvent event) { if(event.phase == TickEvent.Phase.START) { if(apocalypseCountdown > 0) { apocalypseCountdown--; } } } /** * Tick hook for client render */ @SubscribeEvent public void tick(TickEvent.RenderTickEvent event) { if(event.phase == TickEvent.Phase.START) { } } @SubscribeEvent public void eventHandler(RenderGameOverlayEvent event) { Minecraft mc = Minecraft.getMinecraft(); //DEBUG vehicles if(apocalypseCountdown > 0 && FlansMod.DEBUG) { mc.fontRenderer.drawString("Seconds to the apocalypse: " + (apocalypseCountdown / 20), 2, 2, 0xffffff); } //Draw white screen if we are being nuked ScaledResolution scaledresolution = new ScaledResolution(FlansModClient.minecraft); int i = scaledresolution.getScaledWidth(); int j = scaledresolution.getScaledHeight(); Tessellator tessellator = Tessellator.getInstance(); if(!event.isCancelable() && event.getType() == ElementType.HELMET) { boolean playerIsInExplosion = false; for(Object obj : mc.world.loadedEntityList) { if(obj instanceof EntityNukeDrop) { EntityNukeDrop nuke = (EntityNukeDrop)obj; float scale = 1F - 1F / ((float)nuke.timeSinceExplosion / 5F + 1); scale *= 100F * scale; float alpha = ((float)nuke.timeSinceExplosion / (float)EntityNukeDrop.explosionLength); alpha = 1F - alpha * alpha; alpha *= 0.5F; //Render white screen if(mc.player.getDistanceSq(nuke) < scale * scale) { FlansModClient.minecraft.entityRenderer.setupOverlayRendering(); GlStateManager.enableBlend(); GlStateManager.disableDepth(); GlStateManager.disableTexture2D(); GlStateManager.depthMask(false); GlStateManager.blendFunc(770, 771); GlStateManager.color(1F, 1F, 1F, alpha); GlStateManager.disableAlpha(); WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2 - 2 * j, j, -90D, 0.0D, 1.0D); worldrenderer.addVertexWithUV(i / 2 + 2 * j, j, -90D, 1.0D, 1.0D); worldrenderer.addVertexWithUV(i / 2 + 2 * j, 0.0D, -90D, 1.0D, 0.0D); worldrenderer.addVertexWithUV(i / 2 - 2 * j, 0.0D, -90D, 0.0D, 0.0D); worldrenderer.draw(); GlStateManager.depthMask(true); GlStateManager.enableDepth(); GlStateManager.enableAlpha(); GlStateManager.enableTexture2D(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); } } } } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelBuggy.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.4.2 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; //Path where the model is located import com.flansmod.client.model.ModelVehicle; import com.flansmod.client.tmt.Coord2D; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.client.tmt.Shape2D; public class ModelBuggy extends ModelVehicle //Same as Filename { int textureX = 256; int textureY = 256; public ModelBuggy() //Same as Filename { bodyModel = new ModelRendererTurbo[206]; bodyModel[0] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 9 bodyModel[1] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 10 bodyModel[2] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 11 bodyModel[3] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 12 bodyModel[4] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 13 bodyModel[5] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 14 bodyModel[6] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 20 bodyModel[7] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 21 bodyModel[8] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 30 bodyModel[9] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 31 bodyModel[10] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 41 bodyModel[11] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 46 bodyModel[12] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 49 bodyModel[13] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 52 bodyModel[14] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 55 bodyModel[15] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 56 bodyModel[16] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 57 bodyModel[17] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 59 bodyModel[18] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 60 bodyModel[19] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 61 bodyModel[20] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 2 bodyModel[21] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 3 bodyModel[22] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 5 bodyModel[23] = new ModelRendererTurbo(this, 0, 67, textureX, textureY); // Box 6 bodyModel[24] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 7 bodyModel[25] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 9 bodyModel[26] = new ModelRendererTurbo(this, 0, 59, textureX, textureY); // Box 10 bodyModel[27] = new ModelRendererTurbo(this, 0, 73, textureX, textureY); // Box 11 bodyModel[28] = new ModelRendererTurbo(this, 0, 67, textureX, textureY); // Box 12 bodyModel[29] = new ModelRendererTurbo(this, 0, 59, textureX, textureY); // Box 13 bodyModel[30] = new ModelRendererTurbo(this, 0, 73, textureX, textureY); // Box 14 bodyModel[31] = new ModelRendererTurbo(this, 0, 59, textureX, textureY); // Box 15 bodyModel[32] = new ModelRendererTurbo(this, 0, 67, textureX, textureY); // Box 16 bodyModel[33] = new ModelRendererTurbo(this, 0, 73, textureX, textureY); // Box 17 bodyModel[34] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 20 bodyModel[35] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 21 bodyModel[36] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 22 bodyModel[37] = new ModelRendererTurbo(this, 127, 122, textureX, textureY); // Box 24 bodyModel[38] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 25 bodyModel[39] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 26 bodyModel[40] = new ModelRendererTurbo(this, 97, 124, textureX, textureY); // Box 27 bodyModel[41] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 28 bodyModel[42] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 30 bodyModel[43] = new ModelRendererTurbo(this, 97, 122, textureX, textureY); // Box 31 bodyModel[44] = new ModelRendererTurbo(this, 63, 129, textureX, textureY); // Box 32 bodyModel[45] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 33 bodyModel[46] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 34 bodyModel[47] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 35 bodyModel[48] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 36 bodyModel[49] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 37 bodyModel[50] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 38 bodyModel[51] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 39 bodyModel[52] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 40 bodyModel[53] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 41 bodyModel[54] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 42 bodyModel[55] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 43 bodyModel[56] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 45 bodyModel[57] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 46 bodyModel[58] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 47 bodyModel[59] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 48 bodyModel[60] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 49 bodyModel[61] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 50 bodyModel[62] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 51 bodyModel[63] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 52 bodyModel[64] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 54 bodyModel[65] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 55 bodyModel[66] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 56 bodyModel[67] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 57 bodyModel[68] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 63 bodyModel[69] = new ModelRendererTurbo(this, 0, 51, textureX, textureY); // Box 64 bodyModel[70] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 67 bodyModel[71] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 68 bodyModel[72] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 69 bodyModel[73] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 70 bodyModel[74] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 71 bodyModel[75] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 8 bodyModel[76] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 9 bodyModel[77] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 12 bodyModel[78] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 13 bodyModel[79] = new ModelRendererTurbo(this, 85, 55, textureX, textureY); // Box 14 bodyModel[80] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 82 bodyModel[81] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 83 bodyModel[82] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 84 bodyModel[83] = new ModelRendererTurbo(this, 60, 50, textureX, textureY); // Box 85 bodyModel[84] = new ModelRendererTurbo(this, 85, 55, textureX, textureY); // Box 86 bodyModel[85] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 92 bodyModel[86] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 93 bodyModel[87] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 94 bodyModel[88] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 95 bodyModel[89] = new ModelRendererTurbo(this, 30, 55, textureX, textureY); // Box 96 bodyModel[90] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 97 bodyModel[91] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 98 bodyModel[92] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 99 bodyModel[93] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 100 bodyModel[94] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 101 bodyModel[95] = new ModelRendererTurbo(this, 30, 55, textureX, textureY); // Box 102 bodyModel[96] = new ModelRendererTurbo(this, 0, 55, textureX, textureY); // Box 103 bodyModel[97] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 104 bodyModel[98] = new ModelRendererTurbo(this, 0, 67, textureX, textureY); // Box 106 bodyModel[99] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 107 bodyModel[100] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 108 bodyModel[101] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 109 bodyModel[102] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 112 bodyModel[103] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 114 bodyModel[104] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 119 bodyModel[105] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 120 bodyModel[106] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 121 bodyModel[107] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 122 bodyModel[108] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 123 bodyModel[109] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 124 bodyModel[110] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 125 bodyModel[111] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 126 bodyModel[112] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 127 bodyModel[113] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 129 bodyModel[114] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 131 bodyModel[115] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 132 bodyModel[116] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 133 bodyModel[117] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 134 bodyModel[118] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 135 bodyModel[119] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 136 bodyModel[120] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 137 bodyModel[121] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 138 bodyModel[122] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 139 bodyModel[123] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 140 bodyModel[124] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 141 bodyModel[125] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 143 bodyModel[126] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 144 bodyModel[127] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 147 bodyModel[128] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 148 bodyModel[129] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 149 bodyModel[130] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 150 bodyModel[131] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 151 bodyModel[132] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 159 bodyModel[133] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 160 bodyModel[134] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 161 bodyModel[135] = new ModelRendererTurbo(this, 72, 96, textureX, textureY); // Box 162 bodyModel[136] = new ModelRendererTurbo(this, 40, 68, textureX, textureY); // Box 163 bodyModel[137] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 164 bodyModel[138] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 165 bodyModel[139] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 166 bodyModel[140] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 167 bodyModel[141] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 168 bodyModel[142] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 169 bodyModel[143] = new ModelRendererTurbo(this, 87, 18, textureX, textureY); // Box 170 bodyModel[144] = new ModelRendererTurbo(this, 87, 5, textureX, textureY); // Box 171 bodyModel[145] = new ModelRendererTurbo(this, 54, 11, textureX, textureY); // Box 172 bodyModel[146] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 173 bodyModel[147] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 174 bodyModel[148] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 175 bodyModel[149] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 176 bodyModel[150] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 177 bodyModel[151] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 178 bodyModel[152] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 179 bodyModel[153] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 180 bodyModel[154] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 181 bodyModel[155] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 182 bodyModel[156] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 183 bodyModel[157] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 184 bodyModel[158] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 185 bodyModel[159] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 186 bodyModel[160] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 187 bodyModel[161] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 188 bodyModel[162] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 189 bodyModel[163] = new ModelRendererTurbo(this, 119, 42, textureX, textureY); // Box 190 bodyModel[164] = new ModelRendererTurbo(this, 87, 30, textureX, textureY); // Box 191 bodyModel[165] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 192 bodyModel[166] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 193 bodyModel[167] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 194 bodyModel[168] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 195 bodyModel[169] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 211 bodyModel[170] = new ModelRendererTurbo(this, 0, 78, textureX, textureY); // Box 212 bodyModel[171] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 213 bodyModel[172] = new ModelRendererTurbo(this, 0, 78, textureX, textureY); // Box 214 bodyModel[173] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 215 bodyModel[174] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 216 bodyModel[175] = new ModelRendererTurbo(this, 19, 53, textureX, textureY); // Box 218 bodyModel[176] = new ModelRendererTurbo(this, 6, 49, textureX, textureY); // Box 219 bodyModel[177] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 230 bodyModel[178] = new ModelRendererTurbo(this, 73, 107, textureX, textureY); // Box 231 bodyModel[179] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 232 bodyModel[180] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 233 bodyModel[181] = new ModelRendererTurbo(this, 0, 107, textureX, textureY); // Box 234 bodyModel[182] = new ModelRendererTurbo(this, 97, 122, textureX, textureY); // Box 235 bodyModel[183] = new ModelRendererTurbo(this, 63, 129, textureX, textureY); // Box 236 bodyModel[184] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 237 bodyModel[185] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 238 bodyModel[186] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 239 bodyModel[187] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 240 bodyModel[188] = new ModelRendererTurbo(this, 0, 107, textureX, textureY); // Box 241 bodyModel[189] = new ModelRendererTurbo(this, 73, 107, textureX, textureY); // Box 242 bodyModel[190] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 243 bodyModel[191] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 244 bodyModel[192] = new ModelRendererTurbo(this, 85, 65, textureX, textureY); // Box 245 bodyModel[193] = new ModelRendererTurbo(this, 85, 65, textureX, textureY); // Box 246 bodyModel[194] = new ModelRendererTurbo(this, 70, 72, textureX, textureY); // Box 247 bodyModel[195] = new ModelRendererTurbo(this, 70, 72, textureX, textureY); // Box 248 bodyModel[196] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 249 bodyModel[197] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 250 bodyModel[198] = new ModelRendererTurbo(this, 111, 51, textureX, textureY); // Box 251 bodyModel[199] = new ModelRendererTurbo(this, 111, 51, textureX, textureY); // Box 252 bodyModel[200] = new ModelRendererTurbo(this, 121, 51, textureX, textureY); // Box 253 bodyModel[201] = new ModelRendererTurbo(this, 121, 51, textureX, textureY); // Box 254 bodyModel[202] = new ModelRendererTurbo(this, 121, 55, textureX, textureY); // Box 255 bodyModel[203] = new ModelRendererTurbo(this, 121, 55, textureX, textureY); // Box 256 bodyModel[204] = new ModelRendererTurbo(this, 0, 126, textureX, textureY); // Box 258 bodyModel[205] = new ModelRendererTurbo(this, 6, 49, textureX, textureY); // Box 1 bodyModel[0].addShapeBox(0F, 0F, 0F, 21, 1, 1, 0F, 0F, 0F, -4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 4F, 0F, 0F, -4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 4F); // Box 9 bodyModel[0].setRotationPoint(7F, 4.2F, 9F); bodyModel[1].addShapeBox(0F, 0F, 0F, 1, 9, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 4F, 0F, 0F, -4F, 0F, 0F, -4F, 0F, 0F, 4F, 0F, 0F); // Box 10 bodyModel[1].setRotationPoint(32F, -4.8F, 9F); bodyModel[2].addShapeBox(0F, 0F, 0F, 1, 1, 20, 0F, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 11 bodyModel[2].setRotationPoint(32F, -5.8F, -10F); bodyModel[3].addShapeBox(0F, 0F, 0F, 1, 1, 20, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 12 bodyModel[3].setRotationPoint(28F, 4.2F, -10F); bodyModel[4].addShapeBox(0F, 0F, 0F, 10, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 13 bodyModel[4].setRotationPoint(-14F, -6.8F, 13F); bodyModel[5].addShapeBox(0F, 0F, 0F, 21, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 14 bodyModel[5].setRotationPoint(-14F, 4.2F, 13F); bodyModel[6].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F); // Box 20 bodyModel[6].setRotationPoint(-25F, -6.8F, 13F); bodyModel[7].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F); // Box 21 bodyModel[7].setRotationPoint(-25F, 4.2F, 13F); bodyModel[8].addShapeBox(0F, 0F, 0F, 1, 8, 1, 0F, 5F, 0F, 2F, -5F, 0F, 2F, -5F, 0F, -2F, 5F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 30 bodyModel[8].setRotationPoint(-4F, -17.8F, 11F); bodyModel[9].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 31 bodyModel[9].setRotationPoint(-4F, -9.8F, -13F); bodyModel[10].addShapeBox(0F, 0F, 0F, 1, 14, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 41 bodyModel[10].setRotationPoint(-4F, -9.8F, 13F); bodyModel[11].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 46 bodyModel[11].setRotationPoint(2F, 4.2F, -13F); bodyModel[12].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 49 bodyModel[12].setRotationPoint(-14F, 4.2F, -13F); bodyModel[13].addShapeBox(0F, 0F, 0F, 16, 1, 1, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 52 bodyModel[13].setRotationPoint(-41F, -7.8F, 13F); bodyModel[14].addShapeBox(0F, 0F, 0F, 10, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 55 bodyModel[14].setRotationPoint(-35F, 3.2F, 13F); bodyModel[15].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 56 bodyModel[15].setRotationPoint(-26F, 3.2F, -13F); bodyModel[16].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 57 bodyModel[16].setRotationPoint(-35F, 3.2F, -13F); bodyModel[17].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 59 bodyModel[17].setRotationPoint(-35F, -6.8F, 13F); bodyModel[18].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 60 bodyModel[18].setRotationPoint(-26F, -6.8F, 13F); bodyModel[19].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 61 bodyModel[19].setRotationPoint(-14F, -5.8F, 13F); bodyModel[20].addShapeBox(0F, 0F, 0F, 25, 2, 1, 0F, 0F, -2F, -4F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -2F, 4F, 0F, 1F, -4F, 0F, 2F, 0F, 0F, 2F, 0F, 0F, 1F, 4F); // Box 2 bodyModel[20].setRotationPoint(7F, -8.8F, 9F); bodyModel[21].addShapeBox(0F, 0F, 0F, 25, 1, 1, 0F, 0F, 0F, 0F, 0F, -3F, -21F, 0F, -3F, 21F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 3F, -21F, 0F, 3F, 21F, 0F, 0F, 0F); // Box 3 bodyModel[21].setRotationPoint(7F, -8.8F, -13F); bodyModel[22].addShapeBox(0F, 0F, 0F, 1, 1, 22, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 5 bodyModel[22].setRotationPoint(32F, 0.7F, -11F); bodyModel[23].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 6 bodyModel[23].setRotationPoint(32.5F, 2.2F, 4F); bodyModel[24].addShapeBox(0F, 0F, 0F, 1, 1, 22, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 7 bodyModel[24].setRotationPoint(32F, 3.7F, -11F); bodyModel[25].addShapeBox(0F, 0F, 0F, 1, 2, 1, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 9 bodyModel[25].setRotationPoint(32F, 1.7F, 11F); bodyModel[26].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 10 bodyModel[26].setRotationPoint(32.5F, 1.2F, 4F); bodyModel[27].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F); // Box 11 bodyModel[27].setRotationPoint(32.5F, 3.2F, 4F); bodyModel[28].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 12 bodyModel[28].setRotationPoint(32.5F, 2.2F, -7F); bodyModel[29].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 13 bodyModel[29].setRotationPoint(32.5F, 1.2F, -7F); bodyModel[30].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F); // Box 14 bodyModel[30].setRotationPoint(32.5F, 3.2F, -7F); bodyModel[31].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 15 bodyModel[31].setRotationPoint(32.5F, 1.2F, -1.5F); bodyModel[32].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 16 bodyModel[32].setRotationPoint(32.5F, 2.2F, -1.5F); bodyModel[33].addShapeBox(0F, 0F, 0F, 1, 1, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F); // Box 17 bodyModel[33].setRotationPoint(32.5F, 3.2F, -1.5F); bodyModel[34].addShapeBox(0F, 0F, 0F, 13, 1, 1, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 20 bodyModel[34].setRotationPoint(18.5F, 1.7F, 11F); bodyModel[35].addShapeBox(0F, 0F, 0F, 13, 1, 1, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 21 bodyModel[35].setRotationPoint(18.5F, 2.7F, 11F); bodyModel[36].addShapeBox(0F, 0F, 0F, 1, 3, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 22 bodyModel[36].setRotationPoint(17.5F, 1.7F, 11F); bodyModel[37].addShapeBox(0F, 0F, 0F, 14, 1, 25, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F); // Box 24 bodyModel[37].setRotationPoint(-12.5F, 3.7F, -12.5F); bodyModel[38].addShapeBox(0F, 0F, 0F, 15, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F); // Box 25 bodyModel[38].setRotationPoint(-13F, 4.2F, -13F); bodyModel[39].addShapeBox(0F, 0F, 0F, 24, 1, 23, 0F, 0F, -0.3F, 0F, 0F, -3.3F, -4F, 0F, -3.3F, -4F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 2.7F, -4F, 0F, 2.7F, -4F, 0F, -0.3F, 0F); // Box 26 bodyModel[39].setRotationPoint(7.5F, -9.3F, -11.5F); bodyModel[40].addShapeBox(0F, 0F, 0F, 1, 9, 25, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F); // Box 27 bodyModel[40].setRotationPoint(-25.5F, -6.3F, -12.5F); bodyModel[41].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 28 bodyModel[41].setRotationPoint(-26F, -7.8F, -13F); bodyModel[42].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 6F, 0F, 0F, -6F, 0F, 0F, -6F, 0F, 0F, 6F, 0F, 0F); // Box 30 bodyModel[42].setRotationPoint(-6F, -5.8F, 13F); bodyModel[43].addShapeBox(0F, 0F, 0F, 1, 6, 10, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 31 bodyModel[43].setRotationPoint(-23F, -6.8F, 1F); bodyModel[44].addShapeBox(0F, 0F, 0F, 11, 2, 10, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F); // Box 32 bodyModel[44].setRotationPoint(-23F, 1.5F, 1F); bodyModel[45].addShapeBox(0F, 0F, 0F, 21, 1, 1, 0F, 0F, 0F, 4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -4F, 0F, 0F, 4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -4F); // Box 33 bodyModel[45].setRotationPoint(7F, 4.2F, -10F); bodyModel[46].addShapeBox(0F, 0F, 0F, 1, 9, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 4F, 0F, 0F, -4F, 0F, 0F, -4F, 0F, 0F, 4F, 0F, 0F); // Box 34 bodyModel[46].setRotationPoint(32F, -4.8F, -10F); bodyModel[47].addShapeBox(0F, 0F, 0F, 25, 2, 1, 0F, 0F, -2F, 4F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -2F, -4F, 0F, 1F, 4F, 0F, 2F, 0F, 0F, 2F, 0F, 0F, 1F, -4F); // Box 35 bodyModel[47].setRotationPoint(7F, -8.8F, -10F); bodyModel[48].addShapeBox(0F, 0F, 0F, 1, 2, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, 1F, 0F); // Box 36 bodyModel[48].setRotationPoint(32F, 1.7F, -12F); bodyModel[49].addShapeBox(0F, 0F, 0F, 13, 1, 1, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 37 bodyModel[49].setRotationPoint(18.5F, 1.7F, -12F); bodyModel[50].addShapeBox(0F, 0F, 0F, 13, 1, 1, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 38 bodyModel[50].setRotationPoint(18.5F, 2.7F, -12F); bodyModel[51].addShapeBox(0F, 0F, 0F, 10, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 39 bodyModel[51].setRotationPoint(-14F, -6.8F, -14F); bodyModel[52].addShapeBox(0F, 0F, 0F, 21, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 40 bodyModel[52].setRotationPoint(-14F, 4.2F, -14F); bodyModel[53].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F); // Box 41 bodyModel[53].setRotationPoint(-25F, -6.8F, -14F); bodyModel[54].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F); // Box 42 bodyModel[54].setRotationPoint(-25F, 4.2F, -14F); bodyModel[55].addShapeBox(0F, 0F, 0F, 1, 14, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 43 bodyModel[55].setRotationPoint(-4F, -9.8F, -14F); bodyModel[56].addShapeBox(0F, 0F, 0F, 16, 1, 1, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 45 bodyModel[56].setRotationPoint(-41F, -7.8F, -14F); bodyModel[57].addShapeBox(0F, 0F, 0F, 10, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 46 bodyModel[57].setRotationPoint(-35F, 3.2F, -14F); bodyModel[58].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 47 bodyModel[58].setRotationPoint(-35F, -6.8F, -14F); bodyModel[59].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 48 bodyModel[59].setRotationPoint(-26F, -6.8F, -14F); bodyModel[60].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 49 bodyModel[60].setRotationPoint(-14F, -5.8F, -14F); bodyModel[61].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 6F, 0F, 0F, -6F, 0F, 0F, -6F, 0F, 0F, 6F, 0F, 0F); // Box 50 bodyModel[61].setRotationPoint(-6F, -5.8F, -14F); bodyModel[62].addShapeBox(0F, 0F, 0F, 1, 3, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 51 bodyModel[62].setRotationPoint(17.5F, 1.7F, -12F); bodyModel[63].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 52 bodyModel[63].setRotationPoint(32F, -4.8F, -8F); bodyModel[64].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 54 bodyModel[64].setRotationPoint(32F, -4.8F, 7F); bodyModel[65].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 55 bodyModel[65].setRotationPoint(32F, -4.8F, -5.5F); bodyModel[66].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 56 bodyModel[66].setRotationPoint(32F, -4.8F, -0.5F); bodyModel[67].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 57 bodyModel[67].setRotationPoint(32F, -4.8F, -3F); bodyModel[68].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 63 bodyModel[68].setRotationPoint(32F, -4.8F, 4.5F); bodyModel[69].addShapeBox(0F, 0F, 0F, 1, 6, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F, -0.2F, -0.5F, -0.2F); // Box 64 bodyModel[69].setRotationPoint(32F, -4.8F, 2F); bodyModel[70].addShapeBox(0F, 0F, 0F, 25, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, -21F, 0F, 0F, 21F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -21F, 0F, 0F, 21F, 0F, 0F, 0F); // Box 67 bodyModel[70].setRotationPoint(3F, 4.2F, -13F); bodyModel[71].addShapeBox(0F, 0F, 0F, 25, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 21F, 0F, 0F, -21F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 21F, 0F, 0F, -21F, 0F, 0F, 0F); // Box 68 bodyModel[71].setRotationPoint(3F, 4.2F, 12F); bodyModel[72].addShapeBox(0F, 0F, 0F, 15, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F); // Box 69 bodyModel[72].setRotationPoint(-13F, 4.2F, 12F); bodyModel[73].addShapeBox(0F, 0F, 0F, 1, 13, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 70 bodyModel[73].setRotationPoint(6F, -8.8F, -14F); bodyModel[74].addShapeBox(0F, 0F, 0F, 1, 13, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 71 bodyModel[74].setRotationPoint(6F, -8.8F, 13F); bodyModel[75].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, 0F, -0.3F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -0.3F, 0F, 0F, 0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0.5F, 0F); // Box 8 bodyModel[75].setRotationPoint(17F, -7F, 13F); bodyModel[76].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, 0F, -1.7F, 0F, 0F, 0.2F, 0F, 0F, 0.2F, 0F, 0F, -1.7F, 0F, -1.1F, 1.7F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1.1F, 1.7F, 0F); // Box 9 bodyModel[76].setRotationPoint(13F, -6.5F, 13F); bodyModel[77].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, -1.7F, -3F, 0F, 0F, 0.3F, 0F, 0F, 0.3F, 0F, -1.7F, -3F, 0F, -2.9F, 2.5F, 0F, 1.2F, -0.3F, 0F, 1.2F, -0.3F, 0F, -2.9F, 2.5F, 0F); // Box 12 bodyModel[77].setRotationPoint(9F, -4.5F, 13F); bodyModel[78].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, -2.4F, -3F, 0F, -0.3F, 0.5F, 0F, -0.3F, 0.5F, 0F, -2.4F, -3F, 0F, -3.5F, 1.7F, 0F, 0.9F, -1F, 0F, 0.9F, -1F, 0F, -3.5F, 2.5F, 0F); // Box 13 bodyModel[78].setRotationPoint(7F, -1F, 13F); bodyModel[79].addShapeBox(0F, 0F, 0F, 6, 1, 8, 0F, 0F, 0.5F, 0F, 0F, -0.8F, 0F, 0F, -0.8F, 0F, 0F, 0.5F, 0F, 0F, -0.5F, 0F, 0F, 1.2F, 0F, 0F, 1.2F, 0F, 0F, -0.5F, 0F); // Box 14 bodyModel[79].setRotationPoint(21F, -6.5F, 13F); bodyModel[80].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, 0F, -0.3F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -0.3F, 0F, 0F, 0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0.5F, 0F); // Box 82 bodyModel[80].setRotationPoint(17F, -7F, -21F); bodyModel[81].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, 0F, -1.7F, 0F, 0F, 0.2F, 0F, 0F, 0.2F, 0F, 0F, -1.7F, 0F, -1.1F, 1.7F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1.1F, 1.7F, 0F); // Box 83 bodyModel[81].setRotationPoint(13F, -6.5F, -21F); bodyModel[82].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, -1.7F, -3F, 0F, 0F, 0.3F, 0F, 0F, 0.3F, 0F, -1.7F, -3F, 0F, -2.9F, 2.5F, 0F, 1.2F, -0.3F, 0F, 1.2F, -0.3F, 0F, -2.9F, 2.5F, 0F); // Box 84 bodyModel[82].setRotationPoint(9F, -4.5F, -21F); bodyModel[83].addShapeBox(0F, 0F, 0F, 4, 1, 8, 0F, -2.4F, -3F, 0F, -0.3F, 0.5F, 0F, -0.3F, 0.5F, 0F, -2.4F, -3F, 0F, -3.5F, 2.5F, 0F, 0.9F, -1F, 0F, 0.9F, -1F, 0F, -3.5F, 1.7F, 0F); // Box 85 bodyModel[83].setRotationPoint(7F, -1F, -21F); bodyModel[84].addShapeBox(0F, 0F, 0F, 6, 1, 8, 0F, 0F, 0.5F, 0F, 0F, -0.8F, 0F, 0F, -0.8F, 0F, 0F, 0.5F, 0F, 0F, -0.5F, 0F, 0F, 1.2F, 0F, 0F, 1.2F, 0F, 0F, -0.5F, 0F); // Box 86 bodyModel[84].setRotationPoint(21F, -6.5F, -21F); bodyModel[85].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, -0.3F, 0.5F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, -0.3F, 0.5F, 0F, 0.9F, -1F, 0F, 0F, 3F, 0F, 0F, 3F, 0F, 0.9F, -1F, 0F); // Box 92 bodyModel[85].setRotationPoint(-26F, -1F, 14F); bodyModel[86].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0.3F, 0F, -1.7F, -3F, 0F, -1.7F, -3F, 0F, 0F, 0.3F, 0F, 1.2F, -0.3F, 0F, -2.9F, 2.5F, 0F, -2.9F, 2.5F, 0F, 1.2F, -0.3F, 0F); // Box 93 bodyModel[86].setRotationPoint(-28F, -4.5F, 14F); bodyModel[87].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0.2F, 0F, 0F, -1.7F, 0F, 0F, -1.7F, 0F, 0F, 0.2F, 0F, 0F, 0F, 0F, -1.1F, 1.7F, 0F, -1.1F, 1.7F, 0F, 0F, 0F, 0F); // Box 94 bodyModel[87].setRotationPoint(-32F, -6.5F, 14F); bodyModel[88].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0.5F, 0F, 0F, 0.5F, 0F, 0F, 0F, 0F); // Box 95 bodyModel[88].setRotationPoint(-36F, -7F, 14F); bodyModel[89].addShapeBox(0F, 0F, 0F, 8, 1, 9, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 96 bodyModel[89].setRotationPoint(-44F, -7F, 14F); bodyModel[90].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -4F, 0F, 0F, 0F); // Box 97 bodyModel[90].setRotationPoint(-22F, 2F, 14F); bodyModel[91].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, -0.3F, 0.5F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, -0.3F, 0.5F, 0F, 0.9F, -1F, 0F, 0F, 3F, 0F, 0F, 3F, 0F, 0.9F, -1F, 0F); // Box 98 bodyModel[91].setRotationPoint(-26F, -1F, -23F); bodyModel[92].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0.3F, 0F, -1.7F, -3F, 0F, -1.7F, -3F, 0F, 0F, 0.3F, 0F, 1.2F, -0.3F, 0F, -2.9F, 2.5F, 0F, -2.9F, 2.5F, 0F, 1.2F, -0.3F, 0F); // Box 99 bodyModel[92].setRotationPoint(-28F, -4.5F, -23F); bodyModel[93].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0.2F, 0F, 0F, -1.7F, 0F, 0F, -1.7F, 0F, 0F, 0.2F, 0F, 0F, 0F, 0F, -1.1F, 1.7F, 0F, -1.1F, 1.7F, 0F, 0F, 0F, 0F); // Box 100 bodyModel[93].setRotationPoint(-32F, -6.5F, -23F); bodyModel[94].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0.5F, 0F, 0F, 0.5F, 0F, 0F, 0F, 0F); // Box 101 bodyModel[94].setRotationPoint(-36F, -7F, -23F); bodyModel[95].addShapeBox(0F, 0F, 0F, 8, 1, 9, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 102 bodyModel[95].setRotationPoint(-44F, -7F, -23F); bodyModel[96].addShapeBox(0F, 0F, 0F, 4, 1, 9, 0F, 0F, 0F, 0F, 0F, 0F, -4F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -4F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 103 bodyModel[96].setRotationPoint(-22F, 2F, -23F); bodyModel[97].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 104 bodyModel[97].setRotationPoint(6F, -8.8F, -13F); bodyModel[98].addShapeBox(0F, 0F, 0F, 8, 1, 23, 0F, 0F, -0.3F, 0F, 0F, -1.3F, 0F, 0F, -1.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 0.7F, 0F, 0F, 0.7F, 0F, 0F, -0.3F, 0F); // Box 106 bodyModel[98].setRotationPoint(-2.5F, -10.3F, -11.5F); bodyModel[99].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F); // Box 107 bodyModel[99].setRotationPoint(-3F, -6.8F, -13F); bodyModel[100].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F); // Box 108 bodyModel[100].setRotationPoint(-3F, -6.8F, 12F); bodyModel[101].addShapeBox(0F, 0F, 0F, 1, 1, 20, 0F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 109 bodyModel[101].setRotationPoint(-9F, -18.8F, -10F); bodyModel[102].addShapeBox(0F, 0F, 0F, 1, 1, 20, 0F, -1F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, -1F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 112 bodyModel[102].setRotationPoint(-24F, -20.8F, -10F); bodyModel[103].addShapeBox(0F, 0F, 0F, 1, 4, 1, 0F, -5F, 0F, 2F, 5F, 0F, 2F, 5F, 0F, -2F, -5F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 114 bodyModel[103].setRotationPoint(-29F, -19.8F, 11F); bodyModel[104].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 119 bodyModel[104].setRotationPoint(-3F, -6.8F, 13F); bodyModel[105].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 120 bodyModel[105].setRotationPoint(-3F, -6.8F, -14F); bodyModel[106].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 121 bodyModel[106].setRotationPoint(6F, -6.8F, -13F); bodyModel[107].addShapeBox(0F, 0F, 0F, 25, 1, 1, 0F, 0F, 0F, 0F, 0F, -3F, 21F, 0F, -3F, -21F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 3F, 21F, 0F, 3F, -21F, 0F, 0F, 0F); // Box 122 bodyModel[107].setRotationPoint(7F, -8.8F, 12F); bodyModel[108].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, -1F, 25F, 0F, -1F, -25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 25F, 0F, 1F, -25F, 0F, 0F, 0F); // Box 123 bodyModel[108].setRotationPoint(-3F, -9.8F, 12F); bodyModel[109].addShapeBox(0F, 0F, 0F, 9, 1, 1, 0F, 0F, 0F, 0F, 0F, -1F, -25F, 0F, -1F, 25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, -25F, 0F, 1F, 25F, 0F, 0F, 0F); // Box 124 bodyModel[109].setRotationPoint(-3F, -9.8F, -13F); bodyModel[110].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 125 bodyModel[110].setRotationPoint(-4F, -9.8F, -13F); bodyModel[111].addShapeBox(0F, 0F, 0F, 1, 8, 1, 0F, 5F, 0F, -2F, -5F, 0F, -2F, -5F, 0F, 2F, 5F, 0F, 2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 126 bodyModel[111].setRotationPoint(-4F, -17.8F, -12F); bodyModel[112].addShapeBox(0F, 0F, 0F, 1, 4, 1, 0F, -5F, 0F, -2F, 5F, 0F, -2F, 5F, 0F, 2F, -5F, 0F, 2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 127 bodyModel[112].setRotationPoint(-29F, -19.8F, -12F); bodyModel[113].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -6F, 0F, 0F, 6F, 0F, 0F, 6F, 0F, 0F, -6F, 0F, 0F); // Box 129 bodyModel[113].setRotationPoint(-2F, -5.8F, -14F); bodyModel[114].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -6F, 0F, 0F, 6F, 0F, 0F, 6F, 0F, 0F, -6F, 0F, 0F); // Box 131 bodyModel[114].setRotationPoint(-2F, -5.8F, 13F); bodyModel[115].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 132 bodyModel[115].setRotationPoint(-29F, -7.8F, -13F); bodyModel[116].addShapeBox(0F, 0F, 0F, 7, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 133 bodyModel[116].setRotationPoint(-42F, 3.2F, 13F); bodyModel[117].addShapeBox(0F, 0F, 0F, 7, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 134 bodyModel[117].setRotationPoint(-42F, 3.2F, -14F); bodyModel[118].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 135 bodyModel[118].setRotationPoint(-42F, 3.2F, -13F); bodyModel[119].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 1F, 0F, 0F); // Box 136 bodyModel[119].setRotationPoint(-41F, -6.8F, 13F); bodyModel[120].addShapeBox(0F, 0F, 0F, 1, 10, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 1F, 0F, 0F); // Box 137 bodyModel[120].setRotationPoint(-41F, -6.8F, -14F); bodyModel[121].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 138 bodyModel[121].setRotationPoint(-4F, -6.8F, -13F); bodyModel[122].addShapeBox(0F, 0F, 0F, 1, 3, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 139 bodyModel[122].setRotationPoint(-23F, -0.8F, 1F); bodyModel[123].addShapeBox(0F, 0F, 0F, 1, 3, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 140 bodyModel[123].setRotationPoint(-23F, -0.8F, 9F); bodyModel[124].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 0F, 0F, 0F, -1F, 25F, 0F, -1F, -25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 25F, 0F, 1F, -25F, 0F, 0F, 0F); // Box 141 bodyModel[124].setRotationPoint(-25F, 3.2F, 12F); bodyModel[125].addShapeBox(0F, 0F, 0F, 11, 1, 1, 0F, 0F, 0F, 0F, 0F, -1F, -25F, 0F, -1F, 25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, -25F, 0F, 1F, 25F, 0F, 0F, 0F); // Box 143 bodyModel[125].setRotationPoint(-25F, 3.2F, -13F); bodyModel[126].addShapeBox(0F, 0F, 0F, 8, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -25F, 0F, 0F, 25F, 0F, 0F, 0F); // Box 144 bodyModel[126].setRotationPoint(-34F, 3.2F, -13F); bodyModel[127].addShapeBox(0F, 0F, 0F, 6, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 25F, 0F, 0F, -25F, 0F, 0F, 0F); // Box 147 bodyModel[127].setRotationPoint(-41F, 3.2F, 12F); bodyModel[128].addShapeBox(0F, 0F, 0F, 14, 1, 25, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F); // Box 148 bodyModel[128].setRotationPoint(-40.5F, 2.7F, -12.5F); bodyModel[129].addShapeBox(0F, 0F, 0F, 1, 2, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 149 bodyModel[129].setRotationPoint(-14F, 2.2F, 10F); bodyModel[130].addShapeBox(0F, 0F, 0F, 1, 2, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 150 bodyModel[130].setRotationPoint(-14F, 2.2F, 1F); bodyModel[131].addShapeBox(0F, 0F, 0F, 14, 1, 1, 0F, 0F, 2F, -2F, 0F, 0F, -2F, 0F, 0F, 2F, 0F, 2F, 2F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -2F, 0F); // Box 151 bodyModel[131].setRotationPoint(-23F, -18.8F, -10F); bodyModel[132].addShapeBox(0F, 0F, 0F, 1, 8, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 5F, 0F, 2F, -5F, 0F, 2F, -5F, 0F, -2F, 5F, 0F, -2F); // Box 159 bodyModel[132].setRotationPoint(-29F, -15.8F, -12F); bodyModel[133].addShapeBox(0F, 0F, 0F, 1, 8, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 5F, 0F, -2F, -5F, 0F, -2F, -5F, 0F, 2F, 5F, 0F, 2F); // Box 160 bodyModel[133].setRotationPoint(-29F, -15.8F, 11F); bodyModel[134].addShapeBox(0F, 0F, 0F, 1, 1, 26, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 161 bodyModel[134].setRotationPoint(-34F, -7.8F, -13F); bodyModel[135].addShapeBox(0F, 0F, 0F, 12, 2, 8, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 162 bodyModel[135].setRotationPoint(-40F, -6F, -1F); bodyModel[136].addShapeBox(0F, 0F, 0F, 12, 2, 8, 0F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F, 0.2F, 0F, 0.2F); // Box 163 bodyModel[136].setRotationPoint(-40F, -5F, -1F); bodyModel[137].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 164 bodyModel[137].setRotationPoint(-38F, -5F, -3.2F); bodyModel[138].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 165 bodyModel[138].setRotationPoint(-35F, -5F, -3.2F); bodyModel[139].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 166 bodyModel[139].setRotationPoint(-32F, -5F, -3.2F); bodyModel[140].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 167 bodyModel[140].setRotationPoint(-32F, -5F, 6.8F); bodyModel[141].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 168 bodyModel[141].setRotationPoint(-35F, -5F, 6.8F); bodyModel[142].addShapeBox(0F, 0F, 0F, 2, 2, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 169 bodyModel[142].setRotationPoint(-38F, -5F, 6.8F); bodyModel[143].addShapeBox(0F, 0F, 0F, 12, 2, 8, 0F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F); // Box 170 bodyModel[143].setRotationPoint(-40F, -2F, -1F); bodyModel[144].addShapeBox(0F, 0F, 0F, 12, 3, 8, 0F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 171 bodyModel[144].setRotationPoint(-40F, 0F, -1F); bodyModel[145].addShapeBox(0F, 0F, 0F, 12, 2, 8, 0F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F); // Box 172 bodyModel[145].setRotationPoint(-40F, -4F, -1F); bodyModel[146].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 173 bodyModel[146].setRotationPoint(-32F, -5.5F, -2.2F); bodyModel[147].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 174 bodyModel[147].setRotationPoint(-35F, -5.5F, -2.2F); bodyModel[148].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 175 bodyModel[148].setRotationPoint(-38F, -5.5F, -2.2F); bodyModel[149].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 176 bodyModel[149].setRotationPoint(-32F, -5.5F, 5.8F); bodyModel[150].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 177 bodyModel[150].setRotationPoint(-35F, -5.5F, 5.8F); bodyModel[151].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 178 bodyModel[151].setRotationPoint(-38F, -5.5F, 5.8F); bodyModel[152].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 179 bodyModel[152].setRotationPoint(-32F, -3.5F, 5.8F); bodyModel[153].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 180 bodyModel[153].setRotationPoint(-35F, -3.5F, 5.8F); bodyModel[154].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 181 bodyModel[154].setRotationPoint(-38F, -3.5F, 5.8F); bodyModel[155].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 182 bodyModel[155].setRotationPoint(-32F, -3.5F, -2.2F); bodyModel[156].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 183 bodyModel[156].setRotationPoint(-35F, -3.5F, -2.2F); bodyModel[157].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F); // Box 184 bodyModel[157].setRotationPoint(-38F, -3.5F, -2.2F); bodyModel[158].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 185 bodyModel[158].setRotationPoint(-38F, -5F, -3.2F); bodyModel[159].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 186 bodyModel[159].setRotationPoint(-35F, -5F, -3.2F); bodyModel[160].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 187 bodyModel[160].setRotationPoint(-32F, -5F, -3.2F); bodyModel[161].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 188 bodyModel[161].setRotationPoint(-32F, -5F, 7.8F); bodyModel[162].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 189 bodyModel[162].setRotationPoint(-35F, -5F, 7.8F); bodyModel[163].addShapeBox(0F, 0F, 0F, 2, 2, 1, 0F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F, 0F, 0F, -0.1F); // Box 190 bodyModel[163].setRotationPoint(-38F, -5F, 7.8F); bodyModel[164].addShapeBox(0F, 0F, 0F, 12, 1, 8, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F); // Box 191 bodyModel[164].setRotationPoint(-40F, -1.5F, -1F); bodyModel[165].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 192 bodyModel[165].setRotationPoint(-39F, -6.5F, 3F); bodyModel[166].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 193 bodyModel[166].setRotationPoint(-31F, -6.5F, 3F); bodyModel[167].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 194 bodyModel[167].setRotationPoint(-36.5F, -6.5F, 3F); bodyModel[168].addShapeBox(0F, 0F, 0F, 2, 1, 2, 0F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, -0.5F, 0F, -0.5F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 195 bodyModel[168].setRotationPoint(-33.5F, -6.5F, 3F); bodyModel[169].addShapeBox(-0.5F, 0F, -0.5F, 1, 2, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F); // Box 211 bodyModel[169].setRotationPoint(-3.5F, -11.8F, 13.5F); bodyModel[169].rotateAngleY = 0.43633231F; bodyModel[170].addShapeBox(-0.5F, -2F, -1F, 1, 2, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 212 bodyModel[170].setRotationPoint(-3.5F, -11.8F, 13.5F); bodyModel[170].rotateAngleY = 0.43633231F; bodyModel[171].addShapeBox(-0.5F, 0F, -0.5F, 1, 2, 1, 0F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F); // Box 213 bodyModel[171].setRotationPoint(-3.5F, -11.8F, -13.5F); bodyModel[171].rotateAngleY = -0.43633231F; bodyModel[172].addShapeBox(-0.5F, -2F, -1F, 1, 2, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 214 bodyModel[172].setRotationPoint(-3.5F, -11.8F, -13.5F); bodyModel[172].rotateAngleY = -0.43633231F; bodyModel[173].addShapeBox(0F, 0F, 0F, 1, 12, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 2F, 0F, 4F, -2F, 0F, 4F, -2F, 0F, -4F, 2F, 0F, -4F); // Box 215 bodyModel[173].setRotationPoint(-24F, -19.8F, -10F); bodyModel[174].addShapeBox(0F, 0F, 0F, 1, 12, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 2F, 0F, -4F, -2F, 0F, -4F, -2F, 0F, 4F, 2F, 0F, 4F); // Box 216 bodyModel[174].setRotationPoint(-24F, -19.8F, 9F); bodyModel[175].addShapeBox(0F, 0F, 0F, 5, 4, 4, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 218 bodyModel[175].setRotationPoint(-33F, -1F, -12F); bodyModel[175].rotateAngleY = 0.29670597F; bodyModel[176].addShapeBox(0F, 0F, 0F, 5, 2, 3, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 219 bodyModel[176].setRotationPoint(-34F, 1F, -6F); bodyModel[176].rotateAngleY = 0.05235988F; bodyModel[177].addShapeBox(0F, 0F, 0F, 1, 8, 0, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -5.3F, 0F, 0F, 4.7F, 0F, 0F, 4.7F, 0F, 2F, -5.3F, 0F, 2F); // Box 230 bodyModel[177].setRotationPoint(-8.5F, -18F, 9F); bodyModel[178].addShapeBox(0F, 0F, 0F, 1, 3, 8, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -5.3F, 0F, 0F, 4.7F, 0F, 0F, 4.7F, 0F, 0F, -5.3F, 0F, 0F); // Box 231 bodyModel[178].setRotationPoint(-8.5F, -18F, 1F); bodyModel[179].addShapeBox(0F, 0F, 0F, 14, 1, 1, 0F, 0F, 2F, 2F, 0F, 0F, 2F, 0F, 0F, -2F, 0F, 2F, -2F, 0F, -2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -2F, 0F); // Box 232 bodyModel[179].setRotationPoint(-23F, -18.8F, 9F); bodyModel[180].addShapeBox(0F, 0F, 0F, 14, 1, 1, 0F, 0F, 2F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 2F, 0F, 0F, -2.5F, 0F, 0F, -0.5F, 0F, 0F, -0.5F, 0F, 0F, -2.5F, 0F); // Box 233 bodyModel[180].setRotationPoint(-23F, -18.8F, -0.5F); bodyModel[181].addShapeBox(0F, 0F, 0F, 1, 2, 8, 0F, -2.3F, 0F, 0F, 1.7F, 0F, 0F, 1.7F, 0F, 0F, -2.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F); // Box 234 bodyModel[181].setRotationPoint(-3.5F, -12F, 1F); bodyModel[182].addShapeBox(0F, 0F, 0F, 1, 6, 10, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 235 bodyModel[182].setRotationPoint(-23F, -6.8F, -11F); bodyModel[183].addShapeBox(0F, 0F, 0F, 11, 2, 10, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F, -3F, 0F, 0F); // Box 236 bodyModel[183].setRotationPoint(-23F, 1.5F, -11F); bodyModel[184].addShapeBox(0F, 0F, 0F, 1, 3, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 237 bodyModel[184].setRotationPoint(-23F, -0.8F, -3F); bodyModel[185].addShapeBox(0F, 0F, 0F, 1, 3, 2, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F, -0.2F, 0F, 0F); // Box 238 bodyModel[185].setRotationPoint(-23F, -0.8F, -11F); bodyModel[186].addShapeBox(0F, 0F, 0F, 1, 2, 2, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 239 bodyModel[186].setRotationPoint(-14F, 2.2F, -11F); bodyModel[187].addShapeBox(0F, 0F, 0F, 1, 2, 2, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 240 bodyModel[187].setRotationPoint(-14F, 2.2F, -2F); bodyModel[188].addShapeBox(0F, 0F, 0F, 1, 2, 8, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -5.3F, 0F, 0F, 4.7F, 0F, 0F, 4.7F, 0F, 0F, -5.3F, 0F, 0F); // Box 241 bodyModel[188].setRotationPoint(-8.5F, -18F, -9F); bodyModel[189].addShapeBox(0F, 0F, 0F, 1, 3, 8, 0F, -2.3F, 0F, 0F, 1.7F, 0F, 0F, 1.7F, 0F, 0F, -2.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F); // Box 242 bodyModel[189].setRotationPoint(-3.5F, -13F, -9F); bodyModel[190].addShapeBox(0F, 0F, 0F, 1, 8, 0, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -5.3F, 0F, 2F, 4.7F, 0F, 2F, 4.7F, 0F, 0F, -5.3F, 0F, 0F); // Box 243 bodyModel[190].setRotationPoint(-8.5F, -18F, -9F); bodyModel[191].addShapeBox(0F, 0F, 0F, 1, 8, 2, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -5.3F, 0F, 0F, 4.7F, 0F, 0F, 4.7F, 0F, 0F, -5.3F, 0F, 0F); // Box 244 bodyModel[191].setRotationPoint(-8.5F, -18F, -1F); bodyModel[192].addShapeBox(0F, 0F, 0F, 1, 4, 9, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 4.7F, 0F, 0F, -5.3F, 0F, 0F, -5.3F, 0F, 2F, 4.7F, 0F, 2F); // Box 245 bodyModel[192].setRotationPoint(-24.5F, -20F, 0F); bodyModel[193].addShapeBox(0F, 0F, 0F, 1, 4, 9, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 4.7F, 0F, 2F, -5.3F, 0F, 2F, -5.3F, 0F, 0F, 4.7F, 0F, 0F); // Box 246 bodyModel[193].setRotationPoint(-24.5F, -20F, -9F); bodyModel[194].addShapeBox(0F, 0F, 0F, 1, 8, 11, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 4.7F, 0F, 0F, -5.3F, 0F, 0F, -5.3F, 0F, 2F, 4.7F, 0F, 2F); // Box 247 bodyModel[194].setRotationPoint(-29.5F, -16F, 0F); bodyModel[195].addShapeBox(0F, 0F, 0F, 1, 8, 11, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, 4.7F, 0F, 2F, -5.3F, 0F, 2F, -5.3F, 0F, 0F, 4.7F, 0F, 0F); // Box 248 bodyModel[195].setRotationPoint(-29.5F, -16F, -11F); bodyModel[196].addShapeBox(0F, 0F, 0F, 2, 2, 42, 0F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F, 0F, 0F, -2F); // Box 249 bodyModel[196].setRotationPoint(19.5F, 1.5F, -21F); bodyModel[197].addBox(0F, 0F, 0F, 2, 2, 46, 0F); // Box 250 bodyModel[197].setRotationPoint(-36.5F, 1.5F, -23F); bodyModel[198].addBox(0F, 0F, 0F, 1, 4, 3, 0F); // Box 251 bodyModel[198].setRotationPoint(0F, -1F, 7F); bodyModel[198].rotateAngleZ = -0.55850536F; bodyModel[199].addBox(0F, 0F, 0F, 1, 4, 3, 0F); // Box 252 bodyModel[199].setRotationPoint(0F, -1F, -1F); bodyModel[199].rotateAngleZ = -0.55850536F; bodyModel[200].addBox(1F, 2F, 1F, 3, 1, 1, 0F); // Box 253 bodyModel[200].setRotationPoint(0F, -1F, -1F); bodyModel[200].rotateAngleZ = -0.55850536F; bodyModel[201].addBox(1F, 2F, 1F, 3, 1, 1, 0F); // Box 254 bodyModel[201].setRotationPoint(0F, -1F, 7F); bodyModel[201].rotateAngleZ = -0.55850536F; bodyModel[202].addBox(3F, 1F, 0F, 2, 3, 3, 0F); // Box 255 bodyModel[202].setRotationPoint(0F, -1F, 7F); bodyModel[202].rotateAngleZ = -0.55850536F; bodyModel[203].addBox(3F, 1F, 0F, 2, 3, 3, 0F); // Box 256 bodyModel[203].setRotationPoint(0F, -1F, -1F); bodyModel[203].rotateAngleZ = -0.55850536F; bodyModel[204].addShapeBox(0F, 0F, 0F, 1, 11, 26, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F, -0.3F, 0F, 0F); // Box 258 bodyModel[204].setRotationPoint(3F, -6F, -13F); bodyModel[205].addShapeBox(0F, 0F, 0F, 5, 2, 3, 0F, 0F, 0F, 0.2F, 0F, 0F, 0.2F, 0F, 0F, 0.2F, 0F, 0F, 0.2F, 0F, -1F, 0.2F, 0F, -1F, 0.2F, 0F, -1F, 0.2F, 0F, -1F, 0.2F); // Box 1 bodyModel[205].setRotationPoint(-34F, 0F, -6F); bodyModel[205].rotateAngleY = 0.05235988F; leftFrontWheelModel = new ModelRendererTurbo[1]; leftFrontWheelModel[0] = new ModelRendererTurbo(this, 112, 73, textureX, textureY); // Box 10 leftFrontWheelModel[0].addShape3D(8F, -7F, -5F, new Shape2D(new Coord2D[]{new Coord2D(4, 0, 4, 0), new Coord2D(12, 0, 12, 0), new Coord2D(15, 3, 15, 3), new Coord2D(15, 11, 15, 11), new Coord2D(12, 14, 12, 14), new Coord2D(4, 14, 4, 14), new Coord2D(1, 11, 1, 11), new Coord2D(1, 3, 1, 3)}), 5, 14, 14, 52, 5, ModelRendererTurbo.MR_FRONT, new float[]{5, 8, 5, 8, 5, 8, 5, 8}); // Box 10 leftFrontWheelModel[0].setRotationPoint(20.5F, 2.7F, 15F); rightFrontWheelModel = new ModelRendererTurbo[1]; rightFrontWheelModel[0] = new ModelRendererTurbo(this, 112, 73, textureX, textureY); // Box 10 rightFrontWheelModel[0].addShape3D(8F, -7F, 0F, new Shape2D(new Coord2D[]{new Coord2D(4, 0, 4, 0), new Coord2D(12, 0, 12, 0), new Coord2D(15, 3, 15, 3), new Coord2D(15, 11, 15, 11), new Coord2D(12, 14, 12, 14), new Coord2D(4, 14, 4, 14), new Coord2D(1, 11, 1, 11), new Coord2D(1, 3, 1, 3)}), 5, 14, 14, 52, 5, ModelRendererTurbo.MR_FRONT, new float[]{5, 8, 5, 8, 5, 8, 5, 8}); // Box 10 rightFrontWheelModel[0].setRotationPoint(20.5F, 2.7F, -15F); leftBackWheelModel = new ModelRendererTurbo[1]; leftBackWheelModel[0] = new ModelRendererTurbo(this, 117, 96, textureX, textureY); // Box 10 leftBackWheelModel[0].addShape3D(8F, -7F, -7F, new Shape2D(new Coord2D[]{new Coord2D(4, 0, 4, 0), new Coord2D(12, 0, 12, 0), new Coord2D(15, 3, 15, 3), new Coord2D(15, 11, 15, 11), new Coord2D(12, 14, 12, 14), new Coord2D(4, 14, 4, 14), new Coord2D(1, 11, 1, 11), new Coord2D(1, 3, 1, 3)}), 7, 14, 14, 52, 7, ModelRendererTurbo.MR_FRONT, new float[]{5, 8, 5, 8, 5, 8, 5, 8}); // Box 10 leftBackWheelModel[0].setRotationPoint(-35.5F, 2.7F, 15F); rightBackWheelModel = new ModelRendererTurbo[1]; rightBackWheelModel[0] = new ModelRendererTurbo(this, 117, 96, textureX, textureY); // Box 10 rightBackWheelModel[0].addShape3D(8F, -7F, 0F, new Shape2D(new Coord2D[]{new Coord2D(4, 0, 4, 0), new Coord2D(12, 0, 12, 0), new Coord2D(15, 3, 15, 3), new Coord2D(15, 11, 15, 11), new Coord2D(12, 14, 12, 14), new Coord2D(4, 14, 4, 14), new Coord2D(1, 11, 1, 11), new Coord2D(1, 3, 1, 3)}), 7, 14, 14, 52, 7, ModelRendererTurbo.MR_FRONT, new float[]{5, 8, 5, 8, 5, 8, 5, 8}); // Box 10 rightBackWheelModel[0].setRotationPoint(-35.5F, 2.7F, -15F); steeringWheelModel = new ModelRendererTurbo[11]; steeringWheelModel[0] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 196 steeringWheelModel[1] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 200 steeringWheelModel[2] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 201 steeringWheelModel[3] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 202 steeringWheelModel[4] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 203 steeringWheelModel[5] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 205 steeringWheelModel[6] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 206 steeringWheelModel[7] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 207 steeringWheelModel[8] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 209 steeringWheelModel[9] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 210 steeringWheelModel[10] = new ModelRendererTurbo(this, 0, 98, textureX, textureY); // Box 0 steeringWheelModel[0].addShapeBox(0F, -0.5F, -3F, 1, 1, 6, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F); // Box 196 steeringWheelModel[0].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[1].addShapeBox(0F, -2F, 3F, 1, 1, 1, 0F, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 200 steeringWheelModel[1].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[2].addShapeBox(0F, -2F, -4F, 1, 1, 1, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 201 steeringWheelModel[2].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[3].addShapeBox(0F, -3F, -3F, 1, 1, 6, 0F, 0F, -0.5F, -1F, 0F, -0.5F, -1F, 0F, -0.5F, -1F, 0F, -0.5F, -1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F); // Box 202 steeringWheelModel[3].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[4].addShapeBox(0F, 2F, 3F, 1, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F, 0F, 0F, 1F, 0F, 0F, -1F, 0F, 0F, -1F); // Box 203 steeringWheelModel[4].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[5].addShapeBox(0F, 2F, -4F, 1, 1, 1, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F, 0F, 0F, -1F, 0F, 0F, 1F, 0F, 0F, 1F); // Box 205 steeringWheelModel[5].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[6].addBox(0F, -1F, -4F, 1, 3, 1, 0F); // Box 206 steeringWheelModel[6].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[7].addBox(0F, -1F, 3F, 1, 3, 1, 0F); // Box 207 steeringWheelModel[7].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[8].addShapeBox(0F, 0F, -0.5F, 1, 3, 1, 0F, -0.2F, -0.3F, -0.2F, -0.2F, -0.3F, -0.2F, -0.2F, -0.3F, -0.2F, -0.2F, -0.3F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F, -0.2F, 0F, -0.2F); // Box 209 steeringWheelModel[8].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[9].addShapeBox(0.6F, -0.5F, -0.5F, 3, 1, 1, 0F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F, -0.2F, -0.3F, -0.3F); // Box 210 steeringWheelModel[9].setRotationPoint(-7F, -9.5F, 7F); steeringWheelModel[10].addShapeBox(0F, 3F, -3F, 1, 1, 6, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -0.5F, -1F, 0F, -0.5F, -1F, 0F, -0.5F, -1F, 0F, -0.5F, -1F); // Box 0 steeringWheelModel[10].setRotationPoint(-7F, -9.5F, 7F); translateAll(0F, 0F, 0F); flipAll(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelGroundSkeleton.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.1.13 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; import com.flansmod.client.model.ModelItemHolder; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelGroundSkeleton extends ModelItemHolder { int textureX = 32; int textureY = 16; public ModelGroundSkeleton() { baseModel = new ModelRendererTurbo[3]; baseModel[0] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 1 baseModel[1] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 2 baseModel[2] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Box 3 baseModel[0].addBox(0F, 0F, 0F, 8, 8, 8, 0F); // Box 1 baseModel[0].setRotationPoint(4F, -4F, 0F); baseModel[0].rotateAngleX = 0.52359878F; baseModel[1].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 2 baseModel[1].setRotationPoint(1F, 6F, 9F); baseModel[1].rotateAngleX = 2.35619449F; baseModel[1].rotateAngleY = -0.26179939F; baseModel[2].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 3 baseModel[2].setRotationPoint(13F, 6F, 8F); baseModel[2].rotateAngleX = 2.35619449F; baseModel[2].rotateAngleY = 0.26179939F; itemOffset = new Vector3f(0F, -0.35F, 0.5F); //itemRotation = new Vector3f(-30F, 0F, 0F); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelGunRack.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.1.13 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; import com.flansmod.client.model.ModelItemHolder; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelGunRack extends ModelItemHolder { int textureX = 256; int textureY = 32; public ModelGunRack() { baseModel = new ModelRendererTurbo[10]; baseModel[0] = new ModelRendererTurbo(this, 1, 1, textureX, textureY); // Import Box5 baseModel[1] = new ModelRendererTurbo(this, 57, 1, textureX, textureY); // Box 6 baseModel[2] = new ModelRendererTurbo(this, 73, 1, textureX, textureY); // Box 8 baseModel[3] = new ModelRendererTurbo(this, 97, 1, textureX, textureY); // Box 9 baseModel[4] = new ModelRendererTurbo(this, 113, 1, textureX, textureY); // Box 10 baseModel[5] = new ModelRendererTurbo(this, 137, 1, textureX, textureY); // Box 11 baseModel[6] = new ModelRendererTurbo(this, 153, 1, textureX, textureY); // Box 12 baseModel[7] = new ModelRendererTurbo(this, 169, 1, textureX, textureY); // Box 13 baseModel[8] = new ModelRendererTurbo(this, 201, 1, textureX, textureY); // Box 14 baseModel[9] = new ModelRendererTurbo(this, 217, 1, textureX, textureY); // Box 15 baseModel[0].addBox(0F, 0F, 0F, 16, 1, 8, 0F); // Import Box5 baseModel[0].setRotationPoint(0F, -1F, 0F); baseModel[1].addBox(0F, 0F, 0F, 1, 5, 6, 0F); // Box 6 baseModel[1].setRotationPoint(0F, -11F, 0F); baseModel[2].addBox(0F, 0F, 0F, 1, 5, 8, 0F); // Box 8 baseModel[2].setRotationPoint(0F, -6F, 0F); baseModel[3].addBox(0F, 0F, 0F, 1, 5, 4, 0F); // Box 9 baseModel[3].setRotationPoint(0F, -16F, 0F); baseModel[4].addBox(0F, 0F, 0F, 1, 5, 8, 0F); // Box 10 baseModel[4].setRotationPoint(15F, -6F, 0F); baseModel[5].addBox(0F, 0F, 0F, 1, 5, 6, 0F); // Box 11 baseModel[5].setRotationPoint(15F, -11F, 0F); baseModel[6].addBox(0F, 0F, 0F, 1, 5, 4, 0F); // Box 12 baseModel[6].setRotationPoint(15F, -16F, 0F); baseModel[7].addBox(0F, 0F, 0F, 14, 15, 1, 0F); // Box 13 baseModel[7].setRotationPoint(1F, -16F, 0F); baseModel[8].addBox(0F, 0F, 0F, 1, 1, 6, 0F); // Box 14 baseModel[8].setRotationPoint(5F, -9F, 0F); baseModel[9].addBox(0F, 0F, 0F, 1, 1, 6, 0F); // Box 15 baseModel[9].setRotationPoint(10F, -9F, 0F); itemOffset = new Vector3f(0F, 0.5F, -0.25F); itemRotation = new Vector3f(75F, 90F, 0F); //flipAll(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelNukeDrop.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; public class ModelNukeDrop extends ModelBase { private ModelRendererTurbo[] nukeModel; private ModelRendererTurbo[] mushroomCloudModel; private ModelRendererTurbo[] ballModel; public ModelNukeDrop() { int textureX = 64, textureY = 64; nukeModel = new ModelRendererTurbo[5]; nukeModel[0] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); nukeModel[0].addBox(-2, -4, -2, 4, 8, 4); nukeModel[1] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); nukeModel[1].addTrapezoid(-2, -6, -2, 4, 2, 4, 0F, -1F, ModelRendererTurbo.MR_BOTTOM); nukeModel[2] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); nukeModel[2].addTrapezoid(-2, 4, -2, 4, 2, 4, 0F, -1F, ModelRendererTurbo.MR_TOP); nukeModel[3] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); nukeModel[3].addTrapezoid(-2, 6, -2, 4, 2, 4, 0F, -1F, ModelRendererTurbo.MR_BOTTOM); nukeModel[4] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); nukeModel[4].addBox(-2, 8, -2, 4, 2, 4); ballModel = new ModelRendererTurbo[2]; ballModel[0] = new ModelRendererTurbo(this, 32, 0, textureX, textureY); ballModel[0].addSphere(0, 0, 0, 16, 16, 16, 32, 32); ballModel[1] = new ModelRendererTurbo(this, 32, 0, textureX, textureY); ballModel[1].flip = true; ballModel[1].addSphere(0, 0, 0, 16, 16, 16, 32, 32); } public void renderNuke(float scale) { for(ModelRendererTurbo aNukeModel : nukeModel) aNukeModel.render(scale); } public void renderMushroomCloud(float scale) { } public void renderBall(float scale) { for(ModelRendererTurbo aBallModel : ballModel) aBallModel.render(scale); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelPowerCube.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.1.13 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; public class ModelPowerCube extends ModelBase { int textureX = 512; int textureY = 32; private ModelRendererTurbo[] bodyModel; public ModelPowerCube() { bodyModel = new ModelRendererTurbo[13]; bodyModel[0] = new ModelRendererTurbo(this, 1, 1, textureX, textureY); // Box 0 bodyModel[1] = new ModelRendererTurbo(this, 41, 1, textureX, textureY); // Box 1 bodyModel[2] = new ModelRendererTurbo(this, 73, 1, textureX, textureY); // Box 2 bodyModel[3] = new ModelRendererTurbo(this, 105, 1, textureX, textureY); // Box 3 bodyModel[4] = new ModelRendererTurbo(this, 129, 1, textureX, textureY); // Box 4 bodyModel[5] = new ModelRendererTurbo(this, 169, 1, textureX, textureY); // Box 5 bodyModel[6] = new ModelRendererTurbo(this, 201, 1, textureX, textureY); // Box 6 bodyModel[7] = new ModelRendererTurbo(this, 233, 1, textureX, textureY); // Box 7 bodyModel[8] = new ModelRendererTurbo(this, 265, 1, textureX, textureY); // Box 8 bodyModel[9] = new ModelRendererTurbo(this, 281, 1, textureX, textureY); // Box 9 bodyModel[10] = new ModelRendererTurbo(this, 297, 1, textureX, textureY); // Box 10 bodyModel[11] = new ModelRendererTurbo(this, 313, 1, textureX, textureY); // Box 11 bodyModel[12] = new ModelRendererTurbo(this, 329, 1, textureX, textureY); // Box 12 bodyModel[0].addBox(0F, 0F, 0F, 16, 2, 2, 0F); // Box 0 bodyModel[0].setRotationPoint(0F, -2F, 0F); bodyModel[1].addBox(0F, 0F, 0F, 16, 2, 2, 0F); // Box 1 bodyModel[1].setRotationPoint(0F, -2F, 14F); bodyModel[2].addBox(0F, 0F, 0F, 2, 2, 12, 0F); // Box 2 bodyModel[2].setRotationPoint(0F, -2F, 2F); bodyModel[3].addBox(0F, 0F, 0F, 2, 2, 12, 0F); // Box 3 bodyModel[3].setRotationPoint(14F, -2F, 2F); bodyModel[4].addBox(0F, 0F, 0F, 16, 2, 2, 0F); // Box 4 bodyModel[4].setRotationPoint(0F, -16F, 0F); bodyModel[5].addBox(0F, 0F, 0F, 16, 2, 2, 0F); // Box 5 bodyModel[5].setRotationPoint(0F, -16F, 14F); bodyModel[6].addBox(0F, 0F, 0F, 2, 2, 12, 0F); // Box 6 bodyModel[6].setRotationPoint(14F, -16F, 2F); bodyModel[7].addBox(0F, 0F, 0F, 2, 2, 12, 0F); // Box 7 bodyModel[7].setRotationPoint(0F, -16F, 2F); bodyModel[8].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 8 bodyModel[8].setRotationPoint(0F, -14F, 0F); bodyModel[9].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 9 bodyModel[9].setRotationPoint(14F, -14F, 0F); bodyModel[10].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 10 bodyModel[10].setRotationPoint(14F, -14F, 14F); bodyModel[11].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 11 bodyModel[11].setRotationPoint(0F, -14F, 14F); bodyModel[12].addBox(0F, 0F, 0F, 8, 8, 8, 0F); // Box 12 bodyModel[12].setRotationPoint(4F, -12F, 4F); } public void render() { float f5 = 0.0625F; for(int i = 0; i < 12; i++) { bodyModel[i].render(f5); } } public void renderPower() { bodyModel[12].render(0.0625F); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelSkullBoss.java ================================================ package com.flansmod.apocalypse.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import net.minecraft.client.model.ModelBase; public class ModelSkullBoss extends ModelBase { private ModelRendererTurbo head; private ModelRendererTurbo jaw; public ModelSkullBoss() { int textureX = 64, textureY = 32; head = new ModelRendererTurbo(this, 0, 0, textureX, textureY); head.addBox(-4, 0, -4, 8, 8, 8); jaw = new ModelRendererTurbo(this, 32, 0, textureX, textureY); jaw.addBox(-3, -4, -3, 6, 4, 6); } public void renderHead(float scale) { head.render(scale); } public void renderJaw(float scale) { jaw.render(scale); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelSkullDrone.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.1.13 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; import com.flansmod.client.model.ModelItemHolder; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; import net.minecraft.client.model.ModelBase; public class ModelSkullDrone extends ModelBase { int textureX = 64; int textureY = 32; private ModelRendererTurbo[] baseModel, propellerModel; public Vector3f itemOrigin = new Vector3f(0f, -0.5f, 0f); public int numPropellers = 4; public Vector3f[] propellerOrigins = new Vector3f[] { new Vector3f(1.1f, 0.55f, 1.1f), new Vector3f(1.1f, 0.55f, -1.1f), new Vector3f(-1.1f, 0.55f, -1.1f), new Vector3f(-1.1f, 0.55f, 1.1f) }; public ModelSkullDrone() { baseModel = new ModelRendererTurbo[6]; baseModel[0] = new ModelRendererTurbo(this, 0, 0, textureX, textureY); // Head baseModel[1] = new ModelRendererTurbo(this, 32, 0, textureX, textureY); // Jaw baseModel[2] = new ModelRendererTurbo(this, 56, 0, textureX, textureY); // Arm 1 baseModel[3] = new ModelRendererTurbo(this, 56, 0, textureX, textureY); // Arm 2 baseModel[4] = new ModelRendererTurbo(this, 56, 0, textureX, textureY); // Arm 3 baseModel[5] = new ModelRendererTurbo(this, 56, 0, textureX, textureY); // Arm 4 baseModel[0].addBox(-4, 0, -4, 8, 8, 8); // Head baseModel[1].addBox(-3, -4, -3, 6, 4, 6); // Jaw for(int i = 0; i < 4; i++) { baseModel[i + 2].addBox(-1F, 0F, -1F, 2, 24, 2, 0F); // Arm 1 baseModel[i + 2].setRotationPoint(propellerOrigins[i].x * 4f, 0F, propellerOrigins[i].z * 4f); baseModel[i + 2].rotateAngleX = -(float)Math.PI * 0.375f; baseModel[i + 2].rotateAngleY = (float)Math.PI * (1.25f + i * 0.5f); } propellerModel = new ModelRendererTurbo[2]; propellerModel[0] = new ModelRendererTurbo(this, 0, 16, textureX, textureY); // Box 1 propellerModel[1] = new ModelRendererTurbo(this, 0, 18, textureX, textureY); // Box 2 propellerModel[0].addBox(-6F, -0.5F, -0.5F, 12, 1, 1, 0F); // Box 1 propellerModel[1].addBox(-0.5F, -0.5F, -6F, 1, 1, 12, 0F); // Box 2 } public void renderBase(float scale) { for(ModelRendererTurbo mr : baseModel) mr.render(scale); } public void renderPropeller(float scale) { for(ModelRendererTurbo mr : propellerModel) mr.render(scale); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelSlumpedSkeleton.java ================================================ //This File was created with the Minecraft-SMP Modelling Toolbox 2.1.1.13 // Copyright (C) 2015 Minecraft-SMP.de // This file is for Flan's Flying Mod Version 4.0.x+ package com.flansmod.apocalypse.client.model; import com.flansmod.client.model.ModelItemHolder; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelSlumpedSkeleton extends ModelItemHolder { int textureX = 128; int textureY = 32; public ModelSlumpedSkeleton() { baseModel = new ModelRendererTurbo[6]; baseModel[0] = new ModelRendererTurbo(this, 1, 1, textureX, textureY); // Import Box1 baseModel[1] = new ModelRendererTurbo(this, 41, 1, textureX, textureY); // Import Box2 baseModel[2] = new ModelRendererTurbo(this, 57, 1, textureX, textureY); // Import Box3 baseModel[3] = new ModelRendererTurbo(this, 69, 1, textureX, textureY); // Import Box5 baseModel[4] = new ModelRendererTurbo(this, 97, 1, textureX, textureY); // Box 0 baseModel[5] = new ModelRendererTurbo(this, 113, 1, textureX, textureY); // Box 1 baseModel[0].addBox(0F, 0F, 0F, 8, 8, 8, 0F); // Import Box1 baseModel[0].setRotationPoint(4F, -5F, 12F); baseModel[0].rotateAngleX = -0.78539816F; baseModel[1].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Import Box2 baseModel[1].setRotationPoint(2F, 6F, 9F); baseModel[1].rotateAngleX = 0.78539816F; baseModel[1].rotateAngleY = -0.26179939F; baseModel[2].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Import Box3 baseModel[2].setRotationPoint(12F, 6F, 8F); baseModel[2].rotateAngleX = 0.78539816F; baseModel[2].rotateAngleY = 0.26179939F; baseModel[3].addBox(0F, 0F, 0F, 8, 12, 4, 0F); // Import Box5 baseModel[3].setRotationPoint(4F, 4F, 7F); baseModel[4].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 0 baseModel[4].setRotationPoint(5F, 16F, 10F); baseModel[4].rotateAngleX = 1.57079633F; baseModel[4].rotateAngleY = -0.26179939F; baseModel[5].addBox(0F, 0F, 0F, 2, 12, 2, 0F); // Box 1 baseModel[5].setRotationPoint(9F, 16F, 10F); baseModel[5].rotateAngleX = 1.57079633F; baseModel[5].rotateAngleY = 0.26179939F; translateAll(0, -16, -8); itemOffset = new Vector3f(0F, -0.35F, 0.25F); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/ModelTeleporter.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; public class ModelTeleporter extends ModelBase { private ModelRendererTurbo model; public ModelTeleporter() { int textureX = 64, textureY = 64; model = new ModelRendererTurbo(this, 0, 0, textureX, textureY); model.addSphere(0, 0, 0, 16, 16, 16, 64, 64); } public void render(float f) { model.render(f); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderFakePlayer.java ================================================ package com.flansmod.apocalypse.client.model; import com.flansmod.apocalypse.common.entity.EntityFakePlayer; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderBiped; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; public class RenderFakePlayer extends RenderBiped { private static final ResourceLocation SURVIVOR_SKIN = new ResourceLocation("flansmodapocalypse", "textures/entity/Survivor.png"); public RenderFakePlayer(RenderManager man, ModelBiped model, float f) { super(man, model, f); this.addLayer(new LayerBipedArmor(this)); } protected ResourceLocation getEntityTexture(EntityFakePlayer entity) { return SURVIVOR_SKIN; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderFakePlayer(manager, new ModelBiped(), 0); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderNukeDrop.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntityTeleporter; public class RenderNukeDrop extends Render { private static final ResourceLocation texture = new ResourceLocation("flansmodapocalypse", "textures/entity/NukeDrop.png"); private ModelNukeDrop model; public RenderNukeDrop(RenderManager rm) { super(rm); model = new ModelNukeDrop(); MinecraftForge.EVENT_BUS.register(this); } public void render(EntityNukeDrop entity, double x, double y, double z, float p_76986_8_, float partialTicks) { bindEntityTexture(entity); EntityNukeDrop nuke = entity; GlStateManager.pushMatrix(); GlStateManager.translate(x, y, z); if(entity.onGround) { //Exploded float alpha = ((float)nuke.timeSinceExplosion / (float)EntityNukeDrop.explosionLength); alpha = 1F - alpha * alpha; alpha *= 0.5F; GlStateManager.enableAlpha(); RenderHelper.disableStandardItemLighting(); GlStateManager.shadeModel(7425); GlStateManager.enableBlend(); GlStateManager.blendFunc(770, 1); GlStateManager.disableCull(); GlStateManager.pushMatrix(); float scale = 1F - 1F / ((float)nuke.timeSinceExplosion / 5F + 1); scale *= 100F * scale; GlStateManager.scale(-scale, scale, scale); GlStateManager.color(1F, 1F, 1F, alpha); model.renderBall(0.0625F); GlStateManager.popMatrix(); GlStateManager.enableCull(); GlStateManager.disableBlend(); GlStateManager.shadeModel(7424); RenderHelper.enableStandardItemLighting(); } else { //Falling model.renderNuke(0.0625F); } GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntityNukeDrop entity) { return texture; } @SubscribeEvent public void renderWorld(RenderWorldLastEvent event) { //Get the world World world = Minecraft.getMinecraft().world; if(world == null) return; //Get the camera frustrum for clipping Entity camera = Minecraft.getMinecraft().getRenderViewEntity(); double x = camera.lastTickPosX + (camera.posX - camera.lastTickPosX) * event.getPartialTicks(); double y = camera.lastTickPosY + (camera.posY - camera.lastTickPosY) * event.getPartialTicks(); double z = camera.lastTickPosZ + (camera.posZ - camera.lastTickPosZ) * event.getPartialTicks(); //Frustum frustrum = new Frustum(); //frustrum.setPosition(x, y, z); //Push GlStateManager.pushMatrix(); //Setup lighting Minecraft.getMinecraft().entityRenderer.enableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableLighting(); GlStateManager.disableBlend(); RenderHelper.enableStandardItemLighting(); GlStateManager.translate(-(float)x, -(float)y, -(float)z); for(Object entity : world.loadedEntityList) { if(entity instanceof EntityNukeDrop) { EntityNukeDrop nuke = (EntityNukeDrop)entity; int i = nuke.getBrightnessForRender(); if(nuke.isBurning()) { i = 15728880; } int j = i % 65536; int k = i / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); render(nuke, nuke.prevPosX + (nuke.posX - nuke.prevPosX) * event.getPartialTicks(), nuke.prevPosY + (nuke.posY - nuke.prevPosY) * event.getPartialTicks(), nuke.prevPosZ + (nuke.posZ - nuke.prevPosZ) * event.getPartialTicks(), 0F, event.getPartialTicks()); } } //Reset Lighting Minecraft.getMinecraft().entityRenderer.disableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableLighting(); //Pop GlStateManager.popMatrix(); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderNukeDrop(manager); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderPowerCube.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.util.ResourceLocation; import com.flansmod.apocalypse.common.blocks.TileEntityPowerCube; public class RenderPowerCube extends TileEntitySpecialRenderer { private ResourceLocation TEXTURE = new ResourceLocation("flansmodapocalypse", "textures/blocks/PowerCube.png"); private ModelPowerCube model; public RenderPowerCube() { model = new ModelPowerCube(); } @Override public void render(TileEntityPowerCube holder, double posX, double posY, double posZ, float partialTicks, int destroyStage, float alpha) { if(model != null) { bindTexture(TEXTURE); GlStateManager.pushMatrix(); GlStateManager.translate((float)posX, (float)posY, (float)posZ); GlStateManager.rotate(180F, 0F, 0F, 1F); /* switch(EnumFacing.HORIZONTALS[holder.getBlockMetadata()]) { case NORTH: GlStateManager.translate(-1F, 0F, 0F); GlStateManager.rotate(0F, 0F, 1F, 0F); break; case EAST: GlStateManager.translate(-1F, 0F, 1F); GlStateManager.rotate(90F, 0F, 1F, 0F); break; case SOUTH: GlStateManager.translate(0F, 0F, 1F); GlStateManager.rotate(180F, 0F, 1F, 0F); break; case WEST: GlStateManager.rotate(270F, 0F, 1F, 0F); break; } */ GlStateManager.translate(-1F, 0F, 0F); model.render(); float angle = (holder.age + partialTicks) * 10F; float scale = (float)Math.sin(angle * 0.01F); GlStateManager.pushMatrix(); GlStateManager.translate(0.5F, -0.5F, 0.5F); GlStateManager.rotate(angle * 1.345F, 1F, 0F, 0F); GlStateManager.rotate(angle * 0.8925F, 0F, 1F, 0F); GlStateManager.rotate(angle * 0.245F, 0F, 0F, 1F); GlStateManager.scale(scale, scale, scale); GlStateManager.translate(-0.5F, 0.5F, -0.5F); model.renderPower(); GlStateManager.popMatrix(); scale = (float)Math.cos(angle * 0.0134F); GlStateManager.pushMatrix(); GlStateManager.translate(0.5F, -0.5F, 0.5F); GlStateManager.rotate(angle * 1.783F, 1F, 0F, 0F); GlStateManager.rotate(angle * 1.145F, 0F, 1F, 0F); GlStateManager.rotate(angle * 0.3567F, 0F, 0F, 1F); GlStateManager.scale(scale, scale, scale); GlStateManager.translate(-0.5F, 0.5F, -0.5F); model.renderPower(); GlStateManager.popMatrix(); scale = (float)Math.sin(angle * 0.0254F); GlStateManager.pushMatrix(); GlStateManager.translate(0.5F, -0.5F, 0.5F); GlStateManager.rotate(angle * 1.9993F, 1F, 0F, 0F); GlStateManager.rotate(angle * 1.111F, 0F, 1F, 0F); GlStateManager.rotate(angle * 0.578F, 0F, 0F, 1F); GlStateManager.scale(scale, scale, scale); GlStateManager.translate(-0.5F, 0.5F, -0.5F); model.renderPower(); GlStateManager.popMatrix(); GlStateManager.popMatrix(); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderSkullBoss.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntitySkullBoss; import com.flansmod.apocalypse.common.entity.EntityTeleporter; public class RenderSkullBoss extends Render { private static final ResourceLocation texture = new ResourceLocation("flansmodapocalypse", "textures/entity/skullboss.png"); private ModelSkullBoss model; public RenderSkullBoss(RenderManager rm) { super(rm); model = new ModelSkullBoss(); } public void doRender(EntitySkullBoss entity, double x, double y, double z, float p_76986_8_, float partialTicks) { bindEntityTexture(entity); GlStateManager.pushMatrix(); GlStateManager.translate(x, y, z); GlStateManager.rotate(-entity.rotationYaw + entity.GetSpawnSpin(partialTicks), 0, 1, 0); GlStateManager.rotate(entity.rotationPitch, 0, 0, 1); GlStateManager.scale(32f, 32f, 32f); float laughFactor = entity.GetLaughFactor(partialTicks); GlStateManager.pushMatrix(); { GlStateManager.rotate(laughFactor * 15.0f, 0, 0, 1); model.renderHead(1F / 16F); } GlStateManager.popMatrix(); GlStateManager.pushMatrix(); { GlStateManager.rotate(-laughFactor * 15.0f, 0, 0, 1); model.renderJaw(1F / 16F); } GlStateManager.popMatrix(); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntitySkullBoss entity) { return texture; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderSkullBoss(manager); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderSkullDrone.java ================================================ package com.flansmod.apocalypse.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.apocalypse.common.entity.EntitySkullDrone; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntitySkullBoss; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.client.ClientProxy; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.model.ModelGun; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.vector.Vector3f; public class RenderSkullDrone extends Render { private static final ResourceLocation texture = new ResourceLocation("flansmodapocalypse", "textures/entity/skulldrone.png"); private ModelSkullDrone model; private static final ItemRenderer renderer = new ItemRenderer(Minecraft.getMinecraft()); private static RenderItem renderItem; public RenderSkullDrone(RenderManager rm) { super(rm); renderItem = Minecraft.getMinecraft().getRenderItem(); model = new ModelSkullDrone(); } public void doRender(EntitySkullDrone entity, double x, double y, double z, float p_76986_8_, float partialTicks) { bindEntityTexture(entity); GlStateManager.pushMatrix(); GlStateManager.translate(x, y, z); GlStateManager.rotate(-entity.rotationYaw, 0, 1, 0); GlStateManager.pushMatrix(); { model.renderBase(1F / 16F); for(int i = 0; i < model.numPropellers; i++) { GlStateManager.pushMatrix(); GlStateManager.translate(model.propellerOrigins[i].x, model.propellerOrigins[i].y, model.propellerOrigins[i].z); GlStateManager.rotate((entity.ticksExisted + partialTicks) * (i % 2== 0 ? -80f :80f), 0f, 1f, 0f); GlStateManager.scale(2f, 2f, 2f); model.renderPropeller(1f / 16f); GlStateManager.popMatrix(); } } GlStateManager.popMatrix(); GlStateManager.pushMatrix(); ItemStack stack = entity.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); if(!stack.isEmpty()) { model.itemOrigin = new Vector3f(0f, -0.5f, 0f); GlStateManager.translate(model.itemOrigin.x, model.itemOrigin.y, model.itemOrigin.z); GlStateManager.rotate(entity.rotationPitch, 0, 0, 1); Item item = stack.getItem(); if(item instanceof ItemGun && ((ItemGun)item).GetType().model != null) { GunType gunType = ((ItemGun)item).GetType(); ModelGun model = gunType.model; //GlStateManager.rotate(-90F, 0F, 0F, 1F); bindTexture(FlansModResourceHandler.getTexture(gunType)); ClientProxy.gunRenderer.renderGun(stack, gunType, 1F / 16F, model, entity.animations, 0F); } else { GlStateManager.rotate(-135F, 0F, 0F, 1F); GlStateManager.translate(0F, -0.4F, 0F); IBakedModel ibakedmodel = renderItem.getItemModelMesher().getItemModel(stack); renderItem.renderItem(stack, ibakedmodel); GlStateManager.disableRescaleNormal(); } } GlStateManager.popMatrix(); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntitySkullDrone entity) { return texture; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderSkullDrone(manager); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderSurvivor.java ================================================ package com.flansmod.apocalypse.client.model; import com.flansmod.apocalypse.common.entity.EntitySurvivor; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderBiped; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.layers.LayerBipedArmor; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; public class RenderSurvivor extends RenderBiped { private static final ResourceLocation SURVIVOR_SKIN = new ResourceLocation("flansmodapocalypse", "textures/entity/Survivor.png"); public RenderSurvivor(RenderManager man, ModelBiped model, float f) { super(man, model, f); this.addLayer(new LayerBipedArmor(this)); } protected ResourceLocation getEntityTexture(EntitySurvivor entity) { return SURVIVOR_SKIN; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderSurvivor(manager, new ModelBiped(), 0); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/client/model/RenderTeleporter.java ================================================ package com.flansmod.apocalypse.client.model; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.client.model.RenderParachute; import com.flansmod.common.tools.EntityParachute; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; public class RenderTeleporter extends Render { private ModelTeleporter model; private static final ResourceLocation texture = new ResourceLocation("flansmodapocalypse", "textures/entity/Teleporter.png"); private static int[] randomiser = new int[]{145, 167, 324, 541}; public RenderTeleporter(RenderManager renderManager) { super(renderManager); model = new ModelTeleporter(); } public void doRender(EntityTeleporter entity, double x, double y, double z, float p_76986_8_, float partialTicks) { bindEntityTexture(entity); RenderHelper.disableStandardItemLighting(); //GlStateManager.disableTexture2D(); GlStateManager.shadeModel(7425); //GlStateManager.enableBlend(); //GlStateManager.blendFunc(770, 1); //GlStateManager.disableAlpha(); GlStateManager.enableCull(); //GlStateManager.depthMask(false); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); for(int i = 0; i < 4; i++) { float scaleX = 0.4F * (float)Math.sin((entity.ticksExisted + partialTicks) * 0.1F + 1.7F * randomiser[i]) + 1.0F; float scaleY = 0.4F * (float)Math.cos((entity.ticksExisted + partialTicks) * 0.114F + 1.145F + 0.35F * randomiser[(i + 1) % 4]) + 1.0F; float scaleZ = 0.4F * (float)Math.cos((entity.ticksExisted + partialTicks) * 0.121F + 0.7545F - 11F * randomiser[i]) + 1.0F; float rotation = 100F * (float)Math.cos((entity.ticksExisted + partialTicks) * 0.000121F * randomiser[(i + 2) % 4]); GlStateManager.pushMatrix(); GlStateManager.translate(0.0F, 1.0F, 0.0F); GlStateManager.translate(x, y, z); GlStateManager.rotate(rotation, 1F, 1F, 0F); GlStateManager.rotate(100F * (float)Math.sin((entity.ticksExisted + partialTicks) * 0.000173F * randomiser[(i + 2) % 4]), 1F, 0F, 1F); GlStateManager.scale(-scaleX, scaleY, scaleZ); model.render(0.0625F); GlStateManager.popMatrix(); } GlStateManager.depthMask(true); GlStateManager.disableCull(); GlStateManager.disableBlend(); GlStateManager.shadeModel(7424); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableTexture2D(); GlStateManager.enableAlpha(); RenderHelper.enableStandardItemLighting(); } @Override protected ResourceLocation getEntityTexture(EntityTeleporter entity) { return texture; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderTeleporter(manager); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/ApocalypseData.java ================================================ package com.flansmod.apocalypse.common; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.UUID; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.common.FlansMod; public class ApocalypseData { /** * The point at which each player entered the apocalypse. For deciding where they should come out */ public HashMap entryPoints = new HashMap<>(); @SubscribeEvent public void worldData(WorldEvent event) { if(event.getWorld().isRemote) return; if(event instanceof WorldEvent.Load) { loadPerWorldData(event, event.getWorld()); savePerWorldData(event, event.getWorld()); } if(event instanceof WorldEvent.Save) { savePerWorldData(event, event.getWorld()); } } private void savePerWorldData(WorldEvent event, World world) { if(world.provider.getDimension() == 0) { try { //Make directory File dir = new File(world.getSaveHandler().getWorldDirectory(), "apocalypse"); if(!dir.exists()) dir.mkdirs(); //Save per-world file File file = new File(dir, "apocalypse.dat"); NBTTagCompound tags = new NBTTagCompound(); if(!file.exists()) file.createNewFile(); CompressedStreamTools.write(tags, new DataOutputStream(new FileOutputStream(file))); //Save per-player file for(Map.Entry uuidBlockPosEntry : entryPoints.entrySet()) { UUID uuid = (uuidBlockPosEntry).getKey(); File playerFile = new File(dir, uuid.toString() + ".dat"); NBTTagCompound playerTags = new NBTTagCompound(); if(!playerFile.exists()) playerFile.createNewFile(); BlockPos pos = entryPoints.get(uuid); playerTags.setIntArray("EntryPoint", new int[]{pos.getX(), pos.getY(), pos.getZ()}); CompressedStreamTools.write(playerTags, new DataOutputStream(new FileOutputStream(playerFile))); } } catch(Exception e) { FlansMod.log.throwing(e); } } } private void loadPerWorldData(WorldEvent event, World world) { if(world.provider.getDimension() == 0) { try { //Make directory File dir = new File(world.getSaveHandler().getWorldDirectory(), "apocalypse"); if(!dir.exists()) return; //Load per-world file File file = new File(world.getSaveHandler().getWorldDirectory(), "apocalypse/apocalypse.dat"); if(!file.exists()) file.createNewFile(); NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); //Load per-player file for(File playerFile : dir.listFiles()) { if(playerFile.getName().equals("apocalypse.dat")) continue; UUID uuid = UUID.fromString(playerFile.getName().split("\\.")[0]); NBTTagCompound playerTags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(playerFile))); int[] entryPoint = playerTags.getIntArray("EntryPoint"); entryPoints.put(uuid, new BlockPos(entryPoint[0], entryPoint[1], entryPoint[2])); } } catch(Exception e) { FlansMod.log.throwing(e); } } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/CommonProxyApocalypse.java ================================================ package com.flansmod.apocalypse.common; import java.util.EnumSet; import java.util.HashMap; import net.minecraft.entity.Entity; import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketPlayerPosLook; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.fml.common.registry.EntityRegistry; import com.flansmod.apocalypse.common.entity.EntityAIMecha; import com.flansmod.apocalypse.common.entity.EntityFakePlayer; import com.flansmod.apocalypse.common.entity.EntityFlyByPlane; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntitySurvivor; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.apocalypse.common.network.PacketApocalypseCountdown; import com.flansmod.apocalypse.common.world.TeleporterApocalypse; import com.flansmod.apocalypse.common.world.buildings.StructureAbandonedVillagePieces; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.parts.PartType; public class CommonProxyApocalypse { private int apocalypseCountdown = 0; /** * The mecha that started all this */ private EntityMecha apocalypseMecha = null; public ApocalypseData data; private static HashMap deathPoints = new HashMap<>(); public void preInit(FMLPreInitializationEvent event) { MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(data = new ApocalypseData()); StructureAbandonedVillagePieces.registerVillagePieces(); } public void init(FMLInitializationEvent event) { FlansMod.getPacketHandler().registerPacket(PacketApocalypseCountdown.class); } public void postInit(FMLPostInitializationEvent event) { } /** * Tick hook for server */ @SubscribeEvent public void tick(TickEvent.ServerTickEvent event) { if(event.phase == TickEvent.Phase.START) { //Countdown to 0 and on 0, do apocalypse things if(getApocalypseCountdown() > 0) { if(apocalypseMecha == null || apocalypseMecha.isDead()) { setApocalypseCountdown(0); } else { setApocalypseCountdown(getApocalypseCountdown() - 1); //Wiggle the apocalypse mecha apocalypseMecha.getSeat(0).prevLooking = apocalypseMecha.getSeat(0).looking.clone(); apocalypseMecha.getSeat(0).looking.rotateGlobalYaw(apocalypseMecha.world.rand.nextFloat() * 10F); apocalypseMecha.getSeat(0).looking.rotateGlobalPitch((float)apocalypseMecha.world.rand.nextGaussian() * 3F); //Drop nukes if(getApocalypseCountdown() % 20 == 0) { World world = apocalypseMecha.world; float range = 150F; world.spawnEntity(new EntityNukeDrop(world, apocalypseMecha.posX + world.rand.nextGaussian() * range, 256, apocalypseMecha.posZ + world.rand.nextGaussian() * range)); } //Start the apocalypse if(getApocalypseCountdown() == 0) { FlansMod.log.info("The apocalypse has begun!"); EntityPlayer placer = apocalypseMecha.placer; switch(FlansModApocalypse.OPTION) { case DIM: for(int i = 0; i < placer.world.playerEntities.size(); i++) if(placer.world.playerEntities.get(i).dimension == 0) sendPlayerToApocalypse(placer.world.playerEntities.get(i)); break; case DIM_OPT_IN: break; case NEARBY: for(Object player : placer.world.playerEntities) if(((Entity)player).dimension == 0 && ((Entity)player).getDistanceSq(placer) < 50 * 50) sendPlayerToApocalypse((EntityPlayer)player); break; case NEARBY_OPT_IN: break; case PLACER_ONLY: sendPlayerToApocalypse(placer); break; } apocalypseMecha.setDead(); } } } WorldServer world = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(FlansModApocalypse.dimensionID); if(world != null) { FlansModApocalypse.INSTANCE.UpdateBossFight(world); for(int i = 0; i < world.playerEntities.size(); i++) { EntityPlayer player = world.playerEntities.get(i); //FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().transferPlayerToDimension((EntityPlayerMP)player, 0, new TeleporterApocalypse(FMLCommonHandler.instance().getMinecraftServerInstance().worldServerForDimension(FlansModApocalypse.dimensionID))); if(world.rand.nextInt(5000) == 0) { double dX = world.rand.nextFloat() - 0.5F; double dZ = world.rand.nextFloat() - 0.5F; double mag = Math.sqrt(dX * dX + dZ * dZ); dX /= mag; dZ /= mag; double dist = 200D; dX *= dist; dZ *= dist; PlaneType type = FlansModApocalypse.getLootGenerator().getRandomPlane(world.rand); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Engine", FlansModApocalypse.getLootGenerator().getRandomEngine(type, world.rand).shortName); tags.setString("Type", type.shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } DriveableData data = new DriveableData(tags); EntityFlyByPlane plane = new EntityFlyByPlane(world, player.posX + dX, 120, player.posZ + dZ, type, data); plane.throttle = 1F; world.spawnEntity(plane); float yaw = 180F + (float)Math.atan2(dZ, dX) * 180F / 3.14159F; plane.getSeat(0).looking.setAngles(yaw, 0F, 0F); plane.getSeat(0).prevLooking.setAngles(yaw, 0F, 0F); plane.axes.setAngles(yaw, 0F, 0F); plane.prevAxes.setAngles(yaw, 0F, 0F); Entity pilot = new EntitySkeleton(world); pilot.setPosition(plane.posX, plane.posY, plane.posZ); world.spawnEntity(pilot); pilot.startRiding(plane.getSeat(0)); } if(world.rand.nextInt(FlansModApocalypse.WANDERING_SURVIVOR_RARITY) == 0 && !world.provider.isDaytime()) { double angle = world.rand.nextFloat() * 3.14159F * 2F; double dist = 50D; double dX = Math.cos(angle) * dist; double dZ = Math.sin(angle) * dist; EntitySurvivor survivor = new EntitySurvivor(world); survivor.setPosition(player.posX + dX, world.getTopSolidOrLiquidBlock(new BlockPos(player.posX + dX, 0, player.posZ + dZ)).getY() + 1D, player.posZ + dZ); world.spawnEntity(survivor); } } } } } private void sendPlayerToApocalypse(EntityPlayer player) { //Make a copy of the player to hold their inventory and hang around until they get back EntityFakePlayer fakePlayer = new EntityFakePlayer(player.world, player); player.world.spawnEntity(fakePlayer); player.inventory.clear(); //Teleport them, making note of where they got in player.timeUntilPortal = 10; data.entryPoints.put(player.getPersistentID(), new BlockPos(apocalypseMecha.posX, apocalypseMecha.posY, apocalypseMecha.posZ)); BlockPos exitPoint = new BlockPos(apocalypseMecha.posX, 128, apocalypseMecha.posZ); for(; FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(FlansModApocalypse.dimensionID).isAirBlock(exitPoint); exitPoint = exitPoint.down()) { } FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().transferPlayerToDimension((EntityPlayerMP)player, FlansModApocalypse.dimensionID, new TeleporterApocalypse(FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(FlansModApocalypse.dimensionID), exitPoint.add(0, 1, 0))); giveStarterKit(player); } private void giveStarterKit(EntityPlayer player) { player.inventory.addItemStackToInventory(new ItemStack(Items.STONE_PICKAXE)); player.inventory.addItemStackToInventory(new ItemStack(Items.STONE_SHOVEL)); player.inventory.addItemStackToInventory(new ItemStack(Blocks.LOG, 8)); player.inventory.addItemStackToInventory(new ItemStack(Items.COOKED_BEEF, 4)); } @SubscribeEvent public void itemPlaced(EntityJoinWorldEvent event) { if(!event.getWorld().isRemote && event.getEntity() instanceof EntityMecha && event.getEntity().dimension == 0) { EntityMecha mecha = (EntityMecha)event.getEntity(); PartType engine = mecha.getDriveableData().engine; if(engine.isAIChip) { setApocalypseCountdown(FlansModApocalypse.apocalypseCountdownLength); apocalypseMecha = mecha; FlansMod.getPacketHandler().sendTo(new PacketApocalypseCountdown(getApocalypseCountdown()), (EntityPlayerMP)mecha.placer); } } } /** * Take note of where the player died */ @SubscribeEvent public void playerDied(LivingDeathEvent event) { if(event.getEntityLiving().dimension == FlansModApocalypse.dimensionID && event.getEntityLiving() instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)event.getEntityLiving(); deathPoints.put(player, new BlockPos(player.posX, player.posY, player.posZ)); } } /** * Respawn the player somewhere nearby where they died on the surface */ @SubscribeEvent public void playerRespawned(PlayerRespawnEvent event) { if(event.player.dimension == FlansModApocalypse.dimensionID) { BlockPos pos = deathPoints.get(event.player); if(pos != null) { EnumSet enumset = EnumSet.noneOf(SPacketPlayerPosLook.EnumFlags.class); float angle = event.player.world.rand.nextFloat() * 2F * 3.14159F; pos = pos.add((int)(Math.cos(angle) * FlansModApocalypse.SPAWN_RADIUS), 128 - pos.getY(), (int)(Math.sin(angle) * FlansModApocalypse.SPAWN_RADIUS)); if(pos.getDistance(0, pos.getY(), 0) < 200d) { pos.add((pos.getX() > 0 ? 100 : -100) - pos.getX(), 0, (pos.getZ() > 0 ? 100 : -100) - pos.getZ()); } for(; event.player.world.isAirBlock(pos); pos = pos.down()) { } ((EntityPlayerMP)event.player).connection.setPlayerLocation(pos.getX() + 0.5D, pos.getY() + 1.5D, pos.getZ() + 0.5D, 0F, 0F, enumset); event.player.posX = event.player.prevPosX = pos.getX() + 0.5D; event.player.posY = event.player.prevPosY = pos.getY() + 0.5D; event.player.posZ = event.player.prevPosZ = pos.getZ() + 0.5D; } } } public int getApocalypseCountdown() { return apocalypseCountdown; } private void setApocalypseCountdown(int apocalypseCountdown) { this.apocalypseCountdown = apocalypseCountdown; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/FlansModApocalypse.java ================================================ package com.flansmod.apocalypse.common; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.item.crafting.ShapelessRecipes; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.DimensionType; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.terraingen.DecorateBiomeEvent; import net.minecraftforge.event.terraingen.InitMapGenEvent.EventType; import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.Mod.Instance; import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; import com.flansmod.apocalypse.common.blocks.BlockPowerCube; import com.flansmod.apocalypse.common.blocks.BlockStatic; import com.flansmod.apocalypse.common.blocks.BlockSulphur; import com.flansmod.apocalypse.common.blocks.BlockSulphuricAcid; import com.flansmod.apocalypse.common.blocks.TileEntityPowerCube; import com.flansmod.apocalypse.common.entity.EntityAIMecha; import com.flansmod.apocalypse.common.entity.EntitySkullDrone; import com.flansmod.apocalypse.common.entity.EntityFakePlayer; import com.flansmod.apocalypse.common.entity.EntityFlyByPlane; import com.flansmod.apocalypse.common.entity.EntityNukeDrop; import com.flansmod.apocalypse.common.entity.EntitySkullBoss; import com.flansmod.apocalypse.common.entity.EntitySurvivor; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.apocalypse.common.world.BiomeApocalypse; import com.flansmod.apocalypse.common.world.WorldProviderApocalypse; import com.flansmod.apocalypse.common.world.buildings.WorldGenAbandonedPortal; import com.flansmod.apocalypse.common.world.buildings.WorldGenBossPillar; import com.flansmod.common.BlockItemHolder; import com.flansmod.common.CreativeTabFlan; import com.flansmod.common.FlansMod; import com.flansmod.common.IFlansModContentProvider; import com.flansmod.common.ItemHolderType; import com.flansmod.common.enchantments.GloveType; import com.flansmod.common.enchantments.ItemGlove; import com.flansmod.common.parts.PartType; @Mod(modid = FlansModApocalypse.MODID, name = "Flan's Mod: Apocalypse", version = FlansModApocalypse.VERSION, acceptableRemoteVersions = "@ALLOWED_VERSIONS_APOCALYPSE@", dependencies = "required-after:" + FlansMod.MODID) //, guiFactory = "com.flansmod.client.gui.config.ModGuiFactory") public class FlansModApocalypse implements IFlansModContentProvider { //Core mod stuff public static boolean DEBUG = false; public static final String MODID = "flansmodapocalypse"; public static final String VERSION = "@VERSION_APOCALYPSE@"; @Instance(MODID) public static FlansModApocalypse INSTANCE; @SidedProxy(clientSide = "com.flansmod.apocalypse.client.ClientProxyApocalypse", serverSide = "com.flansmod.apocalypse.common.CommonProxyApocalypse") public static CommonProxyApocalypse proxy; //Config options public static Configuration configFile; /** * The time it takes between an AI chip being activated and the apocalypse happening (in ticks) */ public static int apocalypseCountdownLength = 469; public static int SURVIVOR_RARITY = 250; public static int WANDERING_SURVIVOR_RARITY = 500; public static int SKELETON_RARITY = 50; public static int DEAD_TREE_RARITY = 100; public static int VEHICLE_RARITY = 2000; public static int AIRPORT_RARITY = 125; public static int DYE_FACTORY_RARITY = 400; public static int LAB_RARITY = 100; // TODO: Configify public static int ABANDONED_PORTAL_APOC_RARITY = 4000; public static int ABANDONED_PORTAL_OVERWORLD_RARITY = 4000; /** * The distance between where the player left the overworld, and where they return */ public static int RETURN_RADIUS = 100; /** * How far from their death point does the player respawn? */ public static int SPAWN_RADIUS = 100; public static boolean RESPAWN_IN_APOC = false; /** * Who gets teleported to the apocalypse when a player places a mecha? */ public static TeleportOption OPTION = TeleportOption.PLACER_ONLY; public static int dimensionID; public static DimensionType APOCALYPSE_DIM = null; public static FlansModLootGenerator lootGenerator; //Custom apoclypse defined items and blocks public static Item sulphur; public static Block blockSulphur; public static Fluid sulphuricAcid; public static Block blockSulphuricAcid; public static ResourceLocation sulphuricAcidStill = new ResourceLocation("flansmodapocalypse", "blocks/sulphuricAcidStill"), sulphuricAcidFlowing = new ResourceLocation("flansmodapocalypse", "blocks/sulphuricAcidFlowing"); public static Block blockLabStone; public static Block blockPowerCube; public static Item itemBlockPowerCube, itemBlockLabStone, itemBlockSulphur; public static CreativeTabFlan tabApocalypse = new CreativeTabFlan(5); //References to apocalypse specific items and blocks: public static BlockItemHolder skeleton, slumpedSkeleton, gunRack; public static ItemGlove nukraniumGauntlet; static { FluidRegistry.enableUniversalBucket(); } @SubscribeEvent public void registerItems(RegistryEvent.Register event) { event.getRegistry().register(sulphur); event.getRegistry().register(itemBlockLabStone); event.getRegistry().register(itemBlockSulphur); event.getRegistry().register(itemBlockPowerCube); } @SubscribeEvent public void registerBlocks(RegistryEvent.Register event) { event.getRegistry().register(blockSulphur); event.getRegistry().register(blockSulphuricAcid); event.getRegistry().register(blockLabStone); event.getRegistry().register(blockPowerCube); } @SubscribeEvent public void registerBiomes(RegistryEvent.Register event) { BiomeApocalypse.registerBiomes(); event.getRegistry().register(BiomeApocalypse.deepCanyon); event.getRegistry().register(BiomeApocalypse.canyon); event.getRegistry().register(BiomeApocalypse.desert); event.getRegistry().register(BiomeApocalypse.plateau); event.getRegistry().register(BiomeApocalypse.highPlateau); event.getRegistry().register(BiomeApocalypse.sulphurPits); } @SubscribeEvent public void registerRecipes(RegistryEvent.Register event) { NonNullList ingredients = NonNullList.create(); ingredients.add(Ingredient.fromItem(ItemBlock.getItemFromBlock(Blocks.SAND))); ingredients.add(Ingredient.fromStacks(new ItemStack(sulphur))); event.getRegistry().register(new ShapelessRecipes("FlansModApocalypse", new ItemStack(Items.GUNPOWDER), ingredients).setRegistryName("GunpowderFromSulphur")); ingredients = NonNullList.create(); for(int i = 0; i < 4; i++) ingredients.add(Ingredient.fromItem(ItemBlock.getItemFromBlock((Blocks.OBSIDIAN)))); ingredients.add(Ingredient.fromItem(Items.END_CRYSTAL)); for(int i = 0; i < 4; i++) ingredients.add(Ingredient.fromItem(ItemBlock.getItemFromBlock((Blocks.OBSIDIAN)))); event.getRegistry().register(new ShapedRecipes(MODID, 3, 3, ingredients, new ItemStack(itemBlockPowerCube)).setRegistryName("PowerCubeCrafting")); } @EventHandler public void preInit(FMLPreInitializationEvent event) { MinecraftForge.EVENT_BUS.register(this); //Load config configFile = new Configuration(event.getSuggestedConfigurationFile()); syncConfig(); //Custom apoclypse defined items and blocks //Sulphur block and item // TODO: [1.12] .setStepSound(Block.soundTypeSand) blockSulphur = new BlockSulphur().setTranslationKey("blocksulphur").setRegistryName("blocksulphur").setCreativeTab(tabApocalypse); sulphur = new Item().setTranslationKey("flansulphur").setRegistryName("flansulphur").setCreativeTab(tabApocalypse); itemBlockSulphur = new ItemBlock(blockSulphur).setTranslationKey("blocksulphur").setRegistryName("blocksulphur").setCreativeTab(tabApocalypse); //Sulphuric acid sulphuricAcid = new Fluid("sulphuricacid", sulphuricAcidStill, sulphuricAcidFlowing).setTemperature(300).setViscosity(800); if(FluidRegistry.registerFluid(sulphuricAcid)) { blockSulphuricAcid = new BlockSulphuricAcid(sulphuricAcid, Material.WATER).setTranslationKey("blocksulphuricacid").setRegistryName("blocksulphuricacid").setCreativeTab(tabApocalypse); sulphuricAcid.setBlock(blockSulphuricAcid); sulphuricAcid.setUnlocalizedName(blockSulphuricAcid.getTranslationKey()); FluidRegistry.addBucketForFluid(sulphuricAcid); } else { sulphuricAcid = FluidRegistry.getFluid("sulphuricacid"); blockSulphuricAcid = sulphuricAcid.getBlock(); } //Laboratory Stone blockLabStone = new BlockStatic(Material.ROCK).setHardness(3F).setResistance(5F).setTranslationKey("blocklabstone").setRegistryName("blocklabstone").setCreativeTab(tabApocalypse); itemBlockLabStone = new ItemBlock(blockLabStone).setTranslationKey("blocklabstone").setRegistryName("blocklabstone").setCreativeTab(tabApocalypse); //Power Cube blockPowerCube = new BlockPowerCube(Material.CIRCUITS).setTranslationKey("blockpowercube").setRegistryName("blockpowercube").setHardness(3F).setResistance(5F).setCreativeTab(tabApocalypse); itemBlockPowerCube = new ItemBlock(blockPowerCube).setTranslationKey("blockpowercube").setRegistryName("blockpowercube").setCreativeTab(tabApocalypse); GameRegistry.registerTileEntity(TileEntityPowerCube.class, new ResourceLocation("flansmodapocalypse:powercube")); proxy.preInit(event); } @EventHandler public void init(FMLInitializationEvent event) { proxy.init(event); dimensionID = DimensionManager.getNextFreeDimId(); APOCALYPSE_DIM = DimensionType.register("Apocalypse", "_apocalypse", dimensionID, WorldProviderApocalypse.class, false); DimensionManager.registerDimension(dimensionID, APOCALYPSE_DIM); //Grab references to apocalypse specific items and blocks here: if(ItemHolderType.getItemHolder("flanSkeleton") != null) { skeleton = ItemHolderType.getItemHolder("flanSkeleton").block; skeleton.setCreativeTab(tabApocalypse); } else { FlansMod.log.warn("Could not find skeleton item holder!"); } if(ItemHolderType.getItemHolder("flanSkeleton2") != null) { slumpedSkeleton = ItemHolderType.getItemHolder("flanSkeleton2").block; slumpedSkeleton.setCreativeTab(tabApocalypse); } else { FlansMod.log.warn("Could not find skeleton2 item holder!"); } if(ItemHolderType.getItemHolder("flanGunRack") != null) { gunRack = ItemHolderType.getItemHolder("flanGunRack").block; gunRack.setCreativeTab(tabApocalypse); } else { FlansMod.log.warn("Could not find gun rack item holder!"); } //Put ai chip in apocalypse tab if(PartType.getPart("aiChip") != null) PartType.getPart("aiChip").item.setCreativeTab(tabApocalypse); if(PartType.getPart("complicatedCircuit") != null) PartType.getPart("complicatedCircuit").item.setCreativeTab(tabApocalypse); if(PartType.getPart("nuclearPowerCore") != null) PartType.getPart("nuclearPowerCore").item.setCreativeTab(tabApocalypse); if(GloveType.getGlove("nukranium_gauntlet") != null) { nukraniumGauntlet = (ItemGlove)GloveType.getGlove("nukranium_gauntlet").item; } lootGenerator = new FlansModLootGenerator(); } @EventHandler public void postInit(FMLPostInitializationEvent event) { proxy.postInit(event); } private WorldGenAbandonedPortal portalGen = new WorldGenAbandonedPortal(); @SubscribeEvent public void populateOverworldChunk(PopulateChunkEvent event) { if(event.getRand().nextInt(FlansModApocalypse.ABANDONED_PORTAL_OVERWORLD_RARITY) == 0) { int i = event.getChunkX() * 16 + 8; int j = event.getChunkZ() * 16 + 8; int height = event.getWorld().getHeight(i, j); portalGen.generate(event.getWorld(), event.getRand(), new BlockPos(i, height, j)); } } @SubscribeEvent public void registerEntities(RegistryEvent.Register event) { event.getRegistry().register(new EntityEntry(EntitySurvivor.class, "Survivor").setRegistryName("Survivor")); event.getRegistry().register(new EntityEntry(EntityTeleporter.class, "Teleporter").setRegistryName("Teleporter")); event.getRegistry().register(new EntityEntry(EntityAIMecha.class, "AIMecha").setRegistryName("AIMecha")); event.getRegistry().register(new EntityEntry(EntityFakePlayer.class, "FakePlayer").setRegistryName("FakePlayer")); event.getRegistry().register(new EntityEntry(EntityNukeDrop.class, "NukeDrop").setRegistryName("NukeDrop")); event.getRegistry().register(new EntityEntry(EntityFlyByPlane.class, "FlyByPlane").setRegistryName("FlyByPlane")); event.getRegistry().register(new EntityEntry(EntitySkullBoss.class, "SkullBoss").setRegistryName("SkullBoss")); event.getRegistry().register(new EntityEntry(EntitySkullDrone.class, "AutoDrone").setRegistryName("AutoDrone")); //EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:Survivor"), EntitySurvivor.class, "Survivor", 112, FlansModApocalypse.INSTANCE, 100, 20, true, 0, 0); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:Teleporter"), EntityTeleporter.class, "Teleporter", 113, FlansModApocalypse.INSTANCE, 100, 20, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:AIMecha"), EntityAIMecha.class, "AIMecha", 114, FlansModApocalypse.INSTANCE, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:FakePlayer"), EntityFakePlayer.class, "FakePlayer", 115, FlansModApocalypse.INSTANCE, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:NukeDrop"), EntityNukeDrop.class, "NukeDrop", 116, FlansModApocalypse.INSTANCE, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:FlyByPlane"), EntityFlyByPlane.class, "FlyByPlane", 117, FlansModApocalypse.INSTANCE, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:SkullBoss"), EntitySkullBoss.class, "SkullBoss", 118, FlansModApocalypse.INSTANCE, 500, 5, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmodapocalypse:AutoDrone"), EntitySkullDrone.class, "AutoDrone", 119, FlansModApocalypse.INSTANCE, 500, 5, true); } public static FlansModLootGenerator getLootGenerator() { return lootGenerator; } public static void syncConfig() { apocalypseCountdownLength = configFile.getInt("Apocalypse Countdown Length", Configuration.CATEGORY_GENERAL, apocalypseCountdownLength, 19, Integer.MAX_VALUE, "Time between placing an AI mecha and going to the apocalypse"); SURVIVOR_RARITY = configFile.getInt("Survivor Rarity", Configuration.CATEGORY_GENERAL, SURVIVOR_RARITY, 1, Integer.MAX_VALUE, "Rarity of survivor entities spawned during world creation"); WANDERING_SURVIVOR_RARITY = configFile.getInt("Wandering Survivor Rarity", Configuration.CATEGORY_GENERAL, WANDERING_SURVIVOR_RARITY, 1, Integer.MAX_VALUE, "Rarity of survivor entities spawned at night"); SKELETON_RARITY = configFile.getInt("Skeleton Rarity", Configuration.CATEGORY_GENERAL, SKELETON_RARITY, 1, Integer.MAX_VALUE, "Rarity of buried skeletons"); DEAD_TREE_RARITY = configFile.getInt("Dead Tree Rarity", Configuration.CATEGORY_GENERAL, DEAD_TREE_RARITY, 1, Integer.MAX_VALUE, "Rarity of dead trees"); VEHICLE_RARITY = configFile.getInt("Vehicle Rarity", Configuration.CATEGORY_GENERAL, VEHICLE_RARITY, 1, Integer.MAX_VALUE, "Rarity of broken vehicles"); AIRPORT_RARITY = configFile.getInt("Airport Rarity", Configuration.CATEGORY_GENERAL, AIRPORT_RARITY, 1, Integer.MAX_VALUE, "Rarity of airstrips"); DYE_FACTORY_RARITY = configFile.getInt("Dye Factory Rarity", Configuration.CATEGORY_GENERAL, DYE_FACTORY_RARITY, 1, Integer.MAX_VALUE, "Rarity of dye factories"); LAB_RARITY = configFile.getInt("Lab Rarity", Configuration.CATEGORY_GENERAL, LAB_RARITY, 1, Integer.MAX_VALUE, "Rarity of the research lab"); RETURN_RADIUS = configFile.getInt("Return Radius", Configuration.CATEGORY_GENERAL, RETURN_RADIUS, 1, Integer.MAX_VALUE, "The distance away from your initial AI mecha that your return portal appears"); SPAWN_RADIUS = configFile.getInt("Spawn Radius", Configuration.CATEGORY_GENERAL, SPAWN_RADIUS, 1, Integer.MAX_VALUE, "The distance from your deathpoint that you respawn in the apocalypse"); OPTION = TeleportOption.getOption(configFile.getString("Option", Configuration.CATEGORY_GENERAL, OPTION.toString(), "Who gets teleported to the apocalypse with a player (One of PLACER_ONLY, DIM, DIM_OPT_IN, NEARBY, NEARBY_OPT_IN)")); ABANDONED_PORTAL_APOC_RARITY = configFile.getInt("Abandoned Portal Rarity (Apocalypse)", Configuration.CATEGORY_GENERAL, ABANDONED_PORTAL_APOC_RARITY, 1, Integer.MAX_VALUE, "Rarity of the abandoned portal structures in the apocalypse"); ABANDONED_PORTAL_OVERWORLD_RARITY = configFile.getInt("Abandoned Portal Rarity (Other Dimensions)", Configuration.CATEGORY_GENERAL, ABANDONED_PORTAL_OVERWORLD_RARITY, 1, Integer.MAX_VALUE, "Rarity of the abandoned portal structures in other dimensions"); RESPAWN_IN_APOC = configFile.getBoolean("Respawn in Apocalypse", Configuration.CATEGORY_GENERAL, RESPAWN_IN_APOC, "If false, players will return to their overworld spawn point"); if(configFile.hasChanged()) configFile.save(); } public enum TeleportOption { PLACER_ONLY, DIM, DIM_OPT_IN, NEARBY, NEARBY_OPT_IN; public static TeleportOption getOption(String s) { if(s.equals("PLACER_ONLY")) return PLACER_ONLY; else if(s.equals("DIM")) return DIM; else if(s.equals("DIM_OPT_IN")) return DIM_OPT_IN; else if(s.equals("NEARBY")) return NEARBY; else if(s.equals("NEARBY_OPT_IN")) return NEARBY_OPT_IN; return PLACER_ONLY; } } @Override public String GetContentFolder() { return "Apocalypse"; } @Override public void RegisterModelRedirects() { FlansMod.RegisterModelRedirect("apocalypse", "com.flansmod.apocalypse.client.model"); } // Boss fight server control private static final int kBossWarmupTicks = 200; private static int sElapsedTicks = 0; private static boolean sBossFightInProgress = false; private static EntitySkullBoss sTheBoss = null; public void TriggerBossFight(World world, EntityLivingBase placer) { sElapsedTicks = 0; if(world.isRemote) { return; } sTheBoss = new EntitySkullBoss(world); sTheBoss.setPosition(0d, WorldGenBossPillar.kBossSpawnHeight, 0d); sTheBoss.SetTarget(placer); world.spawnEntity(sTheBoss); } public void UpdateBossFight(World world) { sElapsedTicks++; if(sElapsedTicks >= kBossWarmupTicks) { } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/FlansModLootGenerator.java ================================================ package com.flansmod.apocalypse.common; import java.util.ArrayList; import java.util.List; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagInt; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionType; import net.minecraft.potion.PotionUtils; import net.minecraft.tileentity.TileEntityBrewingStand; import net.minecraft.tileentity.TileEntityChest; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidUtil; import com.flansmod.common.TileEntityItemHolder; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EnumPlaneMode; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.VehicleType; import com.flansmod.common.driveables.mechas.MechaItemType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.parts.EnumPartCategory; import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.teams.ArmourType; import com.flansmod.common.teams.PlayerClass; import com.flansmod.common.teams.Team; import com.flansmod.common.tools.ToolType; import com.flansmod.common.types.EnumType; public class FlansModLootGenerator { private static ArrayList tanks, cars; private static ArrayList planes, helicopters; private static ArrayList mechas, dungeonMechas; private static ArrayList vehicleEngines, planeEngines, mechaEngines; private static ArrayList validGuns; private static int[] potions = new int[]{8193, 8194, 8195, 8197, 8198, 8201, 8203, 8205, 8206}; public FlansModLootGenerator() { tanks = new ArrayList<>(); cars = new ArrayList<>(); planes = new ArrayList<>(); helicopters = new ArrayList<>(); mechas = new ArrayList<>(); dungeonMechas = new ArrayList<>(); for(DriveableType type : DriveableType.types) { if(type instanceof VehicleType) { if(((VehicleType)type).tank) tanks.add((VehicleType)type); else if(!type.floatOnWater) cars.add((VehicleType)type); } else if(type instanceof PlaneType) { if(((PlaneType)type).mode == EnumPlaneMode.PLANE) planes.add((PlaneType)type); else helicopters.add((PlaneType)type); } else if(type instanceof MechaType) { mechas.add((MechaType)type); if(((MechaType)type).height <= 3F) dungeonMechas.add((MechaType)type); } } vehicleEngines = new ArrayList<>(); mechaEngines = new ArrayList<>(); planeEngines = new ArrayList<>(); for(PartType type : PartType.partsByCategory.get(EnumPartCategory.ENGINE)) { if(type.isAIChip) continue; if(type.worksWith.contains(EnumType.plane)) planeEngines.add(type); if(type.worksWith.contains(EnumType.vehicle)) vehicleEngines.add(type); if(type.worksWith.contains(EnumType.mecha)) mechaEngines.add(type); } validGuns = new ArrayList<>(); for(GunType type : GunType.gunList) if(type.dungeonChance != 0) validGuns.add(type); } public ItemStack getRandomLoadedGun(Random rand, boolean explosivesAllowed) { ItemStack stack = getRandomUnloadedGun(rand); GunType gunType = ((ItemGun)stack.getItem()).GetType(); List ammoList = explosivesAllowed ? gunType.ammo : gunType.nonExplosiveAmmo; if(ammoList.size() > 0) { NBTTagList ammoTagsList = new NBTTagList(); for(int i = 0; i < gunType.numAmmoItemsInGun; i++) { NBTTagCompound ammoTag = new NBTTagCompound(); ShootableType ammoType = ammoList.get(rand.nextInt(ammoList.size())); ItemStack ammoStack = new ItemStack(ammoType.item); ammoStack.setItemDamage(rand.nextInt(ammoType.roundsPerItem)); ammoStack.writeToNBT(ammoTag); ammoTagsList.appendTag(ammoTag); } stack.getTagCompound().setTag("ammo", ammoTagsList); } if(gunType.paintjobs.size() > 1) stack.setItemDamage(rand.nextInt(gunType.nonlegendarypaintjobs.size())); return stack; } public ItemStack getRandomUnloadedGun(Random rand) { GunType gun = validGuns.get(rand.nextInt(validGuns.size())); ItemStack stack = new ItemStack(gun.item); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Paint", gun.nonlegendarypaintjobs.get(rand.nextInt(gun.nonlegendarypaintjobs.size())).iconName); stack.setTagCompound(tags); return stack; } public void addRandomLoot(TileEntityItemHolder holder, Random rand, boolean gunsOnly) { //Add a gun, 2/3rds of the time if(gunsOnly || rand.nextInt(3) != 0) holder.setStack(getRandomLoadedGun(rand, true)); else if(rand.nextBoolean()) holder.setStack(getSurvivorJournal(rand)); else if(rand.nextBoolean()) holder.setStack(new ItemStack(Items.ROTTEN_FLESH, 1 + rand.nextInt(3))); } public void fillVillageChest(Random rand, TileEntityChest chest) { int numParts = rand.nextInt(6) + 1; int numAmmo = rand.nextInt(6) + 1; int numFuel = rand.nextInt(3); int numFood = rand.nextInt(3); //Add 1~5 random parts for(int i = 0; i < numParts; i++) { PartType part = PartType.parts.get(rand.nextInt(PartType.parts.size())); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(part.item, 1)); } //Add 1~5 random ammo for(int i = 0; i < numAmmo; i++) { ShootableType type = ShootableType.shootables.get(new ArrayList<>(ShootableType.shootables.keySet()).get(rand.nextInt(ShootableType.shootables.size()))); if(type != null && type.dungeonChance != 0) chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(type.item, 1 + (type.maxStackSize > 1 && rand.nextBoolean() ? 1 : 0))); } //Add 0~2 fuel items ArrayList fuelItems = PartType.partsByCategory.get(EnumPartCategory.FUEL); for(int i = 0; i < numFuel; i++) { PartType fuel = fuelItems.get(rand.nextInt(fuelItems.size())); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(fuel.item, rand.nextInt(Math.min(fuel.stackSize - 1, 2)) + 1)); } //Add 0~2 food items for(int i = 0; i < numFood; i++) { switch(rand.nextInt(4)) { case 0: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.CHICKEN, rand.nextInt(2) + 1)); break; case 1: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.PORKCHOP, rand.nextInt(2) + 1)); break; case 2: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.BEEF, rand.nextInt(2) + 1)); break; case 3: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.BAKED_POTATO, rand.nextInt(3) + 1)); break; } } //Add 0~1 mecha parts if(rand.nextBoolean() && rand.nextBoolean()) { chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(MechaItemType.types.get(rand.nextInt(MechaItemType.types.size())).item)); } //Add 0~1 tools if(rand.nextBoolean()) { chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(ToolType.tools.get(new ArrayList<>(ToolType.tools.keySet()).get(rand.nextInt(ToolType.tools.size()))).item)); } } public PartType getRandomFuel(Random rand) { ArrayList fuelItems = PartType.partsByCategory.get(EnumPartCategory.FUEL); return fuelItems.get(rand.nextInt(fuelItems.size())); } public ItemStack loadAndPaintGun(GunType gun, Random rand) { ItemStack stack = new ItemStack(gun.item); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Paint", gun.nonlegendarypaintjobs.get(rand.nextInt(gun.nonlegendarypaintjobs.size())).iconName); if(gun.ammo.size() > 0) { NBTTagList ammoTagsList = new NBTTagList(); for(int i = 0; i < gun.numAmmoItemsInGun; i++) { NBTTagCompound ammoTag = new NBTTagCompound(); ShootableType ammoType = gun.ammo.get(rand.nextInt(gun.ammo.size())); ItemStack ammoStack = new ItemStack(ammoType.item); ammoStack.setItemDamage(rand.nextInt(ammoType.roundsPerItem)); ammoStack.writeToNBT(ammoTag); ammoTagsList.appendTag(ammoTag); } tags.setTag("ammo", ammoTagsList); } stack.setTagCompound(tags); return stack; } public void dressMeUp(EntityLivingBase entity, Random rand) { if(rand.nextBoolean() && ArmourType.armours.size() > 0) { //Give a completely random piece of armour ArmourType armour = ArmourType.armours.get(rand.nextInt(ArmourType.armours.size())); if(armour != null && armour.type != 2) entity.setItemStackToSlot(EntityEquipmentSlot.values()[armour.type + 2], new ItemStack(armour.item)); } else if(Team.teams.size() > 0) { //Give a random set of armour Team team = Team.teams.get(rand.nextInt(Team.teams.size())); if(team.hat != null) entity.setItemStackToSlot(EntityEquipmentSlot.HEAD, team.hat.copy()); if(team.chest != null) entity.setItemStackToSlot(EntityEquipmentSlot.CHEST, team.chest.copy()); if(team.legs != null) entity.setItemStackToSlot(EntityEquipmentSlot.LEGS, team.legs.copy()); if(team.shoes != null) entity.setItemStackToSlot(EntityEquipmentSlot.FEET, team.shoes.copy()); if(team.classes.size() > 0) { PlayerClass playerClass = team.classes.get(rand.nextInt(team.classes.size())); if(playerClass.hat != null) entity.setItemStackToSlot(EntityEquipmentSlot.HEAD, playerClass.hat.copy()); if(playerClass.chest != null) entity.setItemStackToSlot(EntityEquipmentSlot.CHEST, playerClass.chest.copy()); if(playerClass.legs != null) entity.setItemStackToSlot(EntityEquipmentSlot.LEGS, playerClass.legs.copy()); if(playerClass.shoes != null) entity.setItemStackToSlot(EntityEquipmentSlot.FEET, playerClass.shoes.copy()); } } } public Block getRandomWeaponBox(Random rand) { if(rand.nextInt(4) == 0) { //Get armour box if(ArmourBoxType.boxes.size() > 0) { return ArmourBoxType.boxes.get(new ArrayList<>(ArmourBoxType.boxes.keySet()).get(rand.nextInt(ArmourBoxType.boxes.size()))).block; } } else { //Get weapon box if(GunBoxType.gunBoxMap.size() > 0) { return GunBoxType.gunBoxMap.get(new ArrayList<>(GunBoxType.gunBoxMap.keySet()).get(rand.nextInt(GunBoxType.gunBoxMap.size()))).block; } } return Blocks.AIR; } public DriveableType getRandomDriveable(Random rand) { switch(rand.nextInt(5)) { case 0: if(cars.size() > 0) return cars.get(rand.nextInt(cars.size())); case 1: if(tanks.size() > 0) return tanks.get(rand.nextInt(tanks.size())); case 2: if(planes.size() > 0) return planes.get(rand.nextInt(planes.size())); case 3: if(helicopters.size() > 0) return helicopters.get(rand.nextInt(helicopters.size())); case 4: if(mechas.size() > 0) return mechas.get(rand.nextInt(mechas.size())); } return null; } public PartType getRandomEngine(DriveableType type, Random rand) { switch(EnumType.getFromObject(type)) { case vehicle: return vehicleEngines.size() > 0 ? vehicleEngines.get(rand.nextInt(vehicleEngines.size())) : null; case plane: return planeEngines.size() > 0 ? planeEngines.get(rand.nextInt(planeEngines.size())) : null; case mecha: return mechaEngines.size() > 0 ? mechaEngines.get(rand.nextInt(mechaEngines.size())) : null; default: return null; } } public PlaneType getRandomPlane(Random rand) { if(planes.size() > 0) return planes.get(rand.nextInt(planes.size())); return null; } public void fillBrewingStand(Random rand, TileEntityBrewingStand tileentity) { for(int i = 0; i < 3; i++) if(rand.nextBoolean()) tileentity.setInventorySlotContents(i, new ItemStack(Items.POTIONITEM, 1, potions[rand.nextInt(9)])); } public void fillLiquidLabChest(Random rand, TileEntityChest chest) { int numItems = 3 + rand.nextInt(4); for(int i = 0; i < numItems; i++) { switch(rand.nextInt(10)) { case 0: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.BOWL, rand.nextInt(5) + 1)); break; case 1: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.WATER_BUCKET)); break; case 2: List fluids = new ArrayList(); fluids.addAll(FluidRegistry.getBucketFluids()); if(fluids.size() > 0) { Fluid fluid = fluids.get(rand.nextInt(fluids.size())); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), FluidUtil.getFilledBucket(new FluidStack(fluid, Fluid.BUCKET_VOLUME))); } break; case 3: case 4: case 5: case 6: ItemStack stack = new ItemStack(Items.POTIONITEM); stack = PotionUtils.addPotionToItemStack(stack, PotionType.getPotionTypeForName("minecraft:strength")); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), stack); break; case 7: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(FlansModApocalypse.sulphur, rand.nextInt(12) + 1)); break; case 8: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), getScientistJournal(rand)); break; case 9: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), getScientistJournal(rand)); break; } } } public void fillWeaponChest(Random rand, TileEntityChest chest) { for(int i = 0; i < 3 + rand.nextInt(3); i++) { ItemStack stack = getRandomAmmo(rand); if(stack != null) { chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), stack); } } for(int i = 0; i < 1 + rand.nextInt(1); i++) { ItemStack stack = getRandomAttachment(rand); if(stack != null) { chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), stack); } } } private ItemStack getRandomAmmo(Random rand) { GunType randomGun = validGuns.get(rand.nextInt(validGuns.size())); if(randomGun.ammo.size() <= 0) return null; ShootableType randomBullet = randomGun.ammo.get(rand.nextInt(randomGun.ammo.size())); return new ItemStack(randomBullet.item); } private ItemStack getRandomAttachment(Random rand) { AttachmentType type = AttachmentType.attachments.get(rand.nextInt(AttachmentType.attachments.size())); return new ItemStack(type.item); } public MechaType getRandomDungeonMecha(Random rand) { if(dungeonMechas.size() > 0) return dungeonMechas.get(rand.nextInt(dungeonMechas.size())); return null; } public void fillDyeFactoryChest(TileEntityChest chest, Random rand) { int numDyes = rand.nextInt(4); int numMisc = rand.nextInt(2); for(int i = 0; i < numDyes; i++) { chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.DYE, rand.nextInt(8) + 1, rand.nextInt(16))); } for(int i = 0; i < numMisc; i++) { switch(rand.nextInt(4)) { case 0: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.STRING, rand.nextInt(5) + 1)); break; case 1: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.FEATHER, rand.nextInt(5) + 1)); break; case 2: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.LEATHER, rand.nextInt(8) + 1)); break; case 3: chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Items.CLAY_BALL, rand.nextInt(32) + 1)); break; } } } public ItemStack getScientistJournal(Random rand) { ItemStack stack = new ItemStack(Items.WRITTEN_BOOK); //Give the book an author stack.setTagInfo("author", new NBTTagString("Dr. Brazier")); NBTTagList pages = new NBTTagList(); //Write in a random journal entry switch(rand.nextInt(8)) { case 0: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 1")); pages.appendTag(new NBTTagString("We are trying to find ways to disable the AI mechas. Unfortunately, this involves bringing specimens into our lab for testing. I protested to management, but they wouldn't listen, as ever. This will be the death of us, I know it.")); break; case 1: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 2")); pages.appendTag(new NBTTagString("The Mechas are almost... evolving... We try something new (today it was EMPs), boot them back up for another test and they've become resistant. Just like that. And I fear that the mechas we have here may be contacting others on the outside.")); break; case 2: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 3")); pages.appendTag(new NBTTagString("I lose hope with every passing day. There is no clever way to destroy these Mechas or shut them down. Their programming forms a vast, global, interconnected web. You shut down one and already every other Mecha knows what you did and how to become immune to it")); break; case 3: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 4")); pages.appendTag(new NBTTagString("Finally, we are looking into other approaches, though I must say, I am quite surprised. Management must have gone a bit mad, they've got us looking for a way to travel back in time... back in time! To destroy the first AI Mecha! How absurd!")); break; case 4: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 5")); pages.appendTag(new NBTTagString("The time travel research is slow, but having heard some of the ideas from the others, I think we may actually have a shot. Not that this helps, though. I've been trying to explain stable time loops to management, but they either don't understand, or are just too desperate.")); break; case 5: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 6")); pages.appendTag(new NBTTagString("We actually did it! I cannot believe it, but we sent someone back in time! Admittedly, they ended up walking with Creepersauruses, but nonetheless, we did it!")); break; case 6: stack.setTagInfo("title", new NBTTagString("Research Journal: Entry 7")); pages.appendTag(new NBTTagString("They're here! The mechas are here! If you read this, please, go back in time, destroy the creator, stop th...")); break; case 7: stack.setTagInfo("title", new NBTTagString("Time Portal: Instruction Manual")); pages.appendTag(new NBTTagString("The Time Portal uses the portal properties of obsidian combined with our state-of-the-art power cubes. Place one in each corner of the obsidian grid to activate the portal.")); break; } stack.setTagInfo("pages", pages); return stack; } public ItemStack getSurvivorJournal(Random rand) { ItemStack stack = new ItemStack(Items.WRITTEN_BOOK); //Give the book an author switch(rand.nextInt(1)) { case 0: stack.setTagInfo("author", new NBTTagString("Flan")); break; } NBTTagList pages = new NBTTagList(); //Write in a random journal entry switch(rand.nextInt(8)) { case 0: stack.setTagInfo("title", new NBTTagString("Help me!")); pages.appendTag(new NBTTagString("\"I have no food. My child has no food. We are going to die. Why did this have to happen?\"")); break; case 1: stack.setTagInfo("title", new NBTTagString("The Endtimes")); pages.appendTag(new NBTTagString("\"It's amazing how fast your world can be torn down around you. Just three days ago, I was happily trading emeralds at the village market. Now all that is gone. I am left to wander this wasteland alone. I don't know how long I'll last, or how long I'll stay sane...\"")); break; case 2: stack.setTagInfo("title", new NBTTagString("Day 5")); pages.appendTag(new NBTTagString("\"We found water today! At the bottom of a village well. We drank and bathed and filled our bottles and left. But for reference, the village was at- *bloodstains*\"")); break; case 3: stack.setTagInfo("title", new NBTTagString("Day 7")); pages.appendTag(new NBTTagString("\"They got my brother! Just after we left the village, he was snatched by some sort of... robot... Also, I think the water may have been contaminated. I've been sweating an awful lot, and it's not just the heat.\"")); break; case 4: stack.setTagInfo("title", new NBTTagString("Day 10")); pages.appendTag(new NBTTagString("\"I have been violently ill, but have not found a new water source yet. I may have to drink more contaminated water to stay alive. I couldn't get worse, could I?\"")); break; case 5: stack.setTagInfo("title", new NBTTagString("The Wasteland")); pages.appendTag(new NBTTagString("\"This world is harsh and unforgiving. I've had to make difficult choices, but they are necessary in order to survive. If I hadn't pulled the trigger, they would have done so instead. I'm sure of it.\"")); break; case 6: stack.setTagInfo("title", new NBTTagString("")); pages.appendTag(new NBTTagString("\"We spotted an airstrip in the distance! We're going to head over there under cover of darkness and see if we can acquire ourselves a plane. Let's get out of this terrible place.\"")); break; case 7: stack.setTagInfo("title", new NBTTagString("Time Portal: Instruction Manual")); stack.setTagInfo("generation", new NBTTagInt(3)); pages.appendTag(new NBTTagString("\"The Time Portal uses the portal properties of obsidian combined with-\"")); pages.appendTag(new NBTTagString("\"Beware! The mechas are coming! The time portal is of great importance! You must-\"")); break; } stack.setTagInfo("pages", pages); return stack; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/PropertyFloat.java ================================================ package com.flansmod.apocalypse.common; import net.minecraftforge.common.property.IUnlistedProperty; public class PropertyFloat implements IUnlistedProperty { protected final String name; protected final float minValue, maxValue; public PropertyFloat(String name) { this(name, Float.MAX_VALUE, Float.MIN_VALUE); } public PropertyFloat(String name, float minValue, float maxValue) { this.name = name; this.minValue = minValue; this.maxValue = maxValue; } @Override public String getName() { return name; } @Override public boolean isValid(Float value) { return minValue > maxValue ? true : (value >= minValue && value <= maxValue); } @Override public Class getType() { return Float.class; } @Override public String valueToString(Float value) { return value.toString(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/blocks/BlockPowerCube.java ================================================ package com.flansmod.apocalypse.common.blocks; import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.entity.EntitySkullBoss; import com.flansmod.apocalypse.common.entity.EntityTeleporter; import com.flansmod.apocalypse.common.world.buildings.WorldGenBossPillar; public class BlockPowerCube extends Block implements ITileEntityProvider { public BlockPowerCube(Material material) { super(material); } @Override public TileEntity createNewTileEntity(World worldIn, int meta) { return new TileEntityPowerCube(); } public boolean shouldSideBeRendered(IBlockAccess iblockaccess, int i, int j, int k, int l) { return false; } @Override public boolean canPlaceBlockAt(World world, BlockPos pos) { return world.getBlockState(pos.add(0, -1, 0)).isSideSolid(world, pos.add(0, -1, 0), EnumFacing.UP); } @Override public boolean isOpaqueCube(IBlockState state) { return false; } protected static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D); @Override public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { return AABB; } @Override public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { if((world.provider.getDimension() == FlansModApocalypse.dimensionID || world.provider.getDimension() == 0) && isPortal(world, pos.add(-3 * i, 0, -3 * j))) { world.spawnEntity(new EntityTeleporter(world, pos.add(-3 * i, 0, -3 * j))); } } } final int checkY = MathHelper.floor(WorldGenBossPillar.kPillarMaxHeight + 1); final int checkXZ = MathHelper.floor(WorldGenBossPillar.kPillarInnerEdge + 1); if(world.provider.getDimension() == FlansModApocalypse.dimensionID && world.getBlockState(pos.down()).getBlock() == Blocks.BEDROCK) { if(Math.abs(pos.getX()) == checkXZ && Math.abs(pos.getZ()) == checkXZ) { boolean allPresent = true; for(int i = 0; i < 2; i++) for(int k = 0; k < 2; k++) if(world.getBlockState(new BlockPos(checkXZ * (i == 0 ? 1 : -1), pos.getY(), checkXZ * (k == 0 ? 1 : -1))).getBlock() != this) allPresent = false; if(allPresent) { FlansModApocalypse.INSTANCE.TriggerBossFight(world, placer); for(int i = 0; i < 2; i++) for(int k = 0; k < 2; k++) world.destroyBlock(new BlockPos(checkXZ * (i == 0 ? 1 : -1), pos.getY(), checkXZ * (k == 0 ? 1 : -1)), false); } } } } private boolean isPortal(World world, BlockPos pos) { if(world.getBlockState(pos).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(pos.add(3, 0, 0)).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(pos.add(0, 0, 3)).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(pos.add(3, 0, 3)).getBlock() != FlansModApocalypse.blockPowerCube) return false; for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) if(world.getBlockState(pos.add(i * 3, -1, j * 3)).getBlock() != Blocks.OBSIDIAN || world.getBlockState(pos.add(1 + i, -1, 1 + j)).getBlock() != Blocks.OBSIDIAN) return false; return true; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/blocks/BlockStatic.java ================================================ package com.flansmod.apocalypse.common.blocks; import net.minecraft.block.Block; import net.minecraft.block.material.Material; public class BlockStatic extends Block { public BlockStatic(Material material) { super(material); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/blocks/BlockSulphur.java ================================================ package com.flansmod.apocalypse.common.blocks; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import com.flansmod.apocalypse.common.FlansModApocalypse; public class BlockSulphur extends Block { public BlockSulphur() { super(Material.SAND); } @Override public Item getItemDropped(IBlockState state, Random rand, int fortune) { return FlansModApocalypse.sulphur; } @Override public int quantityDropped(Random random) { return random.nextInt(1) + 1; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/blocks/BlockSulphuricAcid.java ================================================ package com.flansmod.apocalypse.common.blocks; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.block.statemap.StateMap; import net.minecraft.entity.Entity; import net.minecraft.util.DamageSource; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.fluids.BlockFluidClassic; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; public class BlockSulphuricAcid extends BlockFluidClassic { public static final DamageSource acidDamage = new DamageSource("sulphuricAcid"); public BlockSulphuricAcid(Fluid fluid, Material material) { super(fluid, material); setCreativeTab(FlansMod.tabFlanParts); } @Override public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity) { entity.attackEntityFrom(acidDamage, 5.0F); } @SideOnly(Side.CLIENT) public void registerRenderer() { ModelLoader.setCustomStateMapper(this, new StateMap.Builder().ignore(LEVEL).build()); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/blocks/TileEntityPowerCube.java ================================================ package com.flansmod.apocalypse.common.blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ITickable; public class TileEntityPowerCube extends TileEntity implements ITickable { public int age; @Override public void update() { age++; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityAIGoSomewhere.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.EntityCreature; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.RandomPositionGenerator; import net.minecraft.util.math.Vec3d; public class EntityAIGoSomewhere extends EntityAIBase { private EntityCreature theEntityCreature; protected double speed; private double directionX, directionZ; private double randPosX; private double randPosY; private double randPosZ; private static final String __OBFID = "CL_00001604"; public EntityAIGoSomewhere(EntityCreature creature, double speed, double dirX, double dirZ) { this.theEntityCreature = creature; this.speed = speed; this.directionX = dirX; this.directionZ = dirZ; this.setMutexBits(1); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { { Vec3d Vec3d = RandomPositionGenerator.findRandomTargetBlockTowards(this.theEntityCreature, 5, 4, new Vec3d(theEntityCreature.posX + directionX, theEntityCreature.posY, theEntityCreature.posZ + directionZ)); if(Vec3d == null) { return false; } else { this.randPosX = Vec3d.x; this.randPosY = Vec3d.y; this.randPosZ = Vec3d.z; return true; } } } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { this.theEntityCreature.getNavigator().tryMoveToXYZ(this.randPosX, this.randPosY, this.randPosZ, this.speed); } /** * Returns whether an in-progress EntityAIBase should continue executing */ public boolean continueExecuting() { return !this.theEntityCreature.getNavigator().noPath(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityAIMecha.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.vector.Vector3f; public class EntityAIMecha extends EntityMecha { private Entity target; private float targetingRange = 20F; private int targetAcquireInterval = 40; private boolean usingLeft = false; public EntityAIMecha(World world) { super(world); } public EntityAIMecha(World world, double x, double y, double z, MechaType type, DriveableData data, NBTTagCompound tags) { super(world, x, y, z, type, data, tags); } public void onUpdate() { throttle = 1F; //float lookAheadDist = 20F; //float targetHeight = getBiomeHeight(world.getBiomeGenForCoords(new BlockPos((int)(posX + motionX * lookAheadDist), (int)(posY + motionY * lookAheadDist), (int)(posZ + motionZ * lookAheadDist)))); //float currentTargetHeight = getBiomeHeight(world.getBiomeGenForCoords(new BlockPos((int)(posX), (int)(posY), (int)(posZ)))); //flapsPitchLeft = flapsPitchRight += (Math.max(currentTargetHeight, targetHeight) - (float)posY) * 0.1F; super.onUpdate(); } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) { return false; } @Override protected void moveAI(Vector3f actualMotion) { MechaType type = getMechaType(); DriveableData data = getDriveableData(); //Acquire target if(target == null && (this.ticksExisted + this.getEntityId()) % targetAcquireInterval == 0) { double distToCurrentTarget = 999D; for(Object obj : world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().expand(targetingRange, targetingRange, targetingRange))) { double distToPotentialTarget = this.getDistanceSq((Entity)obj); if(isBetterTarget(target, distToCurrentTarget, (Entity)obj, distToPotentialTarget)) { target = (Entity)obj; distToCurrentTarget = distToPotentialTarget; } } } //And if we have line of sight, shoot it if(!world.isRemote && target != null) { Vec3d rightArmOrigin = usingLeft ? axes.findLocalVectorGlobally(getMechaType().leftArmOrigin).toVec3().add(posX, posY, posZ) : axes.findLocalVectorGlobally(getMechaType().rightArmOrigin).toVec3().add(posX, posY, posZ); Vec3d targetOrigin = new Vec3d(target.posX, target.posY + target.getEyeHeight() / 2D, target.posZ); double dX = targetOrigin.x - rightArmOrigin.x; double dY = targetOrigin.y - rightArmOrigin.y; double dZ = targetOrigin.z - rightArmOrigin.z; axes.setAngles((float)Math.atan2(dZ, dX) * 180F / 3.14159F, 0F, 0F); if(getSeat(0) != null) { getSeat(0).looking.setAngles(0F, -(float)Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180F / 3.14159F, 0F); getSeat(0).prevLooking.setAngles(0F, -(float)Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180F / 3.14159F, 0F); } RayTraceResult hit = world.rayTraceBlocks(rightArmOrigin, targetOrigin, false); if(world.isRemote) { //world.spawnEntity(new EntityDebugVector(world, new Vector3f(rightArmOrigin), new Vector3f(dX, dY, dZ), 2)); } { double blockHitX = hit == null ? 0 : hit.hitVec.x - rightArmOrigin.x; double blockHitY = hit == null ? 0 : hit.hitVec.y - rightArmOrigin.y; double blockHitZ = hit == null ? 0 : hit.hitVec.z - rightArmOrigin.z; //If the target is nearer than the block hit or there was no block if(hit == null || hit.typeOfHit != RayTraceResult.Type.BLOCK || dX * dX + dY * dY + dZ * dZ < blockHitX * blockHitX + blockHitY * blockHitY + blockHitZ * blockHitZ) { useItem(usingLeft); if(rand.nextInt(5) == 0) usingLeft = !usingLeft; } //Otherwise, move closer else { //If we have a target, move towards it and look at it moveX = (float)(target.posX - posX); moveZ = (float)(target.posZ - posZ); float mag = (float)Math.sqrt(moveX * moveX + moveZ * moveZ); Vector3f intent = new Vector3f(moveX, 0, moveZ); if(Math.abs(intent.lengthSquared()) > 0.1) { intent.normalise(); ++legSwing; //intent = axes.findLocalVectorGlobally(intent); Vector3f intentOnLegAxes = legAxes.findGlobalVectorLocally(intent); float intentAngle = (float)Math.atan2(intent.z, intent.x) * 180F / 3.14159265F; float angleBetween = intentAngle - legAxes.getYaw(); if(angleBetween > 180F) angleBetween -= 360F; if(angleBetween < -180F) angleBetween += 360F; float signBetween = Math.signum(angleBetween); angleBetween = Math.abs(angleBetween); if(angleBetween > 0.1) { legAxes.rotateGlobalYaw(Math.min(angleBetween, type.rotateSpeed) * signBetween); } intent.scale((type.moveSpeed * data.engine.engineSpeed * speedMultiplier()) * (4.3F / 20F)); if(isPartIntact(EnumDriveablePart.hips)) { //Move! Vector3f.add(actualMotion, intent, actualMotion); } } } } } } @Override protected boolean creative() { return false; } private boolean isBetterTarget(Entity currentTarget, double distToCurrentTarget, Entity potentialTarget, double distToPotentialTarget) { if(potentialTarget instanceof EntityPlayer && distToPotentialTarget < distToCurrentTarget && distToPotentialTarget < targetingRange * targetingRange) return true; return false; } @Override public boolean hasFuel() { return true; } @Override public boolean hasEnoughFuel() { return true; } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { if(world.isRemote || isDead) return true; MechaType type = getMechaType(); if(damagesource.damageType.equals("player") && damagesource.getTrueSource().onGround && (getSeat(0) == null || getSeat(0).getControllingPassenger() == null)) { return false; } else return super.attackEntityFrom(damagesource, i); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityFakePlayer.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryBasic; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class EntityFakePlayer extends EntityFlansModShooter { private IInventory inventory; public EntityFakePlayer(World world) { super(world); } public EntityFakePlayer(World world, EntityPlayer player) { this(world); setPosition(player.posX, player.posY, player.posZ); //Copy the existing player's inventory inventory = new InventoryBasic("FakePlayer", true, player.inventory.getSizeInventory()); for(int i = 0; i < player.inventory.getSizeInventory(); i++) { inventory.setInventorySlotContents(i, player.inventory.getStackInSlot(i).copy()); } } @Override protected void dropFewItems(boolean b, int i) { if(!world.isRemote) { for(int j = 0; j < inventory.getSizeInventory(); j++) { if(inventory.getStackInSlot(j) != null) world.spawnEntity(new EntityItem(world, posX, posY, posZ, inventory.getStackInSlot(j))); } } } @Override public void readEntityFromNBT(NBTTagCompound tags) { super.readEntityFromNBT(tags); inventory = new InventoryBasic("FakePlayer", true, 40); for(int i = 0; i < 40; i++) { inventory.setInventorySlotContents(i, new ItemStack(tags.getCompoundTag("S" + i))); } } @Override public void writeEntityToNBT(NBTTagCompound tags) { super.writeEntityToNBT(tags); for(int i = 0; i < 40; i++) { NBTTagCompound itemtags = new NBTTagCompound(); if(inventory.getStackInSlot(i) != null) inventory.getStackInSlot(i).writeToNBT(itemtags); tags.setTag("S" + i, itemtags); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityFlansModShooter.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EnumCreatureAttribute; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.IRangedAttackMob; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; import net.minecraft.entity.ai.EntityAIAttackRangedBow; import net.minecraft.entity.ai.EntityAIAvoidEntity; import net.minecraft.entity.ai.EntityAIFleeSun; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAIRestrictSun; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWanderAvoidWater; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.monster.AbstractSkeleton; import net.minecraft.entity.monster.EntityIronGolem; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.passive.EntityWolf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.FireableGun; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.vector.Vector3f; public class EntityFlansModShooter extends AbstractSkeleton { public class EntityAIAttackRangedGun extends EntityAIAttackRangedBow { private EntityFlansModShooter entity; public EntityAIAttackRangedGun(EntityFlansModShooter mob, double moveSpeedAmpIn, int attackCooldownIn, float maxAttackDistanceIn) { super(mob, moveSpeedAmpIn, attackCooldownIn, maxAttackDistanceIn); entity = mob; } @Override protected boolean isBowInMainhand() { return !entity.getHeldItemMainhand().isEmpty() && entity.getHeldItemMainhand().getItem() instanceof ItemGun; } } //private EntityAIAttackRangedBow aiArrowAttack = new EntityAIAttackRangedBow(this, 1.0D, 20, 70.0F); private EntityAIAttackRangedGun shooterShoot; private EntityAIAttackMelee shooterMelee; public ItemStack[] ammoStacks; public float shootDelay = 0; public float minigunSpeed = 0.0F; public int loopedSoundDelay = 0; public boolean reloading = false; public boolean shouldPlayWarmupSound = true; private int soundDelay = 0; public EntityFlansModShooter(World world) { super(world); ammoStacks = new ItemStack[0]; //tasks.addTask(1, new EntityAISwimming(this)); //tasks.addTask(4, new EntityAIWander(this, 1.0D)); //tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); //tasks.addTask(6, new EntityAILookIdle(this)); //targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); //targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true)); //targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityIronGolem.class, true)); if(world != null && !world.isRemote) { // tasks.addTask(4, this.aiArrowAttack); } else { setRenderDistanceWeight(200D); } } protected void initEntityAI() { super.initEntityAI(); this.targetTasks.addTask(4, new EntityAINearestAttackableTarget(this, EntityAnimal.class, true)); this.targetTasks.addTask(5, new EntityAINearestAttackableTarget(this, EntitySkullDrone.class, true)); } @Override public void onUpdate() { super.onUpdate(); if(shootDelay > 0) shootDelay--; } @Override public EnumCreatureAttribute getCreatureAttribute() { return EnumCreatureAttribute.UNDEFINED; } // Hack to prevent skeleton burning. What is the point in AbstractSkeleton if its always undead and weak to sunlight eh? @Override public float getBrightness() { return 0.0F; } @Override protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(80D); this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25D); } @Override public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData data) { data = super.onInitialSpawn(difficulty, data); //this.tasks.addTask(4, this.aiArrowAttack); this.setEquipmentBasedOnDifficulty(difficulty); this.setEnchantmentBasedOnDifficulty(difficulty); this.setCanPickUpLoot(this.rand.nextFloat() < 0.55F * difficulty.getClampedAdditionalDifficulty()); return data; } @Override public void setCombatTask() { if(shooterShoot == null || shooterMelee == null) { shooterShoot = new EntityAIAttackRangedGun(this, 1.0D, 20, 15.0F); shooterMelee = new EntityAIAttackMelee(this, 1.2D, false); } if (this.world != null && !this.world.isRemote) { this.tasks.removeTask(this.shooterMelee); this.tasks.removeTask(this.shooterShoot); ItemStack itemstack = this.getHeldItemMainhand(); if (itemstack.getItem() instanceof ItemGun) { int i = 10; if (this.world.getDifficulty() != EnumDifficulty.HARD) { i = 20; } this.shooterShoot.setAttackCooldown(i); this.tasks.addTask(4, this.shooterShoot); } else { this.tasks.addTask(4, this.shooterMelee); } } } @Override public void attackEntityWithRangedAttack(EntityLivingBase entity, float range) { ItemStack stack = getHeldItemMainhand(); if(stack != null && stack.getItem() instanceof ItemGun) { ItemGun item = (ItemGun)stack.getItem(); GunType type = item.GetType(); boolean shouldShoot = false; switch(type.mode) { case MINIGUN: shouldShoot = minigunSpeed >= type.minigunStartSpeed && shootDelay <= 0; break; case BURST: case FULLAUTO: case SEMIAUTO: shouldShoot = shootDelay <= 0; break; } if(type.useLoopingSounds && loopedSoundDelay <= 0 && minigunSpeed > 0.1F && !reloading) { loopedSoundDelay = shouldPlayWarmupSound ? type.warmupSoundLength : type.loopedSoundLength; PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, shouldPlayWarmupSound ? type.warmupSound : type.loopedSound, false); shouldPlayWarmupSound = false; } if(shouldShoot) { //player.inventory.setInventorySlotContents(player.inventory.currentItem, tryToShoot(itemstack, type, world, player, false)); int damage = 0; //Check all gun's slots for a valid bullet to shoot int bulletID = 0; ItemStack bulletStack = ItemStack.EMPTY.copy(); for(; bulletID < type.numAmmoItemsInGun; bulletID++) { ItemStack checkingStack = item.getBulletItemStack(stack, bulletID); if(checkingStack != null && !checkingStack.isEmpty() && checkingStack.getItemDamage() < checkingStack.getMaxDamage()) { bulletStack = checkingStack; break; } } //If no bullet stack was found, reload if(bulletStack == null || bulletStack.isEmpty()) { if(reload(stack, type, world, this, false, false)) { //Set player shoot delay to be the reload delay //Set both gun delays to avoid reloading two guns at once shootDelay = (int)type.getReloadTime(stack); reloading = true; //Play reload sound if(type.reloadSound != null) PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.reloadSound, true); } } //A bullet stack was found, so try shooting with it else if(bulletStack.getItem() instanceof ItemShootable) { //Shoot shoot(stack, type, world, bulletStack, this, false, entity); //Damage the bullet item damage = bulletStack.getItemDamage() + 1; bulletStack.setItemDamage(damage); //Update the stack in the gun item.setBulletItemStack(stack, bulletStack, bulletID); } switch(type.mode) { case FULLAUTO: case MINIGUN: { shootDelay = type.GetShootDelay(stack); break; } case SEMIAUTO: { shootDelay = 2 * type.GetShootDelay(stack); break; } case BURST: { shootDelay = (damage % 3 == 0 ? 3 * type.GetShootDelay(stack) : type.GetShootDelay(stack)); break; } } } } } /** * Reload method. Called automatically when firing with an empty clip */ public boolean reload(ItemStack gunStack, GunType gunType, World world, Entity entity, boolean creative, boolean forceReload) { ItemGun item = ((ItemGun)gunType.item); //Deployable guns cannot be reloaded in the inventory if(gunType.deployable) return false; //If you cannot reload half way through a clip, reject the player for trying to do so if(forceReload && !gunType.canForceReload) return false; //For playing sounds afterwards boolean reloadedSomething = false; //Check each ammo slot, one at a time for(int i = 0; i < gunType.numAmmoItemsInGun; i++) { //Get the stack in the slot ItemStack bulletStack = item.getBulletItemStack(gunStack, i); //If there is no magazine, if the magazine is empty or if this is a forced reload if(bulletStack == null || bulletStack.isEmpty() || bulletStack.getItemDamage() == bulletStack.getMaxDamage() || forceReload) { //Iterate over all inventory slots and find the magazine / bullet item with the most bullets int bestSlot = -1; int bulletsInBestSlot = 0; for(int j = 0; j < ammoStacks.length; j++) { ItemStack searchingStack = ammoStacks[j]; if(searchingStack != null && searchingStack.getItem() instanceof ItemShootable && gunType.isCorrectAmmo(((ItemShootable)(searchingStack.getItem())).type)) { int bulletsInThisSlot = searchingStack.getMaxDamage() - searchingStack.getItemDamage(); if(bulletsInThisSlot > bulletsInBestSlot) { bestSlot = j; bulletsInBestSlot = bulletsInThisSlot; } } } //If there was a valid non-empty magazine / bullet item somewhere in the inventory, load it if(bestSlot != -1) { ItemStack newBulletStack = ammoStacks[bestSlot]; ShootableType newBulletType = ((ItemShootable)newBulletStack.getItem()).type; //Unload the old magazine (Drop an item if it is required and the player is not in creative mode) if(bulletStack != null && bulletStack.getItem() instanceof ItemShootable && ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload != null && !creative) item.dropItem(world, this, ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload); //Load the new magazine ItemStack stackToLoad = newBulletStack.copy(); stackToLoad.setCount(1); item.setBulletItemStack(gunStack, stackToLoad, i); //Remove the magazine from the inventory if(!creative) newBulletStack.setCount(newBulletStack.getCount() - 1); if(newBulletStack.getCount() <= 0) newBulletStack = null; ammoStacks[bestSlot] = newBulletStack; //Tell the sound player that we reloaded something reloadedSomething = true; } } } return reloadedSomething; } /** * Method for shooting to avoid repeated code */ private void shoot(ItemStack stack, GunType gunType, World world, ItemStack bulletStack, Entity entity, boolean left, EntityLivingBase target) { ShootableType bullet = ((ItemShootable)bulletStack.getItem()).type; // Play a sound if the previous sound has finished if(soundDelay <= 0 && gunType.shootSound != null) { AttachmentType barrel = gunType.getBarrel(stack); boolean silenced = barrel != null && barrel.silencer; //world.playSoundAtEntity(entityplayer, type.shootSound, 10F, type.distortSound ? 1.0F / (world.rand.nextFloat() * 0.4F + 0.8F) : 1.0F); PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gunType.shootSound, gunType.distortSound, silenced); soundDelay = gunType.shootSoundLength; } if(!world.isRemote) { float inaccuracy = 0.5F; // Spawn the bullet entities Vector3f origin = new Vector3f(posX, posY + getEyeHeight(), posZ); Vector3f direction = new Vector3f(target.posX - posX, (target.posY + target.getEyeHeight()) - (posY + getEyeHeight()), target.posZ - posZ).normalise(null); Vector3f.add(direction, new Vector3f(rand.nextFloat() * direction.x * inaccuracy, rand.nextFloat() * direction.y * inaccuracy, rand.nextFloat() * direction.z * inaccuracy), direction); FireableGun fireableGun = new FireableGun(gunType, gunType.getDamage(stack), gunType.getSpread(stack), gunType.getBulletSpeed(stack), gunType.getSpreadPattern(stack)); //Grenades are currently disabled for this entity if (bullet instanceof BulletType) { FiredShot shot = new FiredShot(fireableGun, (BulletType)bullet, this); ShotHandler.fireGun(world, shot, gunType.numBullets*bullet.numBullets, origin, direction); } // Drop item on shooting if bullet requires it if(bullet.dropItemOnShoot != null) ItemGun.dropItem(world, this, bullet.dropItemOnShoot); // Drop item on shooting if gun requires it if(gunType.dropItemOnShoot != null) ItemGun.dropItem(world, this, gunType.dropItemOnShoot); } shootDelay = gunType.GetShootDelay(stack); } @Override protected boolean canDespawn() { return false; } @Override protected boolean isValidLightLevel() { return true; } @Override public boolean getCanSpawnHere() { return this.world.getDifficulty() != EnumDifficulty.PEACEFUL; } @Override public void setSwingingArms(boolean swingingArms) { } @Override protected SoundEvent getStepSound() { return SoundEvents.ENTITY_ZOMBIE_VILLAGER_STEP; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityFlyByPlane.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import com.flansmod.apocalypse.common.world.BiomeApocalypse; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.PlaneType; public class EntityFlyByPlane extends EntityPlane { public EntityFlyByPlane(World world) { super(world); } public EntityFlyByPlane(World world, double x, double y, double z, PlaneType type, DriveableData data) { super(world, x, y, z, type, data); } public void onUpdate() { throttle = 1F; //float lookAheadDist = 20F; //float targetHeight = getBiomeHeight(world.getBiomeGenForCoords(new BlockPos((int)(posX + motionX * lookAheadDist), (int)(posY + motionY * lookAheadDist), (int)(posZ + motionZ * lookAheadDist)))); //float currentTargetHeight = getBiomeHeight(world.getBiomeGenForCoords(new BlockPos((int)(posX), (int)(posY), (int)(posZ)))); //flapsPitchLeft = flapsPitchRight += (Math.max(currentTargetHeight, targetHeight) - (float)posY) * 0.1F; super.onUpdate(); } private float getBiomeHeight(Biome biome) { if(biome == BiomeApocalypse.desert) return 80F; else if(biome == BiomeApocalypse.deepCanyon || biome == BiomeApocalypse.sulphurPits) return 80F; else if(biome == BiomeApocalypse.highPlateau) return 120F; return 128F; } @Override public boolean canThrust() { return true; } @Override public boolean hasFuel() { return true; } @Override public boolean hasEnoughFuel() { return true; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityNukeDrop.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.apocalypse.common.FlansModApocalypse; public class EntityNukeDrop extends Entity { public static final int explosionLength = 500; public int timeSinceExplosion; public EntityNukeDrop(World world) { super(world); if(world.isRemote) { clientInit(); } setSize(1F, 1F); noClip = false; ignoreFrustumCheck = true; } public EntityNukeDrop(World world, double x, double y, double z) { this(world); setPosition(x, y, z); } @SideOnly(Side.CLIENT) private void clientInit() { setRenderDistanceWeight(400D); } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { } @Override protected void writeEntityToNBT(NBTTagCompound tags) { } @Override public void onUpdate() { super.onUpdate(); if(!onGround) { motionY -= 0.01D; move(MoverType.SELF, motionX, motionY, motionZ); } else { timeSinceExplosion++; if(timeSinceExplosion > explosionLength) setDead(); } if(!world.isRemote && FlansModApocalypse.proxy.getApocalypseCountdown() <= 0) setDead(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntitySkullBoss.java ================================================ package com.flansmod.apocalypse.common.entity; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.world.buildings.WorldGenBossPillar; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.EntityDamageSourceFlan; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.network.PacketPlaySound; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.MoverType; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.item.EntityTNTPrimed; import net.minecraft.entity.monster.EntityShulker; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.Vec3d; import net.minecraft.world.BossInfo; import net.minecraft.world.BossInfoServer; import net.minecraft.world.World; public class EntitySkullBoss extends EntityLiving { protected static final DataParameter ACTION = EntityDataManager.createKey(EntitySkullBoss.class, DataSerializers.BYTE); protected static final DataParameter LOOKING_AT_ENTITY = EntityDataManager.createKey(EntitySkullBoss.class, DataSerializers.VARINT); private final BossInfoServer bossInfo = (BossInfoServer)(new BossInfoServer(this.getDisplayName(), BossInfo.Color.WHITE, BossInfo.Overlay.PROGRESS)).setDarkenSky(true); private int timeInCurrentMode = 0; private EnumAction prevAction = EnumAction.IDLE; public enum EnumAction { IDLE, LAUGH, SPAWN_DRONES, SHOOT_TNT, } private static final int kLaughTicks = 80; private static final int kNumLaughs = 6; private static final float kLaughContributionOffset = 1.0f / ((float)kNumLaughs + 1); private static final float kLaughContributionLength = 2.0f * kLaughContributionOffset; // in degrees public float GetSpawnSpin(float partialTicks) { if(GetCurrentAction() == EnumAction.SPAWN_DRONES) { float parametric = (float)(timeInCurrentMode + partialTicks) / (float)kLaughTicks; float smoothstep = parametric * parametric * (3 - 2 * parametric); return smoothstep * 720f; } return 0.0f; } public float GetLaughFactor(float partialTicks) { if(GetCurrentAction() == EnumAction.LAUGH || GetCurrentAction() == EnumAction.SHOOT_TNT) { float result = 0.0f; float parametric = (float)(timeInCurrentMode + partialTicks) / (float)kLaughTicks; for(int i = 0; i < kNumLaughs; i++) { if(kLaughContributionOffset * i <= parametric && parametric <= kLaughContributionOffset * (i + 2)) { result += Math.sin(Math.PI * (parametric - kLaughContributionOffset * i) / kLaughContributionLength); } } return result; } return 0.0f; } public EntitySkullBoss(World worldIn) { super(worldIn); setSize(16F, 16F); experienceValue = 5000; setNoGravity(true); enablePersistence(); setNoAI(true); ignoreFrustumCheck = true; } @Override protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(1024.0D); //this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(10d); //this.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).setBaseValue(10d); } /** * Add the given player to the list of players tracking this entity. For instance, a player may track a boss in * order to view its associated boss bar. */ @Override public void addTrackingPlayer(EntityPlayerMP player) { super.addTrackingPlayer(player); this.bossInfo.addPlayer(player); } /** * Removes the given player from the list of players tracking this entity. See {@link Entity#addTrackingPlayer} for * more information on tracking. */ @Override public void removeTrackingPlayer(EntityPlayerMP player) { super.removeTrackingPlayer(player); this.bossInfo.removePlayer(player); } private void SwitchAction(EnumAction action) { dataManager.set(ACTION, (byte)action.ordinal()); timeInCurrentMode = 0; } public EnumAction GetCurrentAction() { return EnumAction.values()[dataManager.get(ACTION)]; } @Override public void onUpdate() { super.onUpdate(); timeInCurrentMode++; this.fallDistance = 0f; EnumAction currentAction = GetCurrentAction(); if(currentAction != prevAction) { // For clients, we just get a data update, so check here for a change timeInCurrentMode = 0; prevAction = currentAction; } if(!world.isRemote) { float lerpSpeed = 0.1f; float targetYHeight = 180f + (float)Math.sin(ticksExisted / 200f) * 40f; this.motionX -= this.posX * lerpSpeed / 20f; this.motionZ -= this.posZ * lerpSpeed / 20f; this.motionY = (targetYHeight - this.posY) * lerpSpeed / 20f; this.move(MoverType.SELF, motionX, motionY, motionZ); switch(currentAction) { case IDLE: { if(timeInCurrentMode >= 20) // After 1s in idle, choose another mode { switch(rand.nextInt(3)) { case 1: SwitchAction(EnumAction.LAUGH); break; case 2: SwitchAction(EnumAction.SPAWN_DRONES); break; case 0: SwitchAction(EnumAction.SHOOT_TNT); break; default: SwitchAction(EnumAction.SHOOT_TNT); break; } } break; } case LAUGH: { if(timeInCurrentMode == 2) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, "skullboss_laugh", false); } if(timeInCurrentMode % 5 == 0) { world.createExplosion(this, posX + rand.nextGaussian() * 10d, posY + rand.nextGaussian() * 10d, posZ + rand.nextGaussian() * 10d, 10f, false); } if(timeInCurrentMode >= kLaughTicks) { SwitchAction(EnumAction.IDLE); } break; } case SPAWN_DRONES: { if(timeInCurrentMode == 2) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, "skullboss_spawn", false); EntitySkullDrone drone = new EntitySkullDrone(world); drone.setPosition(posX, posY - 5f, posZ); ItemStack loadedGun = FlansModApocalypse.getLootGenerator().getRandomLoadedGun(rand, false); drone.setHeldItem(EnumHand.MAIN_HAND, loadedGun); drone.setInventorySlotContents(0, ((ItemGun)loadedGun.getItem()).getBulletItemStack(loadedGun, 0).copy()); int lookingAtID = dataManager.get(LOOKING_AT_ENTITY); if(lookingAtID != 0) { Entity target = world.getEntityByID(lookingAtID); drone.SetTarget(target); } world.spawnEntity(drone); } if(timeInCurrentMode >= kLaughTicks) { SwitchAction(EnumAction.IDLE); } break; } case SHOOT_TNT: { if(timeInCurrentMode % 20 == 0) { int lookingAtID = dataManager.get(LOOKING_AT_ENTITY); if(lookingAtID != 0) { Entity target = world.getEntityByID(lookingAtID); if(target != null) { EntityTNTPrimed tnt = new EntityTNTPrimed(world); Vec3d dPos = new Vec3d( target.posX - posX, target.posY - posY, target.posX - posX); double distance = dPos.length(); dPos = dPos.normalize(); dPos = dPos.scale(2d); tnt.setNoGravity(true); tnt.setPosition(posX + dPos.x, posY + dPos.y, posZ + dPos.z); tnt.setVelocity( (target.posX - posX) / 40d, (target.posY - posY) / 40d, (target.posZ - posZ) / 40d); world.spawnEntity(tnt); PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, "fire.ignite", true); } } } if(timeInCurrentMode >= kLaughTicks) { SwitchAction(EnumAction.IDLE); } break; } } } int lookingAtID = dataManager.get(LOOKING_AT_ENTITY); if(lookingAtID != 0) { Entity entity = world.getEntityByID(lookingAtID); if(entity == null || entity.isDead) { if(!world.isRemote) dataManager.set(LOOKING_AT_ENTITY, 0); } else if(!world.isRemote) { double dX = entity.posX - posX; double dY = entity.posY - posY; double dZ = entity.posZ - posZ; float targetYaw = (float)(Math.atan2(dZ, dX) * 180d / Math.PI); float targetPitch = (float)(Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180d / Math.PI); float deltaYaw = targetYaw - rotationYaw; float deltaPitch = targetPitch - rotationPitch; while(deltaYaw > 180f) deltaYaw -= 360f; while(deltaYaw < -180f) deltaYaw += 360f; rotationYaw += deltaYaw / 20f; rotationPitch += deltaPitch / 20f; } } this.bossInfo.setPercent(this.getHealth() / this.getMaxHealth()); } public void SetTarget(Entity target) { dataManager.set(LOOKING_AT_ENTITY, target == null ? 0 : target.getEntityId()); } @Override public boolean attackEntityFrom(DamageSource source, float amount) { if(source.isExplosion()) return false; if(source.getTrueSource() instanceof EntitySkullDrone || source instanceof EntityDamageSourceFlan && ((EntityDamageSourceFlan)source).getCausedPlayer() == null) { return false; } // Hard cap because some Flan's Mod configs can get a bit out of hand if(amount > 99f) amount = 99f; switch(world.getWorldInfo().getDifficulty()) { case HARD: amount *= 0.25f; break; case NORMAL: amount *= 0.5f; break; default: case EASY: case PEACEFUL: break; } super.attackEntityFrom(source, amount); if(!world.isRemote) { Entity sourceEntity = source.getTrueSource(); if(sourceEntity != null) dataManager.set(LOOKING_AT_ENTITY, sourceEntity.getEntityId()); } return true; } @Override protected void entityInit() { super.entityInit(); dataManager.register(ACTION, (byte)0); dataManager.register(LOOKING_AT_ENTITY, 0); PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, "skullboss_spawn", true); } @Override public void readEntityFromNBT(NBTTagCompound tags) { super.readEntityFromNBT(tags); dataManager.set(ACTION, tags.getByte("Action")); dataManager.set(LOOKING_AT_ENTITY, tags.getInteger("LookingAt")); } @Override public void writeEntityToNBT(NBTTagCompound tags) { super.writeEntityToNBT(tags); tags.setByte("Action", dataManager.get(ACTION)); tags.setInteger("LookingAt", dataManager.get(LOOKING_AT_ENTITY)); } @Override public void setDead() { super.setDead(); if(!world.isRemote) { dropItem(Items.GOLDEN_APPLE, rand.nextInt(4) + 1); dropItem(Items.TOTEM_OF_UNDYING, 1); // Lots of gunpowder dropItem(Items.GUNPOWDER, rand.nextInt(32) + 1); dropItem(Items.GUNPOWDER, rand.nextInt(32) + 1); dropItem(Items.GUNPOWDER, rand.nextInt(32) + 1); dropItem(FlansMod.gunpowderBlockItem, rand.nextInt(4) + 1); dropItem(FlansMod.gunpowderBlockItem, rand.nextInt(4) + 1); dropItem(FlansMod.gunpowderBlockItem, rand.nextInt(4) + 1); if(FlansModApocalypse.nukraniumGauntlet != null) { ItemStack gauntlet = new ItemStack(FlansModApocalypse.nukraniumGauntlet); // 50% enchanted, 50% clean if(rand.nextBoolean()) { EnchantmentHelper.addRandomEnchantment(world.rand, gauntlet, 50, true); } entityDropItem(gauntlet, 0.0f); } } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntitySkullDrone.java ================================================ package com.flansmod.apocalypse.common.entity; import java.util.Optional; import com.flansmod.client.model.GunAnimations; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.EnumSpreadPattern; import com.flansmod.common.guns.FireableGun; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGrenade; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.vector.Vector3f; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.MoverType; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class EntitySkullDrone extends EntityLiving implements IInventory { protected static final DataParameter LOOKING_AT_ENTITY = EntityDataManager.createKey(EntitySkullDrone.class, DataSerializers.VARINT); private float shootDelay = 0; private int soundDelay = 0; private Vector3f offsetFromTarget = new Vector3f(); @SideOnly(Side.CLIENT) public GunAnimations animations; public EntitySkullDrone(World worldIn) { super(worldIn); setSize(3F, 1F); setNoGravity(true); enablePersistence(); setNoAI(true); experienceValue = 50; if(worldIn.isRemote) initAnimations(); } @SideOnly(Side.CLIENT) private void initAnimations() { animations = new GunAnimations(); } @Override protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(60.0D); } @SideOnly(Side.CLIENT) private void updateClient() { animations.update(); } @Override public void onUpdate() { super.onUpdate(); if(world.isRemote) updateClient(); this.fallDistance = 0f; int entityID = dataManager.get(LOOKING_AT_ENTITY); Entity target = world.getEntityByID(entityID); if(target != null) { if(target.isDead) { SetTarget(null); } else if(rand.nextInt(1200) == 0) { SetTarget(null); } else { double dX = target.posX - posX; double dY = target.posY - posY; double dZ = target.posZ - posZ; if(!world.isRemote) { // Position code if(rand.nextInt(60) == 0) { offsetFromTarget.scale(0.5f); offsetFromTarget.x += rand.nextGaussian() * 10f; offsetFromTarget.z += rand.nextGaussian() * 10f; offsetFromTarget.y = rand.nextFloat() * 5.0f + 5.0f; } this.motionX = ((target.posX + offsetFromTarget.x) - posX) * 0.06f; this.motionY = ((target.posY + offsetFromTarget.y) - posY) * 0.06f; this.motionZ = ((target.posZ + offsetFromTarget.z) - posZ) * 0.06f; this.move(MoverType.SELF, motionX, motionY, motionZ); } // Look at code float targetYaw = (float)(Math.atan2(dZ, dX) * 180d / Math.PI); float targetPitch = (float)(Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180d / Math.PI); float deltaYaw = targetYaw - rotationYaw; float deltaPitch = targetPitch - rotationPitch; while(deltaYaw > 180f) deltaYaw -= 360f; while(deltaYaw < -180f) deltaYaw += 360f; rotationYaw += deltaYaw / 2f; rotationPitch += deltaPitch / 2f; if(!world.isRemote)// && deltaYaw < 1f && deltaPitch < 1f) { shootDelay--; UseGun(); } } } else if(rand.nextInt(1200) == 0) { Entity closestPlayer = world.getClosestPlayer(posX, posY, posZ, 100.0d, false); if(closestPlayer != null) { SetTarget(closestPlayer); } } } private void UseGun() { ItemStack gunStack = getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); if(!gunStack.isEmpty() && gunStack.getItem() instanceof ItemGun) { ItemGun gunItem = (ItemGun)gunStack.getItem(); GunType gunType = gunItem.GetType(); //If we can shoot if(shootDelay <= 0) { //Go through the bullet stacks in the gun and see if any of them are not null int bulletID = 0; ItemStack ammoStackInGun = null; for(; bulletID < gunType.numAmmoItemsInGun; bulletID++) { ItemStack checkingStack = gunItem.getBulletItemStack(gunStack, bulletID); if(checkingStack != null && !checkingStack.isEmpty() && checkingStack.getItemDamage() < checkingStack.getMaxDamage()) { ammoStackInGun = checkingStack; break; } } //If no bullet stack was found, reload if(ammoStackInGun == null || ammoStackInGun.isEmpty()) { gunItem.Reload(gunStack, world, this, this, EnumHand.MAIN_HAND, true, true, true); if(gunType.reloadSound != null) PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gunType.reloadSound, gunType.distortSound); shootDelay = gunType.reloadTime * 3f; } //A bullet stack was found, so try shooting with it else if(ammoStackInGun.getItem() instanceof ItemBullet || ammoStackInGun.getItem() instanceof ItemGrenade) { //Shoot DoShoot(gunStack, gunType, ammoStackInGun, true, true); //Apply animations to 3D modelled guns //TODO this doesn't work if(world.isRemote) animations.doShoot(gunType.getPumpDelay(), gunType.getPumpTime()); //Damage the bullet item ammoStackInGun.setItemDamage(ammoStackInGun.getItemDamage() + 1); //Update the stack in the gun gunItem.setBulletItemStack(gunStack, ammoStackInGun, bulletID); } } } } private void DoShoot(ItemStack stack, GunType gunType, ItemStack bulletStack, boolean creative, boolean left) { int entityID = dataManager.get(LOOKING_AT_ENTITY); Entity target = world.getEntityByID(entityID); ShootableType bulletType = ((ItemShootable)bulletStack.getItem()).type; Vector3f bulletOrigin = new Vector3f(posX, posY - 1f, posZ); Vector3f aimVector = new Vector3f(target.posX - posX, target.posY - (posY - 1f), target.posZ - posZ); if(!world.isRemote) { ShootableType shootableType = ((ItemShootable)bulletStack.getItem()).type; if (shootableType instanceof BulletType) { FireableGun fireableGun = new FireableGun(gunType, gunType.getDamage(stack), gunType.getSpread(stack) * 5f + 10f, gunType.getBulletSpeed(stack), EnumSpreadPattern.circle); FiredShot shot = new FiredShot(fireableGun, (BulletType)shootableType, this, null); ShotHandler.fireGun(world, shot, gunType.numBullets*bulletType.numBullets, bulletOrigin, aimVector); } else if (shootableType instanceof GrenadeType) { double yaw = Math.atan2(aimVector.z, aimVector.x); double pitch = Math.atan2(Math.sqrt(aimVector.z * aimVector.z + aimVector.x * aimVector.x), aimVector.y) - Math.PI/2; Optional ent = Optional.of(this); Optional player = Optional.ofNullable(null); EntityGrenade grenade = new EntityGrenade(world, bulletOrigin, (GrenadeType) shootableType, (float)Math.toDegrees(pitch), (float)Math.toDegrees(yaw + Math.PI*1.5), player, ent); world.spawnEntity(grenade); } } shootDelay = gunType.mode == EnumFireMode.SEMIAUTO ? Math.max(gunType.GetShootDelay(stack), 5) : gunType.GetShootDelay(stack); // Play a sound if the previous sound has finished if(soundDelay <= 0 && gunType.shootSound != null) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gunType.shootSound, gunType.distortSound); soundDelay = gunType.shootSoundLength; } } public void SetTarget(Entity entity) { dataManager.set(LOOKING_AT_ENTITY, entity == null ? 0 : entity.getEntityId()); offsetFromTarget.x += rand.nextGaussian() * 5f; offsetFromTarget.z += rand.nextGaussian() * 5f; offsetFromTarget.y = 10.0f; } @Override public boolean attackEntityFrom(DamageSource source, float amount) { if(source.isExplosion() || source.isFireDamage()) return false; if(source.getTrueSource() instanceof EntitySkullBoss || source.getTrueSource() instanceof EntitySkullDrone) return false; super.attackEntityFrom(source, amount); if(!world.isRemote) { Entity sourceEntity = source.getTrueSource(); if(sourceEntity != null) dataManager.set(LOOKING_AT_ENTITY, sourceEntity.getEntityId()); } return true; } @Override protected void entityInit() { super.entityInit(); dataManager.register(LOOKING_AT_ENTITY, 0); } @Override public void readEntityFromNBT(NBTTagCompound tags) { super.readEntityFromNBT(tags); dataManager.set(LOOKING_AT_ENTITY, tags.getInteger("LookingAt")); bulletStack = new ItemStack( tags.getCompoundTag("BulletStack")); } @Override public void writeEntityToNBT(NBTTagCompound tags) { super.writeEntityToNBT(tags); tags.setInteger("LookingAt", dataManager.get(LOOKING_AT_ENTITY)); tags.setTag("BulletStack", bulletStack.writeToNBT(new NBTTagCompound())); } // IInventory private ItemStack bulletStack = ItemStack.EMPTY; @Override public int getSizeInventory() { return 1; } @Override public boolean isEmpty() { return bulletStack.isEmpty(); } @Override public ItemStack getStackInSlot(int index) { return bulletStack; } @Override public ItemStack decrStackSize(int index, int count) { bulletStack.setCount(bulletStack.getCount() - count); return bulletStack; } @Override public ItemStack removeStackFromSlot(int index) { ItemStack temp = bulletStack; bulletStack = ItemStack.EMPTY; return temp; } @Override public void setInventorySlotContents(int index, ItemStack stack) { bulletStack = stack; } @Override public int getInventoryStackLimit() { return 64; } @Override public void markDirty() {} @Override public boolean isUsableByPlayer(EntityPlayer player) { return false; } @Override public void openInventory(EntityPlayer player) {} @Override public void closeInventory(EntityPlayer player) {} @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return stack.getItem() instanceof ItemShootable; } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { bulletStack = ItemStack.EMPTY; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntitySkuller.java ================================================ package com.flansmod.apocalypse.common.entity; import javax.annotation.Nullable; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.guns.ItemGun; import com.google.common.base.Predicate; import net.minecraft.entity.EntityBodyHelper; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILookIdle; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAIWatchClosest; import net.minecraft.entity.monster.EntityShulker; import net.minecraft.entity.monster.IMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityShulkerBullet; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; public class EntitySkuller extends EntityShulker { public ItemStack gunStack; public ItemStack ammoStack; public EntitySkuller(World worldIn) { super(worldIn); } public void AssignRandomGun() { gunStack = FlansModApocalypse.lootGenerator.getRandomLoadedGun(rand, false); ammoStack = new ItemStack(((ItemGun)gunStack.getItem()).GetType().nonExplosiveAmmo.get(0).item); } protected void initEntityAI() { this.tasks.addTask(1, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); this.tasks.addTask(4, new EntitySkuller.AIAttack()); this.tasks.addTask(7, new EntitySkuller.AIPeek()); this.tasks.addTask(8, new EntityAILookIdle(this)); this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true, new Class[0])); this.targetTasks.addTask(2, new EntitySkuller.AIAttackNearest(this)); this.targetTasks.addTask(3, new EntitySkuller.AIDefenseAttack(this)); } class AIAttack extends EntityAIBase { private int attackTime; public AIAttack() { this.setMutexBits(3); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { EntityLivingBase entitylivingbase = EntitySkuller.this.getAttackTarget(); if (entitylivingbase != null && entitylivingbase.isEntityAlive()) { return EntitySkuller.this.world.getDifficulty() != EnumDifficulty.PEACEFUL; } else { return false; } } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { this.attackTime = 20; EntitySkuller.this.updateArmorModifier(100); } /** * Reset the task's internal state. Called when this task is interrupted by another one */ public void resetTask() { EntitySkuller.this.updateArmorModifier(0); } /** * Keep ticking a continuous task that has already been started */ public void updateTask() { if (EntitySkuller.this.world.getDifficulty() != EnumDifficulty.PEACEFUL) { --this.attackTime; EntityLivingBase entitylivingbase = EntitySkuller.this.getAttackTarget(); EntitySkuller.this.getLookHelper().setLookPositionWithEntity(entitylivingbase, 180.0F, 180.0F); double d0 = EntitySkuller.this.getDistanceSq(entitylivingbase); if (d0 < 400.0D) { if (this.attackTime <= 0) { this.attackTime = 20 + EntitySkuller.this.rand.nextInt(10) * 20 / 2; //EntityShulkerBullet entityshulkerbullet = new EntityShulkerBullet(EntitySkuller.this.world, EntitySkuller.this, entitylivingbase, EntitySkuller.this.getAttachmentFacing().getAxis()); //EntitySkuller.this.world.spawnEntity(entityshulkerbullet); EntitySkuller.this.playSound(SoundEvents.ENTITY_SHULKER_SHOOT, 2.0F, (EntitySkuller.this.rand.nextFloat() - EntitySkuller.this.rand.nextFloat()) * 0.2F + 1.0F); } } else { EntitySkuller.this.setAttackTarget((EntityLivingBase)null); } super.updateTask(); } } } class AIAttackNearest extends EntityAINearestAttackableTarget { public AIAttackNearest(EntityShulker shulker) { super(shulker, EntityPlayer.class, true); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { return EntitySkuller.this.world.getDifficulty() == EnumDifficulty.PEACEFUL ? false : super.shouldExecute(); } protected AxisAlignedBB getTargetableArea(double targetDistance) { EnumFacing enumfacing = ((EntityShulker)this.taskOwner).getAttachmentFacing(); if (enumfacing.getAxis() == EnumFacing.Axis.X) { return this.taskOwner.getEntityBoundingBox().grow(4.0D, targetDistance, targetDistance); } else { return enumfacing.getAxis() == EnumFacing.Axis.Z ? this.taskOwner.getEntityBoundingBox().grow(targetDistance, targetDistance, 4.0D) : this.taskOwner.getEntityBoundingBox().grow(targetDistance, 4.0D, targetDistance); } } } static class AIDefenseAttack extends EntityAINearestAttackableTarget { public AIDefenseAttack(EntityShulker shulker) { super(shulker, EntityLivingBase.class, 10, true, false, new Predicate() { public boolean apply(@Nullable EntityLivingBase p_apply_1_) { return p_apply_1_ instanceof IMob; } }); } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { return this.taskOwner.getTeam() == null ? false : super.shouldExecute(); } protected AxisAlignedBB getTargetableArea(double targetDistance) { EnumFacing enumfacing = ((EntityShulker)this.taskOwner).getAttachmentFacing(); if (enumfacing.getAxis() == EnumFacing.Axis.X) { return this.taskOwner.getEntityBoundingBox().grow(4.0D, targetDistance, targetDistance); } else { return enumfacing.getAxis() == EnumFacing.Axis.Z ? this.taskOwner.getEntityBoundingBox().grow(targetDistance, targetDistance, 4.0D) : this.taskOwner.getEntityBoundingBox().grow(targetDistance, 4.0D, targetDistance); } } } class AIPeek extends EntityAIBase { private int peekTime; private AIPeek() { } /** * Returns whether the EntityAIBase should begin execution. */ public boolean shouldExecute() { return EntitySkuller.this.getAttackTarget() == null && EntitySkuller.this.rand.nextInt(40) == 0; } /** * Returns whether an in-progress EntityAIBase should continue executing */ public boolean shouldContinueExecuting() { return EntitySkuller.this.getAttackTarget() == null && this.peekTime > 0; } /** * Execute a one shot task or start executing a continuous task */ public void startExecuting() { this.peekTime = 20 * (1 + EntitySkuller.this.rand.nextInt(3)); EntitySkuller.this.updateArmorModifier(30); } /** * Reset the task's internal state. Called when this task is interrupted by another one */ public void resetTask() { if (EntitySkuller.this.getAttackTarget() == null) { EntitySkuller.this.updateArmorModifier(0); } } /** * Keep ticking a continuous task that has already been started */ public void updateTask() { --this.peekTime; } } class BodyHelper extends EntityBodyHelper { public BodyHelper(EntityLivingBase theEntity) { super(theEntity); } /** * Update the Head and Body rendenring angles */ public void updateRenderAngles() { } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntitySurvivor.java ================================================ package com.flansmod.apocalypse.common.entity; import java.util.ArrayList; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ShootableType; public class EntitySurvivor extends EntityFlansModShooter { public static ArrayList validGuns; public EntitySurvivor(World world) { super(world); if(!world.isRemote) { if(validGuns == null) initGunList(); //Pick a random gun for this survivor GunType gun = validGuns.get(world.rand.nextInt(validGuns.size())); ItemStack gunStack = FlansModApocalypse.getLootGenerator().loadAndPaintGun(gun, world.rand); this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, gunStack); //Add random armour FlansModApocalypse.getLootGenerator().dressMeUp(this, world.rand); ammoStacks = new ItemStack[5]; int numAmmo = world.rand.nextInt(4) + 2; for(int i = 0; i < numAmmo; i++) { ShootableType type = gun.ammo.get(world.rand.nextInt(gun.ammo.size())); ammoStacks[i] = new ItemStack(type.item); } } //targetTasks.addTask(4, new EntityAINearestAttackableTarget(this, EntityFlansModShooter.class, true)); //tasks.addTask(5, new EntityAIGoSomewhere(this, 1.0D, world.rand.nextDouble() * 10D, world.rand.nextDouble() * 10D)); setCombatTask(); for(int i = 0; i < inventoryArmorDropChances.length; ++i) { inventoryArmorDropChances[i] = 0.5F; } inventoryHandsDropChances[0] = 1F; experienceValue = 20; } /** * Grab the list of guns valid for survivors from the complete gun list */ private void initGunList() { validGuns = new ArrayList<>(); for(GunType gun : GunType.gunList) { if(gun.mode == EnumFireMode.SEMIAUTO && !gun.deployable && gun.ammo.size() > 0 && !gun.shield && gun.usableByPlayers && gun.dungeonChance != 0) validGuns.add(gun); } } protected void dropFewItems(boolean p_70628_1_, int p_70628_2_) { int numFoods = rand.nextInt(5); for(int i = 0; i < numFoods; i++) { switch(rand.nextInt(5)) { case 0: dropItem(Items.COOKED_BEEF, 1); break; case 1: dropItem(Items.BREAD, 1); break; case 2: dropItem(Items.MUSHROOM_STEW, 1); break; case 3: dropItem(Items.COOKED_RABBIT, 1); break; case 4: dropItem(Items.COOKED_CHICKEN, 1); break; } } for(int i = 0; i < 5; i++) { if(ammoStacks[i] != null) { world.spawnEntity(new EntityItem(world, posX, posY, posZ, ammoStacks[i])); } } if(rand.nextInt(5) == 0) dropItem(Item.getItemFromBlock(Blocks.LOG), rand.nextInt(10) + 5); if(rand.nextInt(12) == 0) dropItem(Items.BOOK, 1); if(rand.nextInt(12) == 0) dropItem(Items.FLINT_AND_STEEL, 1); if(rand.nextInt(40) == 0) dropItem(Items.IRON_AXE, 1); if(rand.nextInt(40) == 0) dropItem(Items.IRON_PICKAXE, 1); if(rand.nextInt(40) == 0) dropItem(Items.IRON_SHOVEL, 1); if(rand.nextInt(4) == 0) dropItem(Item.getItemFromBlock(Blocks.TORCH), rand.nextInt(5) + 1); if(rand.nextBoolean()) { world.spawnEntity(new EntityItem(world, posX, posY, posZ, FlansModApocalypse.getLootGenerator().getSurvivorJournal(rand))); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/entity/EntityTeleporter.java ================================================ package com.flansmod.apocalypse.common.entity; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.world.TeleporterApocalypse; public class EntityTeleporter extends Entity { /** * Points to the lower left power cube in the portal frame */ private BlockPos lowerLeftCornerPowerCube; /** * Points to the lower left power cube in the target teleporter */ private BlockPos targetTeleporter; public EntityTeleporter(World world) { super(world); setSize(1F, 1F); } public EntityTeleporter(World world, BlockPos pos) { this(world); this.lowerLeftCornerPowerCube = pos; this.setPosition(pos.getX() + 2D, pos.getY(), pos.getZ() + 2D); } @Override public void onUpdate() { super.onUpdate(); if(lowerLeftCornerPowerCube == null) { lowerLeftCornerPowerCube = new BlockPos(MathHelper.floor(posX - 1.5D), MathHelper.floor(posY + 0.5D), MathHelper.floor(posZ - 1.5D)); } if(!world.isRemote) for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) if(world.getBlockState(lowerLeftCornerPowerCube.add(3 * i, 0, 3 * j)).getBlock() != FlansModApocalypse.blockPowerCube) { setDead(); //if(targetTeleporter != null) // FMLCommonHandler.instance().getMinecraftServerInstance().worldServerForDimension(otherDimension(this.dimension)). } for(int i = 0; i < 10; i++) { double dX = rand.nextGaussian(); double dY = rand.nextGaussian(); double dZ = rand.nextGaussian(); world.spawnParticle(EnumParticleTypes.PORTAL, posX + dX, posY + 1 + dY, posZ + dZ, dX, dY, dZ); } } private int otherDimension(int i) { if(i == 0) return FlansModApocalypse.dimensionID; return 0; } @Override public void onCollideWithPlayer(EntityPlayer player) { if(!world.isRemote) { if(world.getBlockState(lowerLeftCornerPowerCube).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(lowerLeftCornerPowerCube.add(3,0,0)).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(lowerLeftCornerPowerCube.add(3,0,3)).getBlock() != FlansModApocalypse.blockPowerCube || world.getBlockState(lowerLeftCornerPowerCube.add(0,0,3)).getBlock() != FlansModApocalypse.blockPowerCube) { setDead(); return; } if(targetTeleporter == null)// && world.provider.getDimension() == FlansModApocalypse.dimensionID) findPortal(player); if(targetTeleporter != null && player.timeUntilPortal <= 0) { player.timeUntilPortal = 200; //Switch between overworld and apocalypse if(world.provider.getDimension() == 0) { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().transferPlayerToDimension((EntityPlayerMP)player, FlansModApocalypse.dimensionID, new TeleporterApocalypse(FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(FlansModApocalypse.dimensionID), this.targetTeleporter)); } else { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().transferPlayerToDimension((EntityPlayerMP)player, 0, new TeleporterApocalypse(FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(0), this.targetTeleporter)); } } } } private void findPortal(EntityPlayer player) { if(dimension == FlansModApocalypse.dimensionID) { BlockPos entryPoint = FlansModApocalypse.proxy.data.entryPoints.get(player.getPersistentID()); //Find a valid place to enter the world World overworld = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(0); // Map their apoc pos to overworld 1:1 if(entryPoint == null) entryPoint = player.getPosition(); for(int j = 0; j < 300; j++) { double i = overworld.rand.nextDouble() * Math.PI * 2d; double dX = Math.cos(i) * FlansModApocalypse.RETURN_RADIUS; double dZ = Math.sin(i) * FlansModApocalypse.RETURN_RADIUS; BlockPos pos = new BlockPos(entryPoint.getX() + dX, 256, entryPoint.getZ() + dZ); for(; pos.getY() >= 0; pos = pos.down()) { if(overworld.isAirBlock(pos) && overworld.isSideSolid(pos.down(), EnumFacing.UP)) { if(overworld.getWorldBorder().contains(pos) && overworld.getWorldBorder().contains(pos.add(3, 0, 3))) { //We have found a valid position if(createPortal(overworld, pos)) { targetTeleporter = pos; return; } } } } } } else { World apocWorld = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(FlansModApocalypse.dimensionID); for(int j = 0; j < 300; j++) { double i = apocWorld.rand.nextDouble() * Math.PI * 2d; double dX = Math.cos(i) * FlansModApocalypse.RETURN_RADIUS; double dZ = Math.sin(i) * FlansModApocalypse.RETURN_RADIUS; BlockPos pos = new BlockPos(posX + dX, 256, posZ + dZ); for(; pos.getY() >= 0; pos = pos.down()) { if(apocWorld.isAirBlock(pos) && apocWorld.isSideSolid(pos.down(), EnumFacing.UP)) { if(apocWorld.getWorldBorder().contains(pos) && apocWorld.getWorldBorder().contains(pos.add(3, 0, 3))) { //We have found a valid position if(createPortal(apocWorld, pos)) { targetTeleporter = pos; return; } } } } } } } private boolean createPortal(World otherWorld, BlockPos pos) { //If there isn't enough space, reject this spot for(int i = 0; i < 4; i++) { for(int j = 0; j < 3; j++) { for(int k = 0; k < 4; k++) { if(otherWorld.getBlockState(pos.add(i, j, k)).getBlock() != Blocks.AIR) return false; } } } //Create portal for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { otherWorld.setBlockState(pos.add(i * 3, -1, j * 3), Blocks.OBSIDIAN.getDefaultState()); otherWorld.setBlockState(pos.add(i * 3, 0, j * 3), FlansModApocalypse.blockPowerCube.getDefaultState()); otherWorld.setBlockState(pos.add(1 + i, -1, 1 + j), Blocks.OBSIDIAN.getDefaultState()); } } //Create obsidian base pillar to avoid floating portals for(int i = 0; i < 4; i++) { for(int k = 0; k < 4; k++) { for(int j = -1; j >= 1 && otherWorld.getBlockState(pos.add(i, j, k)).getBlock() == Blocks.AIR; j--) { otherWorld.setBlockState(pos.add(i, j, k), Blocks.OBSIDIAN.getDefaultState()); } } } EntityTeleporter teleporter = new EntityTeleporter(otherWorld, pos); teleporter.targetTeleporter = new BlockPos(lowerLeftCornerPowerCube); otherWorld.spawnEntity(teleporter); return true; } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { lowerLeftCornerPowerCube = new BlockPos(tags.getInteger("X"), tags.getInteger("Y"), tags.getInteger("Z")); this.setPosition(lowerLeftCornerPowerCube.getX() + 2D, lowerLeftCornerPowerCube.getY() + 1D, lowerLeftCornerPowerCube.getZ() + 2D); if(tags.hasKey("targetX")) targetTeleporter = new BlockPos(tags.getInteger("targetX"), tags.getInteger("targetY"), tags.getInteger("targetZ")); } @Override protected void writeEntityToNBT(NBTTagCompound tags) { tags.setInteger("X", lowerLeftCornerPowerCube.getX()); tags.setInteger("Y", lowerLeftCornerPowerCube.getY()); tags.setInteger("Z", lowerLeftCornerPowerCube.getZ()); if(targetTeleporter != null) { tags.setInteger("targetX", targetTeleporter.getX()); tags.setInteger("targetY", targetTeleporter.getY()); tags.setInteger("targetZ", targetTeleporter.getZ()); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/items/ItemSulphuricAcidBucket.java ================================================ package com.flansmod.apocalypse.common.items; import net.minecraft.block.Block; import net.minecraft.item.ItemBucket; public class ItemSulphuricAcidBucket extends ItemBucket { public ItemSulphuricAcidBucket(Block containedBlock) { super(containedBlock); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/network/PacketApocalypseCountdown.java ================================================ package com.flansmod.apocalypse.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import com.flansmod.apocalypse.client.ClientProxyApocalypse; import com.flansmod.common.network.PacketBase; public class PacketApocalypseCountdown extends PacketBase { private int timeRemaining; public PacketApocalypseCountdown() { } public PacketApocalypseCountdown(int timeRemaining) { this.timeRemaining = timeRemaining; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(timeRemaining); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { timeRemaining = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { //Should not be received on server } @Override public void handleClientSide(EntityPlayer clientPlayer) { ClientProxyApocalypse.updateApocalypseCountdownTimer(timeRemaining); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/BiomeApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import java.util.Random; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.ChunkPrimer; import net.minecraftforge.common.BiomeManager; import net.minecraftforge.common.BiomeManager.BiomeEntry; import net.minecraftforge.common.BiomeManager.BiomeType; public class BiomeApocalypse extends Biome { public static Biome deepCanyon, canyon, desert, plateau, highPlateau; public static Biome sulphurPits; public static void registerBiomes() { deepCanyon = new BiomeDesertCanyon((new Biome.BiomeProperties("Deep Canyon")).setWaterColor(6316128).setBaseHeight(-1.8F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); canyon = new BiomeDesertCanyon((new Biome.BiomeProperties("Canyon")).setWaterColor(6316128).setBaseHeight(-1F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); desert = new BiomeDesertCanyon((new Biome.BiomeProperties("Desert")).setWaterColor(6316128).setBaseHeight(0F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); plateau = new BiomeDesertCanyon((new Biome.BiomeProperties("Plateau")).setWaterColor(6316128).setBaseHeight(1F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); highPlateau = new BiomeDesertCanyon((new Biome.BiomeProperties("High Plateau")).setWaterColor(6316128).setBaseHeight(2.5F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); sulphurPits = new BiomeSulphurPits((new Biome.BiomeProperties("Sulphur Pits")).setWaterColor(6316128).setBaseHeight(-1.8F).setHeightVariation(0F).setTemperature(2F).setRainfall(0F).setRainDisabled()); deepCanyon.setRegistryName("deepCanyon_apocalypse"); canyon.setRegistryName("canyon_apocalypse"); desert.setRegistryName("desert_apocalypse"); plateau.setRegistryName("plateau_apocalypse"); highPlateau.setRegistryName("highPlateau_apocalypse"); sulphurPits.setRegistryName("sulphurPits_apocalypse"); //addBiomes(deepCanyon, canyon, desert, plateau, highPlateau, sulphurPits); } private static void addBiomes(Biome... biomes) { for(Biome biome : biomes) { BiomeManager.addBiome(BiomeType.DESERT, new BiomeEntry(biome, 1)); BiomeManager.removeSpawnBiome(biome); } } public BiomeApocalypse(Biome.BiomeProperties properties) { super(properties); this.spawnableCreatureList.clear(); topBlock = Blocks.SAND.getStateFromMeta(1); fillerBlock = Blocks.SAND.getStateFromMeta(1); this.decorator.treesPerChunk = -999; this.decorator.deadBushPerChunk = 1; this.decorator.reedsPerChunk = 0; this.decorator.cactiPerChunk = 0; this.decorator = new BiomeDecoratorApocalypse(); } @Override public void genTerrainBlocks(World worldIn, Random p_180622_2_, ChunkPrimer p_180622_3_, int p_180622_4_, int p_180622_5_, double p_180622_6_) { this.generateBiomeTerrainSandy(worldIn, p_180622_2_, p_180622_3_, p_180622_4_, p_180622_5_, p_180622_6_); } public final void generateBiomeTerrainSandy(World world, Random rand, ChunkPrimer primer, int x, int z, double p_180628_6_) { boolean flag = true; IBlockState iblockstate = this.topBlock; IBlockState iblockstate1 = this.fillerBlock; int k = -1; int l = (int)(p_180628_6_ / 3.0D + 3.0D + rand.nextDouble() * 0.25D); int i1 = x & 15; int j1 = z & 15; for(int k1 = 255; k1 >= 0; --k1) { if(k1 <= rand.nextInt(5)) { primer.setBlockState(j1, k1, i1, Blocks.BEDROCK.getDefaultState()); } else { IBlockState iblockstate2 = primer.getBlockState(j1, k1, i1); if(iblockstate2.getMaterial() == Material.AIR) { k = -1; } else if(iblockstate2.getBlock() == Blocks.STONE) { if(k == -1) { if(l <= 0) { iblockstate = null; iblockstate1 = Blocks.STONE.getDefaultState(); } else if(k1 >= 59 && k1 <= 64) { iblockstate = this.topBlock; iblockstate1 = this.fillerBlock; } k = l; if(k1 >= 62) { primer.setBlockState(j1, k1, i1, iblockstate); } //else if (k1 < 56 - l) //{ // iblockstate = null; // iblockstate1 = Blocks.STONE.getDefaultState(); // primer.setBlockState(j1, k1, i1, Blocks.GRAVEL.getDefaultState()); //} else { primer.setBlockState(j1, k1, i1, iblockstate1); } } else if(k > 0) { --k; primer.setBlockState(j1, k1, i1, iblockstate1); /* if (k == 0 && iblockstate1.getBlock() == Blocks.SAND) { k = rand.nextInt(4) + Math.max(0, k1 - 63); iblockstate1 = iblockstate1.getValue(BlockSand.VARIANT) == BlockSand.EnumType.RED_SAND ? Blocks.red_sandstone.getDefaultState() : Blocks.SANDstone.getDefaultState(); } */ } } } } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/BiomeDecoratorApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import java.util.Random; import net.minecraft.block.BlockStone; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeDecorator; import net.minecraft.world.gen.ChunkGeneratorSettings; import net.minecraft.world.gen.feature.WorldGenMinable; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.terraingen.DecorateBiomeEvent; import net.minecraftforge.event.terraingen.OreGenEvent; import net.minecraftforge.event.terraingen.TerrainGen; import com.flansmod.apocalypse.common.FlansModApocalypse; import static net.minecraftforge.event.terraingen.DecorateBiomeEvent.Decorate.EventType.LAKE_WATER; public class BiomeDecoratorApocalypse extends BiomeDecorator { public boolean generateSulphurLakes = false; public void decorate(World worldIn, Random random, Biome biome, BlockPos pos) { if(this.decorating) { throw new RuntimeException("Already decorating"); } else { this.chunkProviderSettings = ChunkGeneratorSettings.Factory.jsonToFactory(worldIn.getWorldInfo().getGeneratorOptions()).build(); this.chunkPos = pos; this.dirtGen = new WorldGenMinable(Blocks.DIRT.getDefaultState(), 8); this.clayGen = new WorldGenMinable(Blocks.CLAY.getDefaultState(), 30); this.gravelGen = new WorldGenMinable(Blocks.GRAVEL.getDefaultState(), 25); this.graniteGen = new WorldGenMinable(Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.GRANITE), this.chunkProviderSettings.graniteSize); this.dioriteGen = new WorldGenMinable(Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.DIORITE), this.chunkProviderSettings.dioriteSize); this.andesiteGen = new WorldGenMinable(Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, BlockStone.EnumType.ANDESITE), this.chunkProviderSettings.andesiteSize); this.coalGen = new WorldGenMinable(Blocks.COAL_ORE.getDefaultState(), 8); this.ironGen = new WorldGenMinable(Blocks.IRON_ORE.getDefaultState(), 25); this.goldGen = new WorldGenMinable(Blocks.GOLD_ORE.getDefaultState(), this.chunkProviderSettings.goldSize); this.redstoneGen = new WorldGenMinable(Blocks.REDSTONE_ORE.getDefaultState(), 16); this.diamondGen = new WorldGenMinable(Blocks.DIAMOND_ORE.getDefaultState(), 8); this.lapisGen = new WorldGenMinable(Blocks.LAPIS_ORE.getDefaultState(), this.chunkProviderSettings.lapisSize); this.genDecorations(biome, worldIn, random); this.decorating = false; } } @Override protected void genDecorations(Biome biome, World currentWorld, Random randomGenerator) { MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Pre(currentWorld, randomGenerator, chunkPos)); //Forge generation hook boolean doGen; int i, j, k; if(this.generateSulphurLakes) { BlockPos blockpos1; doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, LAKE_WATER); for(j = 0; doGen && j < 15; ++j) { blockpos1 = this.chunkPos.add(randomGenerator.nextInt(16) + 8, randomGenerator.nextInt(10) + 30, randomGenerator.nextInt(16) + 8); (new WorldGenSulphurPool(FlansModApocalypse.blockSulphuricAcid)).generate(currentWorld, randomGenerator, blockpos1); } } //Ore generation MinecraftForge.ORE_GEN_BUS.post(new OreGenEvent.Pre(currentWorld, randomGenerator, chunkPos)); //Generic generation //First parameter is the amount of ore veins, second is the generator, third and fourth are min and max height genStandardOre1(currentWorld, randomGenerator, 5, this.dirtGen, 12, 34); genStandardOre1(currentWorld, randomGenerator, 5, this.gravelGen, 36, 64); genStandardOre1(currentWorld, randomGenerator, 2, this.dioriteGen, 60, 100); genStandardOre1(currentWorld, randomGenerator, 2, this.graniteGen, 60, 100); genStandardOre1(currentWorld, randomGenerator, 1, this.andesiteGen, 60, 100); genStandardOre1(currentWorld, randomGenerator, 20, this.ironGen, 5, 128); if(biome == BiomeApocalypse.highPlateau) { genStandardOre1(currentWorld, randomGenerator, 1, this.diamondGen, 95, 128); genStandardOre1(currentWorld, randomGenerator, 1, this.goldGen, 50, 90); genStandardOre2(currentWorld, randomGenerator, 2, this.lapisGen, 70, 32); genStandardOre1(currentWorld, randomGenerator, 10, this.redstoneGen, 30, 60); } else if(biome == BiomeApocalypse.sulphurPits) { genStandardOre1(currentWorld, randomGenerator, 15, this.coalGen, 0, 25); } MinecraftForge.ORE_GEN_BUS.post(new OreGenEvent.Post(currentWorld, randomGenerator, chunkPos)); /* this.generateOres(); int i; int j; int k; boolean doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, SAND); for (i = 0; doGen && i < this.sandPerChunk2; ++i) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; this.sandGen.generate(this.currentWorld, this.randomGenerator, this.currentWorld.getTopSolidOrLiquidBlock(this.chunkPos.add(j, 0, k))); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, CLAY); for (i = 0; doGen && i < this.clayPerChunk; ++i) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; this.clayGen.generate(this.currentWorld, this.randomGenerator, this.currentWorld.getTopSolidOrLiquidBlock(this.chunkPos.add(j, 0, k))); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, SAND_PASS2); for (i = 0; doGen && i < this.sandPerChunk; ++i) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; this.gravelAsSandGen.generate(this.currentWorld, this.randomGenerator, this.currentWorld.getTopSolidOrLiquidBlock(this.chunkPos.add(j, 0, k))); } i = this.treesPerChunk; if (this.randomGenerator.nextInt(10) == 0) { ++i; } int l; BlockPos blockpos; doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, TREE); for (j = 0; doGen && j < i; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; WorldGenAbstractTree worldgenabstracttree = p_150513_1_.genBigTreeChance(this.randomGenerator); worldgenabstracttree.func_175904_e(); blockpos = this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)); if (worldgenabstracttree.generate(this.currentWorld, this.randomGenerator, blockpos)) { worldgenabstracttree.func_180711_a(this.currentWorld, this.randomGenerator, blockpos); } } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, BIG_SHROOM); for (j = 0; doGen && j < this.bigMushroomsPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; this.bigMushroomGen.generate(this.currentWorld, this.randomGenerator, this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l))); } int i1; doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, FLOWERS); for (j = 0; doGen && j < this.flowersPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() + 32); blockpos = this.chunkPos.add(k, i1, l); BlockFlower.EnumFlowerType enumflowertype = p_150513_1_.pickRandomFlower(this.randomGenerator, blockpos); BlockFlower blockflower = enumflowertype.getBlockType().getBlock(); if (blockflower.getMaterial() != Material.air) { this.yellowFlowerGen.setGeneratedBlock(blockflower, enumflowertype); this.yellowFlowerGen.generate(this.currentWorld, this.randomGenerator, blockpos); } } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, GRASS); for (j = 0; doGen && j < this.grassPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); p_150513_1_.getRandomWorldGenForGrass(this.randomGenerator).generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(k, i1, l)); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, DEAD_BUSH); for (j = 0; doGen && j < this.deadBushPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); (new WorldGenDeadBush()).generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(k, i1, l)); } j = 0; doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, LILYPAD); while (doGen && j < this.waterlilyPerChunk) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); blockpos = this.chunkPos.add(k, i1, l); while (true) { if (blockpos.getY() > 0) { BlockPos blockpos3 = blockpos.down(); if (this.currentWorld.isAirBlock(blockpos3)) { blockpos = blockpos3; continue; } } this.waterlilyGen.generate(this.currentWorld, this.randomGenerator, blockpos); ++j; break; } } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, SHROOM); for (j = 0; doGen && j < this.mushroomsPerChunk; ++j) { if (this.randomGenerator.nextInt(4) == 0) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; BlockPos blockpos2 = this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)); this.mushroomBrownGen.generate(this.currentWorld, this.randomGenerator, blockpos2); } if (this.randomGenerator.nextInt(8) == 0) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); blockpos = this.chunkPos.add(k, i1, l); this.mushroomRedGen.generate(this.currentWorld, this.randomGenerator, blockpos); } } if (doGen && this.randomGenerator.nextInt(4) == 0) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; l = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(j, 0, k)).getY() * 2); this.mushroomBrownGen.generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(j, l, k)); } if (doGen && this.randomGenerator.nextInt(8) == 0) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; l = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(j, 0, k)).getY() * 2); this.mushroomRedGen.generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(j, l, k)); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, REED); for (j = 0; doGen && j < this.reedsPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); this.reedGen.generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(k, i1, l)); } for (j = 0; doGen && j < 10; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); this.reedGen.generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(k, i1, l)); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, PUMPKIN); if (doGen && this.randomGenerator.nextInt(32) == 0) { j = this.randomGenerator.nextInt(16) + 8; k = this.randomGenerator.nextInt(16) + 8; l = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(j, 0, k)).getY() * 2); (new WorldGenPumpkin()).generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(j, l, k)); } doGen = TerrainGen.decorate(currentWorld, randomGenerator, chunkPos, CACTUS); for (j = 0; doGen && j < this.cactiPerChunk; ++j) { k = this.randomGenerator.nextInt(16) + 8; l = this.randomGenerator.nextInt(16) + 8; i1 = nextInt(this.currentWorld.getHorizon(this.chunkPos.add(k, 0, l)).getY() * 2); this.cactusGen.generate(this.currentWorld, this.randomGenerator, this.chunkPos.add(k, i1, l)); } */ MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Post(currentWorld, randomGenerator, chunkPos)); } private int nextInt(Random randomGenerator, int i) { //Safety wrapper to prevent exceptions. if(i <= 1) return 0; return randomGenerator.nextInt(i); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/BiomeDesertCanyon.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.init.Blocks; import net.minecraft.world.biome.Biome; public class BiomeDesertCanyon extends BiomeApocalypse { private final int field_150635_aE = 0, field_150636_aF = 1, field_150637_aG = 2; public BiomeDesertCanyon(Biome.BiomeProperties properties) { super(properties); spawnableMonsterList.clear(); //spawnableMonsterList.add(new Biome.SpawnListEntry(EntitySurvivor.class, 1, 1, 1)); spawnableCreatureList.clear(); topBlock = Blocks.SAND.getStateFromMeta(1); fillerBlock = Blocks.SAND.getStateFromMeta(1); } @Override public float getSpawningChance() { return 1F; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/BiomeProviderApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import java.util.ArrayList; import java.util.List; import java.util.Random; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldType; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeCache; import net.minecraft.world.biome.BiomeProvider; import net.minecraft.world.gen.layer.GenLayer; import net.minecraft.world.gen.layer.IntCache; public class BiomeProviderApocalypse extends BiomeProvider { private GenLayer unzoomedBiomes; private GenLayer zoomedBiomes; /** * The biome list. */ private BiomeCache myBiomeCache; private List myBiomesToSpawnIn; public BiomeProviderApocalypse() { this.myBiomeCache = new BiomeCache(this); this.myBiomesToSpawnIn = new ArrayList(); this.myBiomesToSpawnIn.add(BiomeApocalypse.deepCanyon); this.myBiomesToSpawnIn.add(BiomeApocalypse.canyon); this.myBiomesToSpawnIn.add(BiomeApocalypse.desert); this.myBiomesToSpawnIn.add(BiomeApocalypse.plateau); this.myBiomesToSpawnIn.add(BiomeApocalypse.highPlateau); } public BiomeProviderApocalypse(long par1, WorldType worldType) { this(); GenLayer[] agenlayer; /* if (TwilightForestMod.oldMapGen) { agenlayer = GenLayerTF.makeTheWorldOldMapGen(par1); } else { agenlayer = GenLayerTF.makeTheWorld(par1); } */ agenlayer = GenLayerApocalypse.makeTheWorld(par1); this.unzoomedBiomes = agenlayer[0]; this.zoomedBiomes = agenlayer[1]; } public BiomeProviderApocalypse(World world) { this(world.getSeed(), world.getWorldInfo().getTerrainType()); } @Override public List getBiomesToSpawnIn() { return this.myBiomesToSpawnIn; } @Override public Biome getBiome(BlockPos pos) { Biome biome = this.myBiomeCache.getBiome(pos.getX(), pos.getZ(), null); if(biome == null) { return BiomeApocalypse.desert; } return biome; } /* @Override public float[] getRainfall(float[] par1ArrayOfFloat, int par2, int par3, int par4, int par5) { IntCache.resetIntCache(); if ((par1ArrayOfFloat == null) || (par1ArrayOfFloat.length < par4 * par5)) { par1ArrayOfFloat = new float[par4 * par5]; } int[] ai = this.zoomedBiomes.getInts(par2, par3, par4, par5); for (int i = 0; i < par4 * par5; i++) { if ((ai[i] >= 0) && (Biome.getBiome(ai[i]) != null)) { float f = Biome.getBiome(ai[i]).getRainfall() / 65536.0F; if (f > 1.0F) { f = 1.0F; } par1ArrayOfFloat[i] = f; } } return par1ArrayOfFloat; } */ @Override public float getTemperatureAtHeight(float par1, int par2) { return par1; } @Override public Biome[] getBiomesForGeneration(Biome[] par1ArrayOfBiome, int x, int z, int length, int width) { IntCache.resetIntCache(); if((par1ArrayOfBiome == null) || (par1ArrayOfBiome.length < length * width)) { par1ArrayOfBiome = new Biome[length * width]; } int[] arrayOfInts = this.unzoomedBiomes.getInts(x, z, length, width); for(int i = 0; i < length * width; i++) { if(arrayOfInts[i] >= 0) { par1ArrayOfBiome[i] = Biome.getBiome(arrayOfInts[i]); } else { par1ArrayOfBiome[i] = BiomeApocalypse.desert; } } return par1ArrayOfBiome; } @Override public Biome[] getBiomes(Biome[] par1ArrayOfBiome, int x, int y, int width, int length, boolean cacheFlag) { IntCache.resetIntCache(); if((par1ArrayOfBiome == null) || (par1ArrayOfBiome.length < width * length)) { par1ArrayOfBiome = new Biome[width * length]; } if((cacheFlag) && (width == 16) && (length == 16) && ((x & 0xF) == 0) && ((y & 0xF) == 0)) { Biome[] aBiome = this.myBiomeCache.getCachedBiomes(x, y); System.arraycopy(aBiome, 0, par1ArrayOfBiome, 0, width * length); return par1ArrayOfBiome; } int[] ai = this.zoomedBiomes.getInts(x, y, width, length); for(int i = 0; i < width * length; i++) { if(ai[i] >= 0) { par1ArrayOfBiome[i] = Biome.getBiome(ai[i]); } else { par1ArrayOfBiome[i] = BiomeApocalypse.desert; } } return par1ArrayOfBiome; } @Override public boolean areBiomesViable(int par1, int par2, int par3, List biomes) { int i = par1 - par3 >> 2; int j = par2 - par3 >> 2; int k = par1 + par3 >> 2; int l = par2 + par3 >> 2; int i1 = k - i + 1; int j1 = l - j + 1; int[] ai = this.unzoomedBiomes.getInts(i, j, i1, j1); for(int k1 = 0; k1 < i1 * j1; k1++) { Biome biome = Biome.getBiome(ai[k1]); if(!biomes.contains(biome)) { return false; } } return true; } @Override public BlockPos findBiomePosition(int x, int z, int range, List biomes, Random par5Random) { int i = x - range >> 2; int j = z - range >> 2; int k = x + range >> 2; int l = z + range >> 2; int i1 = k - i + 1; int j1 = l - j + 1; int[] ai = this.unzoomedBiomes.getInts(i, j, i1, j1); BlockPos blockpos = null; int k1 = 0; for(int l1 = 0; l1 < ai.length; l1++) { int i2 = i + l1 % i1 << 2; int j2 = j + l1 / i1 << 2; Biome biome = Biome.getBiome(ai[l1]); if((biomes.contains(biome)) && ((blockpos == null) || (par5Random.nextInt(k1 + 1) == 0))) { blockpos = new BlockPos(i2, 0, j2); k1++; } } return blockpos; } @Override public void cleanupCache() { this.myBiomeCache.cleanupCache(); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/BiomeSulphurPits.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.init.Blocks; import net.minecraft.world.biome.Biome; public class BiomeSulphurPits extends BiomeApocalypse { public BiomeSulphurPits(Biome.BiomeProperties properties) { super(properties); spawnableMonsterList.clear(); spawnableCreatureList.clear(); topBlock = Blocks.SAND.getDefaultState(); fillerBlock = Blocks.SAND.getDefaultState(); BiomeDecoratorApocalypse apoc = (BiomeDecoratorApocalypse)decorator; apoc.generateSulphurLakes = true; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/ChunkProviderApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import javax.annotation.Nullable; import java.util.Arrays; import java.util.List; import java.util.Random; import net.minecraft.block.BlockFalling; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EnumCreatureType; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldEntitySpawner; import net.minecraft.world.WorldType; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkPrimer; import net.minecraft.world.gen.IChunkGenerator; import net.minecraft.world.gen.MapGenBase; import net.minecraft.world.gen.MapGenRavine; import net.minecraft.world.gen.NoiseGeneratorOctaves; import net.minecraft.world.gen.NoiseGeneratorPerlin; import net.minecraft.world.gen.feature.WorldGenDungeons; import net.minecraft.world.gen.structure.MapGenMineshaft; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.world.buildings.MapGenAbandonedVillage; import com.flansmod.apocalypse.common.world.buildings.WorldGenAbandonedPortal; import com.flansmod.apocalypse.common.world.buildings.WorldGenBossPillar; import com.flansmod.apocalypse.common.world.buildings.WorldGenDeadTree; import com.flansmod.apocalypse.common.world.buildings.WorldGenDyeFactory; import com.flansmod.apocalypse.common.world.buildings.WorldGenResearchLab; import com.flansmod.apocalypse.common.world.buildings.WorldGenRoads; import com.flansmod.apocalypse.common.world.buildings.WorldGenRunway; import com.flansmod.apocalypse.common.world.buildings.WorldGenSkeleton; import com.flansmod.common.ModuloHelper; public class ChunkProviderApocalypse implements IChunkGenerator { protected static final IBlockState STONE = Blocks.STONE.getDefaultState(); private final Random rand; private NoiseGeneratorOctaves minLimitPerlinNoise; private NoiseGeneratorOctaves maxLimitPerlinNoise; private NoiseGeneratorOctaves mainPerlinNoise; private NoiseGeneratorPerlin surfaceNoise; public NoiseGeneratorOctaves scaleNoise; public NoiseGeneratorOctaves depthNoise; public NoiseGeneratorOctaves forestNoise; private final World world; private final boolean mapFeaturesEnabled; private final WorldType terrainType; private final double[] heightMap; private final float[] biomeWeights; private IBlockState oceanBlock = Blocks.WATER.getDefaultState(); private double[] depthBuffer = new double[256]; private MapGenAbandonedVillage villageGenerator = new MapGenAbandonedVillage(); private MapGenMineshaft mineshaftGenerator = new MapGenMineshaft(); private MapGenBase ravineGenerator = new MapGenRavine(); private Biome[] biomesForGeneration; double[] mainNoiseRegion; double[] minLimitRegion; double[] maxLimitRegion; double[] depthRegion; private WorldGenDyeFactory dyeFactoryGenerator = new WorldGenDyeFactory(); private WorldGenRunway runwayGenerator = new WorldGenRunway(); private WorldGenSkeleton skeletonGenerator = new WorldGenSkeleton(); private WorldGenRoads roadsGenerator = new WorldGenRoads(); private WorldGenBossPillar bossPillarGenerator = new WorldGenBossPillar(); private WorldGenDeadTree deadTreeGenerator = new WorldGenDeadTree(); public static List runwaySpawnBiome = Arrays.asList(BiomeApocalypse.highPlateau); private WorldGenResearchLab researchLabGenerator = new WorldGenResearchLab(); private WorldGenAbandonedPortal abandonedPortalGenerator = new WorldGenAbandonedPortal(); public static List labSpawnBiome = Arrays.asList(BiomeApocalypse.highPlateau); private final int seaLevel = 24; private final float coordinateScale = 684.412F, heightScale = 684.412F; private final double depthNoiseScaleX = 200F, depthNoiseScaleZ = 200F, depthNoiseScaleExponent = 0.5F; private final float mainNoiseScaleX = 80F, mainNoiseScaleY = 160F, mainNoiseScaleZ = 80F; private final float biomeDepthOffSet = 0.0F, biomeScaleOffset = 0.0F; private final float biomeDepthWeight = 1.0F, biomeScaleWeight = 1.0F; private final double stretchY = 12.0F; private final double baseSize = 8.5F; private final float lowerLimitScale = 512F, upperLimitScale = 512F; private final float dungeonChance = 8F; public ChunkProviderApocalypse(World worldIn, long seed, boolean mapFeaturesEnabledIn) { { mineshaftGenerator = (MapGenMineshaft)net.minecraftforge.event.terraingen.TerrainGen.getModdedMapGen(mineshaftGenerator, net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.MINESHAFT); ravineGenerator = net.minecraftforge.event.terraingen.TerrainGen.getModdedMapGen(ravineGenerator, net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.RAVINE); } this.world = worldIn; this.mapFeaturesEnabled = mapFeaturesEnabledIn; this.terrainType = worldIn.getWorldInfo().getTerrainType(); this.rand = new Random(seed); this.minLimitPerlinNoise = new NoiseGeneratorOctaves(this.rand, 16); this.maxLimitPerlinNoise = new NoiseGeneratorOctaves(this.rand, 16); this.mainPerlinNoise = new NoiseGeneratorOctaves(this.rand, 8); this.surfaceNoise = new NoiseGeneratorPerlin(this.rand, 4); this.scaleNoise = new NoiseGeneratorOctaves(this.rand, 10); this.depthNoise = new NoiseGeneratorOctaves(this.rand, 16); this.forestNoise = new NoiseGeneratorOctaves(this.rand, 8); this.heightMap = new double[825]; this.biomeWeights = new float[25]; for(int i = -2; i <= 2; ++i) { for(int j = -2; j <= 2; ++j) { float f = 10.0F / MathHelper.sqrt((float)(i * i + j * j) + 0.2F); this.biomeWeights[i + 2 + (j + 2) * 5] = f; } } worldIn.setSeaLevel(0); net.minecraftforge.event.terraingen.InitNoiseGensEvent.ContextOverworld ctx = new net.minecraftforge.event.terraingen.InitNoiseGensEvent.ContextOverworld(minLimitPerlinNoise, maxLimitPerlinNoise, mainPerlinNoise, surfaceNoise, scaleNoise, depthNoise, forestNoise); ctx = net.minecraftforge.event.terraingen.TerrainGen.getModdedNoiseGenerators(worldIn, this.rand, ctx); this.minLimitPerlinNoise = ctx.getLPerlin1(); this.maxLimitPerlinNoise = ctx.getLPerlin2(); this.mainPerlinNoise = ctx.getPerlin(); this.surfaceNoise = ctx.getHeight(); this.scaleNoise = ctx.getScale(); this.depthNoise = ctx.getDepth(); this.forestNoise = ctx.getForest(); } public void setBlocksInChunk(int x, int z, ChunkPrimer primer) { this.biomesForGeneration = this.world.getBiomeProvider().getBiomesForGeneration(this.biomesForGeneration, x * 4 - 2, z * 4 - 2, 10, 10); this.generateHeightmap(x * 4, 0, z * 4); for(int i = 0; i < 4; ++i) { int j = i * 5; int k = (i + 1) * 5; for(int l = 0; l < 4; ++l) { int i1 = (j + l) * 33; int j1 = (j + l + 1) * 33; int k1 = (k + l) * 33; int l1 = (k + l + 1) * 33; for(int i2 = 0; i2 < 32; ++i2) { double d0 = 0.125D; double d1 = this.heightMap[i1 + i2]; double d2 = this.heightMap[j1 + i2]; double d3 = this.heightMap[k1 + i2]; double d4 = this.heightMap[l1 + i2]; double d5 = (this.heightMap[i1 + i2 + 1] - d1) * 0.125D; double d6 = (this.heightMap[j1 + i2 + 1] - d2) * 0.125D; double d7 = (this.heightMap[k1 + i2 + 1] - d3) * 0.125D; double d8 = (this.heightMap[l1 + i2 + 1] - d4) * 0.125D; for(int j2 = 0; j2 < 8; ++j2) { double d9 = 0.25D; double d10 = d1; double d11 = d2; double d12 = (d3 - d1) * 0.25D; double d13 = (d4 - d2) * 0.25D; for(int k2 = 0; k2 < 4; ++k2) { double d14 = 0.25D; double d16 = (d11 - d10) * 0.25D; double lvt_45_1_ = d10 - d16; for(int l2 = 0; l2 < 4; ++l2) { if((lvt_45_1_ += d16) > 0.0D) { primer.setBlockState(i * 4 + k2, i2 * 8 + j2, l * 4 + l2, STONE); } } d10 += d12; d11 += d13; } d1 += d5; d2 += d6; d3 += d7; d4 += d8; } } } } } public void replaceBiomeBlocks(int x, int z, ChunkPrimer primer, Biome[] biomesIn) { if(!net.minecraftforge.event.ForgeEventFactory.onReplaceBiomeBlocks(this, x, z, primer, this.world)) return; double d0 = 0.03125D; this.depthBuffer = this.surfaceNoise.getRegion(this.depthBuffer, (double)(x * 16), (double)(z * 16), 16, 16, 0.0625D, 0.0625D, 1.0D); for(int i = 0; i < 16; ++i) { for(int j = 0; j < 16; ++j) { Biome biome = biomesIn[j + i * 16]; biome.genTerrainBlocks(this.world, this.rand, primer, x * 16 + i, z * 16 + j, this.depthBuffer[j + i * 16]); } } } /** * Generates the chunk at the specified position, from scratch */ public Chunk generateChunk(int x, int z) { this.rand.setSeed((long)x * 341873128712L + (long)z * 132897987541L); ChunkPrimer chunkprimer = new ChunkPrimer(); this.setBlocksInChunk(x, z, chunkprimer); this.biomesForGeneration = this.world.getBiomeProvider().getBiomes(this.biomesForGeneration, x * 16, z * 16, 16, 16); this.replaceBiomeBlocks(x, z, chunkprimer, this.biomesForGeneration); this.ravineGenerator.generate(this.world, x, z, chunkprimer); this.mineshaftGenerator.generate(this.world, x, z, chunkprimer); this.villageGenerator.generate(this.world, x, z, chunkprimer); Chunk chunk = new Chunk(this.world, chunkprimer, x, z); byte[] abyte = chunk.getBiomeArray(); for(int i = 0; i < abyte.length; ++i) { abyte[i] = (byte)Biome.getIdForBiome(this.biomesForGeneration[i]); } chunk.generateSkylightMap(); return chunk; } private void generateHeightmap(int p_185978_1_, int p_185978_2_, int p_185978_3_) { this.depthRegion = this.depthNoise.generateNoiseOctaves(this.depthRegion, p_185978_1_, p_185978_3_, 5, 5, this.depthNoiseScaleX, this.depthNoiseScaleZ, this.depthNoiseScaleExponent); float f = this.coordinateScale; float f1 = this.heightScale; this.mainNoiseRegion = this.mainPerlinNoise.generateNoiseOctaves(this.mainNoiseRegion, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)(f / this.mainNoiseScaleX), (double)(f1 / this.mainNoiseScaleY), (double)(f / this.mainNoiseScaleZ)); this.minLimitRegion = this.minLimitPerlinNoise.generateNoiseOctaves(this.minLimitRegion, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)f, (double)f1, (double)f); this.maxLimitRegion = this.maxLimitPerlinNoise.generateNoiseOctaves(this.maxLimitRegion, p_185978_1_, p_185978_2_, p_185978_3_, 5, 33, 5, (double)f, (double)f1, (double)f); int i = 0; int j = 0; for(int k = 0; k < 5; ++k) { for(int l = 0; l < 5; ++l) { float f2 = 0.0F; float f3 = 0.0F; float f4 = 0.0F; int i1 = 2; Biome biome = this.biomesForGeneration[k + 2 + (l + 2) * 10]; for(int j1 = -2; j1 <= 2; ++j1) { for(int k1 = -2; k1 <= 2; ++k1) { Biome biome1 = this.biomesForGeneration[k + j1 + 2 + (l + k1 + 2) * 10]; float f5 = this.biomeDepthOffSet + biome1.getBaseHeight() * this.biomeDepthWeight; float f6 = this.biomeScaleOffset + biome1.getHeightVariation() * this.biomeScaleWeight; if(this.terrainType == WorldType.AMPLIFIED && f5 > 0.0F) { f5 = 1.0F + f5 * 2.0F; f6 = 1.0F + f6 * 4.0F; } float f7 = this.biomeWeights[j1 + 2 + (k1 + 2) * 5] / (f5 + 2.0F); if(biome1.getBaseHeight() > biome.getBaseHeight()) { f7 /= 2.0F; } f2 += f6 * f7; f3 += f5 * f7; f4 += f7; } } f2 = f2 / f4; f3 = f3 / f4; f2 = f2 * 0.9F + 0.1F; f3 = (f3 * 4.0F - 1.0F) / 8.0F; double d7 = this.depthRegion[j] / 8000.0D; if(d7 < 0.0D) { d7 = -d7 * 0.3D; } d7 = d7 * 3.0D - 2.0D; if(d7 < 0.0D) { d7 = d7 / 2.0D; if(d7 < -1.0D) { d7 = -1.0D; } d7 = d7 / 1.4D; d7 = d7 / 2.0D; } else { if(d7 > 1.0D) { d7 = 1.0D; } d7 = d7 / 8.0D; } ++j; double d8 = (double)f3; double d9 = (double)f2; d8 = d8 + d7 * 0.2D; d8 = d8 * this.baseSize / 8.0D; double d0 = this.baseSize + d8 * 4.0D; for(int l1 = 0; l1 < 33; ++l1) { double d1 = ((double)l1 - d0) * this.stretchY * 128.0D / 256.0D / d9; if(d1 < 0.0D) { d1 *= 4.0D; } double d2 = this.minLimitRegion[i] / (double)this.lowerLimitScale; double d3 = this.maxLimitRegion[i] / (double)this.upperLimitScale; double d4 = (this.mainNoiseRegion[i] / 10.0D + 1.0D) / 2.0D; double d5 = MathHelper.clampedLerp(d2, d3, d4) - d1; if(l1 > 29) { double d6 = (double)((float)(l1 - 29) / 3.0F); d5 = d5 * (1.0D - d6) + -10.0D * d6; } this.heightMap[i] = d5; ++i; } } } } /** * Generate initial structures in this chunk, e.g. mineshafts, temples, lakes, and dungeons */ public void populate(int x, int z) { BlockFalling.fallInstantly = true; int i = x * 16; int j = z * 16; BlockPos blockpos = new BlockPos(i, 0, j); Biome biome = this.world.getBiome(blockpos.add(16, 0, 16)); this.rand.setSeed(this.world.getSeed()); long k = this.rand.nextLong() / 2L * 2L + 1L; long l = this.rand.nextLong() / 2L * 2L + 1L; this.rand.setSeed((long)x * k + (long)z * l ^ this.world.getSeed()); boolean flag = false; ChunkPos chunkpos = new ChunkPos(x, z); net.minecraftforge.event.ForgeEventFactory.onChunkPopulate(true, this, this.world, this.rand, x, z, flag); int k1; int l1; int i2; if(rand.nextInt(FlansModApocalypse.DEAD_TREE_RARITY) == 0) { k1 = this.rand.nextInt(16) + 8; l1 = this.rand.nextInt(this.rand.nextInt(248) + 8); i2 = this.rand.nextInt(16) + 8; deadTreeGenerator.generate(world, rand, blockpos.add(k1, l1, i2)); } if(rand.nextInt(FlansModApocalypse.DYE_FACTORY_RARITY) == 0) { k1 = this.rand.nextInt(16) + 8; l1 = this.rand.nextInt(this.rand.nextInt(248) + 8); i2 = this.rand.nextInt(16) + 8; dyeFactoryGenerator.generate(world, rand, blockpos.add(k1, l1, i2)); } if(rand.nextInt(FlansModApocalypse.ABANDONED_PORTAL_APOC_RARITY) == 0) { int height = world.getHeight(i + 8, j + 8); abandonedPortalGenerator.generate(world, rand, blockpos.add(8, height,8)); } if(this.mapFeaturesEnabled) { this.mineshaftGenerator.generateStructure(this.world, this.rand, chunkpos); flag = this.villageGenerator.generateStructure(this.world, this.rand, chunkpos); } if(net.minecraftforge.event.terraingen.TerrainGen.populate(this, this.world, this.rand, x, z, flag, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.DUNGEON)) { for(int j2 = 0; j2 < this.dungeonChance; ++j2) { int i3 = this.rand.nextInt(16) + 8; int l3 = this.rand.nextInt(256); int g = this.rand.nextInt(16) + 8; (new WorldGenDungeons()).generate(this.world, this.rand, blockpos.add(i3, l3, g)); } } biome.decorate(this.world, this.rand, new BlockPos(i, 0, j)); roadsGenerator.generate(world, rand, blockpos); bossPillarGenerator.generate(world, rand, blockpos); if(net.minecraftforge.event.terraingen.TerrainGen.populate(this, this.world, this.rand, x, z, flag, net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ANIMALS)) WorldEntitySpawner.performWorldGenSpawning(this.world, biome, i + 8, j + 8, 16, 16, this.rand); net.minecraftforge.event.ForgeEventFactory.onChunkPopulate(false, this, this.world, this.rand, x, z, flag); if(rand.nextInt(FlansModApocalypse.SKELETON_RARITY) == 0) { k1 = this.rand.nextInt(16) + 8; l1 = this.rand.nextInt(this.rand.nextInt(248) + 8); i2 = this.rand.nextInt(16) + 8; skeletonGenerator.generate(world, rand, blockpos.add(k1, l1, i2)); } int xOrigin = ModuloHelper.divide(x, 4); Random randomRunwayGen = new Random(); randomRunwayGen.setSeed(this.world.getSeed()); k = randomRunwayGen.nextLong() / 2L * 2L + 1L; l = randomRunwayGen.nextLong() / 2L * 2L + 1L; randomRunwayGen.setSeed((long)xOrigin * k + (long)z * l ^ this.world.getSeed()); if(randomRunwayGen.nextInt(FlansModApocalypse.AIRPORT_RARITY) == 0) { boolean canSpawn = true; for(int n = 0; n < 4; n++) { if(!world.getBiomeProvider().areBiomesViable((xOrigin * 4 + n) * 16 + 8, z * 16 + 8, 0, runwaySpawnBiome)) canSpawn = false; } //Generate runway section xOffset at chunk x if(canSpawn) runwayGenerator.generate(world, rand, new BlockPos(x * 16 + 8, 0, z * 16 + 8)); } xOrigin = ModuloHelper.divide(x, 3); int zOrigin = ModuloHelper.divide(z, 3); this.rand.setSeed(this.world.getSeed()); k = this.rand.nextLong() / 2L * 2L + 1L; l = this.rand.nextLong() / 2L * 2L + 1L; this.rand.setSeed((long)xOrigin * k + (long)zOrigin * l ^ this.world.getSeed()); if(rand.nextInt(FlansModApocalypse.LAB_RARITY) == 0) { boolean canSpawn = true; for(int n = 0; n < 5; n++) { for(int m = 0; m < 5; m++) { if(!world.getBiomeProvider().areBiomesViable((xOrigin * 3 - 1 + n) * 16 + 8, (zOrigin * 3 - 1 + m) * 16 + 8, 0, labSpawnBiome)) canSpawn = false; } } //Generate lab rooms in chunk if(canSpawn) { //Reset random seed this.rand.setSeed(this.world.getSeed()); k = this.rand.nextLong() / 2L * 2L + 1L; l = this.rand.nextLong() / 2L * 2L + 1L; this.rand.setSeed((long)x * k + (long)z * l ^ this.world.getSeed()); researchLabGenerator.generate(world, rand, new BlockPos(x * 16, 0, z * 16)); } } BlockFalling.fallInstantly = false; } /** * Called to generate additional structures after initial worldgen, used by ocean monuments */ public boolean generateStructures(Chunk chunkIn, int x, int z) { return false; } public List getPossibleCreatures(EnumCreatureType creatureType, BlockPos pos) { Biome biome = this.world.getBiome(pos); return biome.getSpawnableList(creatureType); } public boolean isInsideStructure(World worldIn, String structureName, BlockPos pos) { if(!this.mapFeaturesEnabled) { return false; } else if("Village".equals(structureName) && this.villageGenerator != null) { return this.villageGenerator.isInsideStructure(pos); } else if("Mineshaft".equals(structureName) && this.mineshaftGenerator != null) { return this.mineshaftGenerator.isInsideStructure(pos); } else { return false; } } @Nullable public BlockPos getNearestStructurePos(World worldIn, String structureName, BlockPos position, boolean findUnexplored) { if(!this.mapFeaturesEnabled) { return null; } else if("Village".equals(structureName) && this.villageGenerator != null) { return this.villageGenerator.getNearestStructurePos(worldIn, position, findUnexplored); } else if("Mineshaft".equals(structureName) && this.mineshaftGenerator != null) { return this.mineshaftGenerator.getNearestStructurePos(worldIn, position, findUnexplored); } else { return null; } } /** * Recreates data about structures intersecting given chunk (used for example by getPossibleCreatures), without * placing any blocks. When called for the first time before any chunk is generated - also initializes the internal * state needed by getPossibleCreatures. */ public void recreateStructures(Chunk chunkIn, int x, int z) { if(this.mapFeaturesEnabled) { this.mineshaftGenerator.generate(this.world, x, z, null); this.villageGenerator.generate(this.world, x, z, null); } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/GenLayerApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.world.gen.layer.GenLayer; import net.minecraft.world.gen.layer.GenLayerVoronoiZoom; import net.minecraft.world.gen.layer.GenLayerZoom; public abstract class GenLayerApocalypse extends GenLayer { public GenLayerApocalypse(long l) { super(l); } public static GenLayer[] makeTheWorld(long l) { GenLayer biomes = new GenLayerBiomes(1L); /* biomes = new GenLayerTFKeyBiomes(1000L, biomes); biomes = new GenLayerTFCompanionBiomes(1000L, biomes); */ biomes = new GenLayerZoom(1000L, biomes); //biomes = new GenLayerZoom(1001L, biomes); /* biomes = new GenLayerTFBiomeStabilize(700L, biomes); biomes = new GenLayerTFThornBorder(500L, biomes); */ biomes = new GenLayerZoom(1002L, biomes); biomes = new GenLayerZoom(1003L, biomes); biomes = new GenLayerZoom(1004L, biomes); biomes = new GenLayerZoom(1005L, biomes); /* GenLayer riverLayer = new GenLayerTFStream(1L, biomes); riverLayer = new GenLayerSmooth(7000L, riverLayer); biomes = new GenLayerTFRiverMix(100L, biomes, riverLayer); */ GenLayer genlayervoronoizoom = new GenLayerVoronoiZoom(10L, biomes); biomes.initWorldGenSeed(l); genlayervoronoizoom.initWorldGenSeed(l); return new GenLayer[]{biomes, genlayervoronoizoom}; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/GenLayerBiomes.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.world.biome.Biome; import net.minecraft.world.gen.layer.GenLayer; import net.minecraft.world.gen.layer.IntCache; public class GenLayerBiomes extends GenLayer { private static final int RARE_BIOME_CHANCE = 12; protected Biome[] commonBiomes = {BiomeApocalypse.deepCanyon, /*BiomeGenApocalypse.canyon,*/ BiomeApocalypse.desert, /*BiomeGenApocalypse.plateau,*/ BiomeApocalypse.highPlateau}; protected Biome[] rareBiomes = {BiomeApocalypse.sulphurPits}; public GenLayerBiomes(long l, GenLayer genlayer) { super(l); this.parent = genlayer; } public GenLayerBiomes(long l) { super(l); } @Override public int[] getInts(int x, int z, int width, int depth) { int[] dest = IntCache.getIntCache(width * depth); for(int dz = 0; dz < depth; dz++) { for(int dx = 0; dx < width; dx++) { initChunkSeed(dx + x, dz + z); if(nextInt(RARE_BIOME_CHANCE) == 0) { dest[(dx + dz * width)] = Biome.getIdForBiome(rareBiomes[nextInt(this.rareBiomes.length)]); } else { dest[(dx + dz * width)] = Biome.getIdForBiome(commonBiomes[nextInt(this.commonBiomes.length)]); } } } return dest; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/TeleporterApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.Teleporter; import net.minecraft.world.WorldServer; public class TeleporterApocalypse extends Teleporter { private WorldServer world; private BlockPos targetTeleporter; public TeleporterApocalypse(WorldServer world, BlockPos targetTeleporter) { super(world); this.world = world; this.targetTeleporter = targetTeleporter; } @Override public boolean makePortal(Entity entity) { return true; } @Override public boolean placeInExistingPortal(Entity entity, float f) { entity.setPosition(targetTeleporter.getX() + 2D, targetTeleporter.getY() + 1.5D, targetTeleporter.getZ() + 2D); return true; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/WorldGenSulphurPool.java ================================================ package com.flansmod.apocalypse.common.world; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenerator; import com.flansmod.apocalypse.common.FlansModApocalypse; public class WorldGenSulphurPool extends WorldGenerator { private Block block; public WorldGenSulphurPool(Block block) { this.block = block; } public boolean generate(World world, Random rand, BlockPos pos) { for(pos = pos.add(-8, 0, -8); pos.getY() > 5 && world.isAirBlock(pos); pos = pos.down()) { } if(pos.getY() <= 4) { return false; } else { pos = pos.down(4); boolean[] aboolean = new boolean[2048]; int i = rand.nextInt(4) + 4; int j; for(j = 0; j < i; ++j) { double d0 = rand.nextDouble() * 6.0D + 3.0D; double d1 = rand.nextDouble() * 4.0D + 2.0D; double d2 = rand.nextDouble() * 6.0D + 3.0D; double d3 = rand.nextDouble() * (16.0D - d0 - 2.0D) + 1.0D + d0 / 2.0D; double d4 = rand.nextDouble() * (8.0D - d1 - 4.0D) + 2.0D + d1 / 2.0D; double d5 = rand.nextDouble() * (16.0D - d2 - 2.0D) + 1.0D + d2 / 2.0D; for(int l = 1; l < 15; ++l) { for(int i1 = 1; i1 < 15; ++i1) { for(int j1 = 1; j1 < 7; ++j1) { double d6 = ((double)l - d3) / (d0 / 2.0D); double d7 = ((double)j1 - d4) / (d1 / 2.0D); double d8 = ((double)i1 - d5) / (d2 / 2.0D); double d9 = d6 * d6 + d7 * d7 + d8 * d8; if(d9 < 1.0D) { aboolean[(l * 16 + i1) * 8 + j1] = true; } } } } } int k; int k1; boolean flag; for(j = 0; j < 16; ++j) { for(k1 = 0; k1 < 16; ++k1) { for(k = 0; k < 8; ++k) { flag = !aboolean[(j * 16 + k1) * 8 + k] && (j < 15 && aboolean[((j + 1) * 16 + k1) * 8 + k] || j > 0 && aboolean[((j - 1) * 16 + k1) * 8 + k] || k1 < 15 && aboolean[(j * 16 + k1 + 1) * 8 + k] || k1 > 0 && aboolean[(j * 16 + (k1 - 1)) * 8 + k] || k < 7 && aboolean[(j * 16 + k1) * 8 + k + 1] || k > 0 && aboolean[(j * 16 + k1) * 8 + (k - 1)]); if(flag) { Material material = world.getBlockState(pos.add(j, k, k1)).getMaterial(); if(k >= 4 && material.isLiquid()) { return false; } if(k < 4 && !material.isSolid() && world.getBlockState(pos.add(j, k, k1)).getBlock() != this.block) { return false; } } } } } for(j = 0; j < 16; ++j) { for(k1 = 0; k1 < 16; ++k1) { for(k = 0; k < 8; ++k) { if(aboolean[(j * 16 + k1) * 8 + k]) { world.setBlockState(pos.add(j, k, k1), k >= 4 ? Blocks.AIR.getDefaultState() : this.block.getDefaultState(), 2); } } } } //if (this.block.getMaterial() == Material.lava) { for(j = 0; j < 16; ++j) { for(k1 = 0; k1 < 16; ++k1) { for(k = 0; k < 8; ++k) { flag = !aboolean[(j * 16 + k1) * 8 + k] && (j < 15 && aboolean[((j + 1) * 16 + k1) * 8 + k] || j > 0 && aboolean[((j - 1) * 16 + k1) * 8 + k] || k1 < 15 && aboolean[(j * 16 + k1 + 1) * 8 + k] || k1 > 0 && aboolean[(j * 16 + (k1 - 1)) * 8 + k] || k < 7 && aboolean[(j * 16 + k1) * 8 + k + 1] || k > 0 && aboolean[(j * 16 + k1) * 8 + (k - 1)]); if(flag && (k < 4 || rand.nextInt(2) != 0) && world.getBlockState(pos.add(j, k, k1)).getMaterial().isSolid()) { world.setBlockState(pos.add(j, k, k1), FlansModApocalypse.blockSulphur.getDefaultState(), 2); } } } } } return true; } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/WorldProviderApocalypse.java ================================================ package com.flansmod.apocalypse.common.world; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.DimensionType; import net.minecraft.world.WorldProvider; import net.minecraft.world.gen.IChunkGenerator; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.apocalypse.common.FlansModApocalypse; public class WorldProviderApocalypse extends WorldProvider { @Override public void init() { super.init(); this.biomeProvider = new BiomeProviderApocalypse(this.world); this.setDimension(FlansModApocalypse.dimensionID); } @Override public IChunkGenerator createChunkGenerator() { return new ChunkProviderApocalypse(world, world.getSeed(), true); } @Override public boolean canRespawnHere() { return FlansModApocalypse.RESPAWN_IN_APOC; } @Override public boolean canCoordinateBeSpawn(int x, int z) { return this.world.getGroundAboveSeaLevel(new BlockPos(x, 0, z)) == Blocks.SAND; } /** * Return Vec3D with biome specific fog color */ @Override @SideOnly(Side.CLIENT) public Vec3d getFogColor(float celestialAngle, float partialTicks) { float f2 = MathHelper.cos(celestialAngle * (float)Math.PI * 2.0F) * 2.0F + 0.5F; f2 = MathHelper.clamp(f2, 0.0F, 1.0F); float f3 = 1.0F; float f4 = 0.85F; float f5 = 0.75F; f3 *= f2 * 0.94F + 0.06F; f4 *= f2 * 0.94F + 0.06F; f5 *= f2 * 0.91F + 0.09F; return new Vec3d((double)f3, (double)f4, (double)f5); } @SideOnly(Side.CLIENT) public Vec3d getSkyColor(net.minecraft.entity.Entity cameraEntity, float partialTicks) { return new Vec3d(0.8F, 0.6F, 0.5F); } @Override public boolean canDoLightning(net.minecraft.world.chunk.Chunk chunk) { return false; } @Override public boolean canDoRainSnowIce(net.minecraft.world.chunk.Chunk chunk) { return false; } @Override public DimensionType getDimensionType() { return DimensionType.OVERWORLD; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/MapGenAbandonedVillage.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Random; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.gen.structure.MapGenStructure; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureComponent; import net.minecraft.world.gen.structure.StructureStart; import com.flansmod.apocalypse.common.world.BiomeApocalypse; public class MapGenAbandonedVillage extends MapGenStructure { public static List villageSpawnBiomes = Arrays.asList(BiomeApocalypse.canyon, BiomeApocalypse.desert); private int terrainType; /** * Distance between villages? */ private int distance; private int something; public MapGenAbandonedVillage() { distance = 20; something = 8; } @Override public String getStructureName() { return "AbandonedVillage"; } @Override protected boolean canSpawnStructureAtCoords(int x, int z) { int xAdjusted = x; int zAdjusted = z; if(xAdjusted < 0) xAdjusted -= distance - 1; if(zAdjusted < 0) zAdjusted -= distance - 1; int xScaled = xAdjusted / distance; int zScaled = zAdjusted / distance; Random rand = world.setRandomSeed(xScaled, zScaled, 10387312); //De-scale. Get co-ordinates of the corner of this village-spawning-area xScaled *= distance; zScaled *= distance; //Pick random spot in this area xScaled += rand.nextInt(distance - something); zScaled += rand.nextInt(distance - something); if(xAdjusted == xScaled && zAdjusted == zScaled && world.getBiomeProvider().areBiomesViable(xAdjusted * 16 + 8, zAdjusted * 16 + 8, 0, villageSpawnBiomes)) { return true; } return false; } @Override protected StructureStart getStructureStart(int x, int z) { return new Start(world, rand, x, z, terrainType); } public static class Start extends StructureStart { private boolean hasMoreThanTwoComponents; public Start() { } public Start(World world, Random rand, int x, int z, int size) { List list = StructureAbandonedVillagePieces.getStructureVillageWeightedPieceList(rand, size); StructureAbandonedVillagePieces.Start structurevillagepieces$start = new StructureAbandonedVillagePieces.Start(world.getBiomeProvider(), 0, rand, (x << 4) + 2, (z << 4) + 2, list, size); this.components.add(structurevillagepieces$start); structurevillagepieces$start.buildComponent(structurevillagepieces$start, this.components, rand); List list1 = structurevillagepieces$start.pendingRoads; List list2 = structurevillagepieces$start.pendingHouses; while(!list1.isEmpty() || !list2.isEmpty()) { if(list1.isEmpty()) { int i = rand.nextInt(list2.size()); StructureComponent structurecomponent = list2.remove(i); structurecomponent.buildComponent(structurevillagepieces$start, this.components, rand); } else { int j = rand.nextInt(list1.size()); StructureComponent structurecomponent2 = list1.remove(j); structurecomponent2.buildComponent(structurevillagepieces$start, this.components, rand); } } this.updateBoundingBox(); int k = 0; for(StructureComponent structurecomponent1 : this.components) { if(!(structurecomponent1 instanceof StructureAbandonedVillagePieces.Road)) { ++k; } } this.hasMoreThanTwoComponents = k > 2; } @Override public void generateStructure(World world, Random rand, StructureBoundingBox boundingBox) { Iterator iterator = this.components.iterator(); while(iterator.hasNext()) { StructureComponent structurecomponent = (StructureComponent)iterator.next(); if(structurecomponent.getBoundingBox().intersectsWith(boundingBox) && !structurecomponent.addComponentParts(world, rand, boundingBox)) { iterator.remove(); } /* if(!(structurecomponent instanceof Well || structurecomponent instanceof Field1 || structurecomponent instanceof Field2)) { StructureBoundingBox box = structurecomponent.getBoundingBox(); int holeX = box.minX + rand.nextInt(box.getXSize() + 1); int holeY = box.minY + rand.nextInt(box.getYSize() + 1); int holeZ = box.minZ + rand.nextInt(box.getZSize() + 1); float holeRadius = rand.nextFloat() * 3F; holeRadius *= holeRadius; for(int i = box.minX; i <= box.maxX; i++) { for(int k = box.minZ; k <= box.maxZ; k++) { for(int j = box.maxY; j >= box.minY; j--) { int dX = i - holeX; int dY = j - holeY; int dZ = k - holeZ; BlockPos pos = new BlockPos(i, j, k); if(world.getBlockState(pos) != Blocks.oak_door) if(dX * dX + dY * dY + dZ * dZ + rand.nextFloat() < holeRadius) world.setBlockState(pos, Blocks.AIR.getDefaultState(), 2); } } } } */ } } @Override public boolean isSizeableStructure() { return this.hasMoreThanTwoComponents; } @Override public void writeToNBT(NBTTagCompound tags) { super.writeToNBT(tags); tags.setBoolean("Valid", this.hasMoreThanTwoComponents); } @Override public void readFromNBT(NBTTagCompound tags) { super.readFromNBT(tags); this.hasMoreThanTwoComponents = tags.getBoolean("Valid"); } } @Override public BlockPos getNearestStructurePos(World worldIn, BlockPos pos, boolean findUnexplored) { this.world = worldIn; return findNearestStructurePosBySpacing(worldIn, this, pos, this.distance, 8, 10387312, false, 100, findUnexplored); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/StructureAbandonedVillagePieces.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import com.google.common.collect.Lists; import net.minecraft.block.Block; import net.minecraft.block.BlockSandStone; import net.minecraft.block.BlockStairs; import net.minecraft.block.BlockTorch; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Biomes; import net.minecraft.init.Blocks; import net.minecraft.item.EnumDyeColor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeProvider; import net.minecraft.world.gen.structure.MapGenStructureIO; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureComponent; import net.minecraft.world.gen.structure.StructureVillagePieces; import net.minecraft.world.gen.structure.template.TemplateManager; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.terraingen.BiomeEvent; import net.minecraftforge.fml.common.eventhandler.Event.Result; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.FlansMod; import com.flansmod.common.TileEntityItemHolder; public class StructureAbandonedVillagePieces { private static final String __OBFID = "CL_00000516"; public static void registerVillagePieces() { MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Library.class, "AVBH"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Field1.class, "AVDF"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Field2.class, "AVF"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Torch.class, "AVL"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Hall.class, "AVPH"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.House4Garden.class, "AVSH"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.WoodHut.class, "AVSmH"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Church.class, "AVST"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Blacksmith.class, "AVS"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Start.class, "AVStart"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Path.class, "AVSR"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.House3.class, "AVTRH"); MapGenStructureIO.registerStructureComponent(StructureAbandonedVillagePieces.Well.class, "AVW"); MapGenStructureIO.registerStructure(MapGenAbandonedVillage.Start.class, "AbandonedVillage"); } public static List getStructureVillageWeightedPieceList(Random p_75084_0_, int p_75084_1_) { ArrayList arraylist = Lists.newArrayList(); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.House4Garden.class, 4, MathHelper.getInt(p_75084_0_, 2 + p_75084_1_, 4 + p_75084_1_ * 2))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Church.class, 20, MathHelper.getInt(p_75084_0_, 0 + p_75084_1_, 1 + p_75084_1_))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Library.class, 20, MathHelper.getInt(p_75084_0_, 0 + p_75084_1_, 2 + p_75084_1_))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.WoodHut.class, 3, MathHelper.getInt(p_75084_0_, 2 + p_75084_1_, 5 + p_75084_1_ * 3))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Hall.class, 15, MathHelper.getInt(p_75084_0_, 0 + p_75084_1_, 2 + p_75084_1_))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Field1.class, 3, MathHelper.getInt(p_75084_0_, 1 + p_75084_1_, 4 + p_75084_1_))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Field2.class, 3, MathHelper.getInt(p_75084_0_, 2 + p_75084_1_, 4 + p_75084_1_ * 2))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.Blacksmith.class, 15, MathHelper.getInt(p_75084_0_, 0, 1 + p_75084_1_))); arraylist.add(new StructureAbandonedVillagePieces.PieceWeight(StructureAbandonedVillagePieces.House3.class, 8, MathHelper.getInt(p_75084_0_, 0 + p_75084_1_, 3 + p_75084_1_ * 2))); //net.minecraftforge.fml.common.registry.VillagerRegistry.addExtraVillageComponents(arraylist, p_75084_0_, p_75084_1_); arraylist.removeIf(o -> { if(o instanceof PieceWeight) return ((PieceWeight)o).villagePiecesLimit == 0; else if(o instanceof StructureVillagePieces.PieceWeight) return ((StructureVillagePieces.PieceWeight)o).villagePiecesLimit == 0; return true; }); return arraylist; } private static int func_75079_a(List p_75079_0_) { boolean flag = false; int i = 0; StructureAbandonedVillagePieces.PieceWeight pieceweight; for(Iterator iterator = p_75079_0_.iterator(); iterator.hasNext(); i += pieceweight.villagePieceWeight) { pieceweight = (StructureAbandonedVillagePieces.PieceWeight)iterator.next(); if(pieceweight.villagePiecesLimit > 0 && pieceweight.villagePiecesSpawned < pieceweight.villagePiecesLimit) { flag = true; } } return flag ? i : -1; } private static StructureAbandonedVillagePieces.Village func_176065_a(StructureAbandonedVillagePieces.Start p_176065_0_, StructureAbandonedVillagePieces.PieceWeight p_176065_1_, List p_176065_2_, Random p_176065_3_, int p_176065_4_, int p_176065_5_, int p_176065_6_, EnumFacing p_176065_7_, int p_176065_8_) { Class oclass = p_176065_1_.villagePieceClass; Object object = null; if(oclass == StructureAbandonedVillagePieces.House4Garden.class) { object = StructureAbandonedVillagePieces.House4Garden.func_175858_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Church.class) { object = StructureAbandonedVillagePieces.Church.func_175854_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Library.class) { object = StructureAbandonedVillagePieces.Library.func_175850_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.WoodHut.class) { object = StructureAbandonedVillagePieces.WoodHut.func_175853_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Hall.class) { object = StructureAbandonedVillagePieces.Hall.func_175857_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Field1.class) { object = StructureAbandonedVillagePieces.Field1.func_175851_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Field2.class) { object = StructureAbandonedVillagePieces.Field2.func_175852_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.Blacksmith.class) { object = StructureAbandonedVillagePieces.Blacksmith.func_175855_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } else if(oclass == StructureAbandonedVillagePieces.House3.class) { object = StructureAbandonedVillagePieces.House3.func_175849_a(p_176065_0_, p_176065_2_, p_176065_3_, p_176065_4_, p_176065_5_, p_176065_6_, p_176065_7_, p_176065_8_); } return (StructureAbandonedVillagePieces.Village)object; } private static StructureAbandonedVillagePieces.Village func_176067_c(StructureAbandonedVillagePieces.Start p_176067_0_, List p_176067_1_, Random p_176067_2_, int p_176067_3_, int p_176067_4_, int p_176067_5_, EnumFacing p_176067_6_, int p_176067_7_) { int i1 = func_75079_a(p_176067_0_.structureVillageWeightedPieceList); if(i1 <= 0) { return null; } else { int j1 = 0; while(j1 < 5) { ++j1; int k1 = p_176067_2_.nextInt(i1); for(Object aStructureVillageWeightedPieceList : p_176067_0_.structureVillageWeightedPieceList) { PieceWeight pieceweight = (PieceWeight)aStructureVillageWeightedPieceList; k1 -= pieceweight.villagePieceWeight; if(k1 < 0) { if(!pieceweight.canSpawnMoreVillagePiecesOfType(p_176067_7_) || pieceweight == p_176067_0_.structVillagePieceWeight && p_176067_0_.structureVillageWeightedPieceList.size() > 1) { break; } Village village = func_176065_a(p_176067_0_, pieceweight, p_176067_1_, p_176067_2_, p_176067_3_, p_176067_4_, p_176067_5_, p_176067_6_, p_176067_7_); if(village != null) { ++pieceweight.villagePiecesSpawned; p_176067_0_.structVillagePieceWeight = pieceweight; if(!pieceweight.canSpawnMoreVillagePieces()) { p_176067_0_.structureVillageWeightedPieceList.remove(pieceweight); } return village; } } } } StructureBoundingBox structureboundingbox = StructureAbandonedVillagePieces.Torch.func_175856_a(p_176067_0_, p_176067_1_, p_176067_2_, p_176067_3_, p_176067_4_, p_176067_5_, p_176067_6_); if(structureboundingbox != null) { return new StructureAbandonedVillagePieces.Torch(p_176067_0_, p_176067_7_, p_176067_2_, structureboundingbox, p_176067_6_); } else { return null; } } } private static StructureComponent func_176066_d(StructureAbandonedVillagePieces.Start p_176066_0_, List p_176066_1_, Random p_176066_2_, int p_176066_3_, int p_176066_4_, int p_176066_5_, EnumFacing p_176066_6_, int p_176066_7_) { if(p_176066_7_ > 50) { return null; } else if(Math.abs(p_176066_3_ - p_176066_0_.getBoundingBox().minX) <= 112 && Math.abs(p_176066_5_ - p_176066_0_.getBoundingBox().minZ) <= 112) { StructureAbandonedVillagePieces.Village village = func_176067_c(p_176066_0_, p_176066_1_, p_176066_2_, p_176066_3_, p_176066_4_, p_176066_5_, p_176066_6_, p_176066_7_ + 1); if(village != null) { int i1 = (village.getBoundingBox().minX + village.getBoundingBox().maxX) / 2; int j1 = (village.getBoundingBox().minZ + village.getBoundingBox().maxZ) / 2; int k1 = village.getBoundingBox().maxX - village.getBoundingBox().minX; int l1 = village.getBoundingBox().maxZ - village.getBoundingBox().minZ; int i2 = k1 > l1 ? k1 : l1; if(p_176066_0_.getBiomeProvider().areBiomesViable(i1, j1, i2 / 2 + 4, MapGenAbandonedVillage.villageSpawnBiomes)) { p_176066_1_.add(village); p_176066_0_.pendingHouses.add(village); return village; } } return null; } else { return null; } } private static StructureComponent func_176069_e(StructureAbandonedVillagePieces.Start p_176069_0_, List p_176069_1_, Random p_176069_2_, int p_176069_3_, int p_176069_4_, int p_176069_5_, EnumFacing p_176069_6_, int p_176069_7_) { if(p_176069_7_ > 3 + p_176069_0_.terrainType) { return null; } else if(Math.abs(p_176069_3_ - p_176069_0_.getBoundingBox().minX) <= 112 && Math.abs(p_176069_5_ - p_176069_0_.getBoundingBox().minZ) <= 112) { StructureBoundingBox structureboundingbox = StructureAbandonedVillagePieces.Path.func_175848_a(p_176069_0_, p_176069_1_, p_176069_2_, p_176069_3_, p_176069_4_, p_176069_5_, p_176069_6_); if(structureboundingbox != null && structureboundingbox.minY > 10) { StructureAbandonedVillagePieces.Path path = new StructureAbandonedVillagePieces.Path(p_176069_0_, p_176069_7_, p_176069_2_, structureboundingbox, p_176069_6_); int i1 = (path.getBoundingBox().minX + path.getBoundingBox().maxX) / 2; int j1 = (path.getBoundingBox().minZ + path.getBoundingBox().maxZ) / 2; int k1 = path.getBoundingBox().maxX - path.getBoundingBox().minX; int l1 = path.getBoundingBox().maxZ - path.getBoundingBox().minZ; int i2 = k1 > l1 ? k1 : l1; if(p_176069_0_.getBiomeProvider().areBiomesViable(i1, j1, i2 / 2 + 4, MapGenAbandonedVillage.villageSpawnBiomes)) { p_176069_1_.add(path); p_176069_0_.pendingRoads.add(path); return path; } } return null; } else { return null; } } public static class Church extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000525"; public Church() { } public Church(StructureAbandonedVillagePieces.Start p_i45564_1_, int p_i45564_2_, Random p_i45564_3_, StructureBoundingBox p_i45564_4_, EnumFacing p_i45564_5_) { super(p_i45564_1_, p_i45564_2_); this.setCoordBaseMode(p_i45564_5_); this.boundingBox = p_i45564_4_; } public static StructureAbandonedVillagePieces.Church func_175854_a(StructureAbandonedVillagePieces.Start p_175854_0_, List p_175854_1_, Random p_175854_2_, int p_175854_3_, int p_175854_4_, int p_175854_5_, EnumFacing p_175854_6_, int p_175854_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175854_3_, p_175854_4_, p_175854_5_, 0, 0, 0, 5, 12, 9, p_175854_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175854_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Church(p_175854_0_, p_175854_7_, p_175854_2_, structureboundingbox, p_175854_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random rand, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 12 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 3, 3, 7, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 5, 1, 3, 9, 3, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 0, 3, 0, 8, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 0, 3, 10, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 1, 0, 10, 3, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 1, 1, 4, 10, 3, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 4, 0, 4, 7, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 0, 4, 4, 4, 7, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 8, 3, 4, 8, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 5, 4, 3, 10, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 5, 5, 3, 5, 7, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 9, 0, 4, 9, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 0, 4, 4, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 0, 11, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 11, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 2, 11, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 2, 11, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 1, 1, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 1, 1, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 2, 1, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 3, 1, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 3, 1, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 3, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 3, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 6, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 7, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 6, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 7, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 6, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 7, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 6, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 7, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 3, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 3, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 3, 8, p_74875_3_); this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 1, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 2, 1, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 3, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.EAST), 1, 2, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.NORTH), 3, 2, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 0, p_74875_3_); if(this.getBlockStateFromPos(worldIn, 2, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, 2, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 2, 0, -1, p_74875_3_); } for(int j = 0; j < 9; ++j) { for(int k = 0; k < 5; ++k) { this.clearCurrentPositionBlocksUpwards(worldIn, k, 12, j, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), k, -1, j, p_74875_3_); } } int[][] destruction = { {3, 3, 0, 0, 0}, {4, 0, 0, 0, 0}, {6, 3, 0, 0, 0}, {8, 9, 3, 0, 0}, {9, 9, 6, 0, 0}, {10, 9, 0, 0, 0}, {10, 9, 9, 0, 0}, {10, 9, 9, 0, 0}, {10, 9, 9, 0, 0} }; destroyBuilding(worldIn, destruction, p_74875_3_); this.spawnVillagers(worldIn, p_74875_3_, 2, 1, 2, 1); return true; } protected int func_180779_c(int p_180779_1_, int p_180779_2_) { return 2; } } public static class Field1 extends StructureAbandonedVillagePieces.Village { /** * First crop type for this field. */ private Block cropTypeA; /** * Second crop type for this field. */ private Block cropTypeB; /** * Third crop type for this field. */ private Block cropTypeC; /** * Fourth crop type for this field. */ private Block cropTypeD; private static final String __OBFID = "CL_00000518"; public Field1() { } public Field1(StructureAbandonedVillagePieces.Start p_i45570_1_, int p_i45570_2_, Random p_i45570_3_, StructureBoundingBox p_i45570_4_, EnumFacing p_i45570_5_) { super(p_i45570_1_, p_i45570_2_); this.setCoordBaseMode(p_i45570_5_); this.boundingBox = p_i45570_4_; this.cropTypeA = this.func_151559_a(p_i45570_3_); this.cropTypeB = this.func_151559_a(p_i45570_3_); this.cropTypeC = this.func_151559_a(p_i45570_3_); this.cropTypeD = this.func_151559_a(p_i45570_3_); } /** * (abstract) Helper method to write subclass data to NBT */ protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setInteger("CA", Block.REGISTRY.getIDForObject(this.cropTypeA)); p_143012_1_.setInteger("CB", Block.REGISTRY.getIDForObject(this.cropTypeB)); p_143012_1_.setInteger("CC", Block.REGISTRY.getIDForObject(this.cropTypeC)); p_143012_1_.setInteger("CD", Block.REGISTRY.getIDForObject(this.cropTypeD)); } /** * (abstract) Helper method to read subclass data from NBT */ protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.cropTypeA = Block.getBlockById(p_143011_1_.getInteger("CA")); this.cropTypeB = Block.getBlockById(p_143011_1_.getInteger("CB")); this.cropTypeC = Block.getBlockById(p_143011_1_.getInteger("CC")); this.cropTypeD = Block.getBlockById(p_143011_1_.getInteger("CD")); } private Block func_151559_a(Random p_151559_1_) { switch(p_151559_1_.nextInt(5)) { case 0: return Blocks.CARROTS; case 1: return Blocks.POTATOES; default: return Blocks.WHEAT; } } public static StructureAbandonedVillagePieces.Field1 func_175851_a(StructureAbandonedVillagePieces.Start p_175851_0_, List p_175851_1_, Random p_175851_2_, int p_175851_3_, int p_175851_4_, int p_175851_5_, EnumFacing p_175851_6_, int p_175851_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175851_3_, p_175851_4_, p_175851_5_, 0, 0, 0, 13, 4, 9, p_175851_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175851_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Field1(p_175851_0_, p_175851_7_, p_175851_2_, structureboundingbox, p_175851_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 4 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 0, 12, 4, 8, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 2, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 0, 1, 5, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 7, 0, 1, 8, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 10, 0, 1, 11, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 0, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 6, 0, 0, 6, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 12, 0, 0, 12, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 0, 11, 0, 0, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 8, 11, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); //this.fillWithBlocks(worldIn, p_74875_3_, 3, 0, 1, 3, 0, 7, Blocks.WATER.getDefaultState(), Blocks.WATER.getDefaultState(), false); //this.fillWithBlocks(worldIn, p_74875_3_, 9, 0, 1, 9, 0, 7, Blocks.WATER.getDefaultState(), Blocks.WATER.getDefaultState(), false); int i; for(i = 1; i <= 7; ++i) { if(p_74875_2_.nextInt(50) == 0) { int row = p_74875_2_.nextInt(11) + 1; if(row != 3 && row != 6 && row != 9) this.setBlockState(worldIn, this.cropTypeD.getStateFromMeta(MathHelper.getInt(p_74875_2_, 2, 7)), row, 1, i, p_74875_3_); } } for(i = 0; i < 9; ++i) { for(int j = 0; j < 13; ++j) { this.clearCurrentPositionBlocksUpwards(worldIn, j, 4, i, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.DIRT.getDefaultState(), j, -1, i, p_74875_3_); } } return true; } } public static class Field2 extends StructureAbandonedVillagePieces.Village { /** * First crop type for this field. */ private Block cropTypeA; /** * Second crop type for this field. */ private Block cropTypeB; private static final String __OBFID = "CL_00000519"; public Field2() { } public Field2(StructureAbandonedVillagePieces.Start p_i45569_1_, int p_i45569_2_, Random p_i45569_3_, StructureBoundingBox p_i45569_4_, EnumFacing p_i45569_5_) { super(p_i45569_1_, p_i45569_2_); this.setCoordBaseMode(p_i45569_5_); this.boundingBox = p_i45569_4_; this.cropTypeA = this.func_151560_a(p_i45569_3_); this.cropTypeB = this.func_151560_a(p_i45569_3_); } /** * (abstract) Helper method to write subclass data to NBT */ protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setInteger("CA", Block.REGISTRY.getIDForObject(this.cropTypeA)); p_143012_1_.setInteger("CB", Block.REGISTRY.getIDForObject(this.cropTypeB)); } /** * (abstract) Helper method to read subclass data from NBT */ protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.cropTypeA = Block.getBlockById(p_143011_1_.getInteger("CA")); this.cropTypeB = Block.getBlockById(p_143011_1_.getInteger("CB")); } private Block func_151560_a(Random p_151560_1_) { switch(p_151560_1_.nextInt(5)) { case 0: return Blocks.CARROTS; case 1: return Blocks.POTATOES; default: return Blocks.WHEAT; } } public static StructureAbandonedVillagePieces.Field2 func_175852_a(StructureAbandonedVillagePieces.Start p_175852_0_, List p_175852_1_, Random p_175852_2_, int p_175852_3_, int p_175852_4_, int p_175852_5_, EnumFacing p_175852_6_, int p_175852_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175852_3_, p_175852_4_, p_175852_5_, 0, 0, 0, 7, 4, 9, p_175852_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175852_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Field2(p_175852_0_, p_175852_7_, p_175852_2_, structureboundingbox, p_175852_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 4 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 0, 6, 4, 8, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 2, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 0, 1, 5, 0, 7, Blocks.FARMLAND.getDefaultState(), Blocks.FARMLAND.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 0, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 6, 0, 0, 6, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 0, 5, 0, 0, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 8, 5, 0, 8, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); //this.fillWithBlocks(worldIn, p_74875_3_, 3, 0, 1, 3, 0, 7, Blocks.WATER.getDefaultState(), Blocks.WATER.getDefaultState(), false); int i; for(i = 1; i <= 7; ++i) { if(p_74875_2_.nextInt(50) == 0) { int row = p_74875_2_.nextInt(5) + 1; if(row != 3) this.setBlockState(worldIn, this.cropTypeA.getStateFromMeta(MathHelper.getInt(p_74875_2_, 2, 7)), row, 1, i, p_74875_3_); } } for(i = 0; i < 9; ++i) { for(int j = 0; j < 7; ++j) { this.clearCurrentPositionBlocksUpwards(worldIn, j, 4, i, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.DIRT.getDefaultState(), j, -1, i, p_74875_3_); } } return true; } } public static class Hall extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000522"; public Hall() { } public Hall(StructureAbandonedVillagePieces.Start p_i45567_1_, int p_i45567_2_, Random p_i45567_3_, StructureBoundingBox p_i45567_4_, EnumFacing p_i45567_5_) { super(p_i45567_1_, p_i45567_2_); this.setCoordBaseMode(p_i45567_5_); this.boundingBox = p_i45567_4_; } public static StructureAbandonedVillagePieces.Hall func_175857_a(StructureAbandonedVillagePieces.Start p_175857_0_, List p_175857_1_, Random p_175857_2_, int p_175857_3_, int p_175857_4_, int p_175857_5_, EnumFacing p_175857_6_, int p_175857_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175857_3_, p_175857_4_, p_175857_5_, 0, 0, 0, 9, 7, 11, p_175857_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175857_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Hall(p_175857_0_, p_175857_7_, p_175857_2_, structureboundingbox, p_175857_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 7 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 7, 4, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 1, 6, 8, 4, 10, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 0, 6, 8, 0, 10, Blocks.DIRT.getDefaultState(), Blocks.DIRT.getDefaultState(), false); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 6, 0, 6, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 2, 1, 6, 2, 1, 10, Blocks.OAK_FENCE.getDefaultState(), Blocks.OAK_FENCE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 1, 6, 8, 1, 10, Blocks.OAK_FENCE.getDefaultState(), Blocks.OAK_FENCE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 3, 1, 10, 7, 1, 10, Blocks.OAK_FENCE.getDefaultState(), Blocks.OAK_FENCE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 7, 0, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 0, 3, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 0, 0, 8, 3, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 0, 7, 1, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 5, 7, 1, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 0, 7, 3, 0, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 5, 7, 3, 5, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 1, 8, 4, 1, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 4, 8, 4, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 5, 2, 8, 5, 3, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 0, 4, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 0, 4, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 4, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 4, 3, p_74875_3_); int k; int l; for(k = -1; k <= 2; ++k) { for(l = 0; l <= 8; ++l) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), l, 4 + k, k, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.SOUTH), l, 4 + k, 5 - k, p_74875_3_); } } this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 0, 2, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 0, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 3, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 5, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 6, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 2, 1, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.WOODEN_PRESSURE_PLATE.getDefaultState(), 2, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 1, 1, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 2, 1, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.EAST), 1, 1, 3, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 5, 0, 1, 7, 0, 3, Blocks.DOUBLE_STONE_SLAB.getDefaultState(), Blocks.DOUBLE_STONE_SLAB.getDefaultState(), false); this.setBlockState(worldIn, Blocks.DOUBLE_STONE_SLAB.getDefaultState(), 6, 1, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.DOUBLE_STONE_SLAB.getDefaultState(), 6, 1, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode()), 2, 3, 1, p_74875_3_); if(this.getBlockStateFromPos(worldIn, 2, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, 2, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 2, 0, -1, p_74875_3_); } this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 6, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 6, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode().getOpposite()), 6, 3, 4, p_74875_3_); for(k = 0; k < 5; ++k) { for(l = 0; l < 9; ++l) { this.clearCurrentPositionBlocksUpwards(worldIn, l, 7, k, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), l, -1, k, p_74875_3_); } } this.spawnVillagers(worldIn, p_74875_3_, 4, 1, 2, 2); return true; } protected int func_180779_c(int p_180779_1_, int p_180779_2_) { return p_180779_1_ == 0 ? 4 : super.func_180779_c(p_180779_1_, p_180779_2_); } } public static class Library extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000517"; private boolean hasMadeChest = false; public Library() { } public Library(StructureAbandonedVillagePieces.Start p_i45571_1_, int p_i45571_2_, Random p_i45571_3_, StructureBoundingBox p_i45571_4_, EnumFacing p_i45571_5_) { super(p_i45571_1_, p_i45571_2_); this.setCoordBaseMode(p_i45571_5_); this.boundingBox = p_i45571_4_; } public static StructureAbandonedVillagePieces.Library func_175850_a(StructureAbandonedVillagePieces.Start p_175850_0_, List p_175850_1_, Random p_175850_2_, int p_175850_3_, int p_175850_4_, int p_175850_5_, EnumFacing p_175850_6_, int p_175850_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175850_3_, p_175850_4_, p_175850_5_, 0, 0, 0, 9, 9, 6, p_175850_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175850_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Library(p_175850_0_, p_175850_7_, p_175850_2_, structureboundingbox, p_175850_6_) : null; } protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setBoolean("Chest", this.hasMadeChest); } protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.hasMadeChest = p_143011_1_.getBoolean("Chest"); } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 9 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 7, 5, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 8, 0, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 5, 0, 8, 5, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 6, 1, 8, 6, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 7, 2, 8, 7, 3, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); int k; int l; for(k = -1; k <= 2; ++k) { for(l = 0; l <= 8; ++l) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), l, 6 + k, k, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.SOUTH), l, 6 + k, 5 - k, p_74875_3_); } } this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 0, 0, 1, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 5, 8, 1, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 1, 0, 8, 1, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 1, 0, 7, 1, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 2, 0, 0, 4, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 2, 5, 0, 4, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 2, 5, 8, 4, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 2, 0, 8, 4, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 2, 1, 0, 4, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 5, 7, 4, 5, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 2, 1, 8, 4, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 0, 7, 4, 0, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 4, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 5, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 6, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 4, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 5, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 6, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 0, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 0, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 0, 3, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 0, 3, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 8, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 8, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 8, 3, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 8, 3, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 2, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 3, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 5, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 6, 2, 5, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 1, 4, 1, 7, 4, 1, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 4, 4, 7, 4, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 3, 4, 2, 3, 4, Blocks.BOOKSHELF.getDefaultState(), Blocks.BOOKSHELF.getDefaultState(), false); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 7, 1, 4, p_74875_3_); //Flan's Mod Bits : Crafting tables this.setBlockState(worldIn, FlansModApocalypse.getLootGenerator().getRandomWeaponBox(p_74875_2_).getDefaultState(), 1, 1, 4, p_74875_3_); this.setBlockState(worldIn, FlansMod.workbench.getStateFromMeta(p_74875_2_.nextInt(2)), 7, 1, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.CRAFTING_TABLE.getDefaultState(), 7, 1, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 3, 1, 4, p_74875_3_); if(!hasMadeChest && p_74875_3_.isVecInside(new BlockPos(this.getXWithOffset(2, 4), this.getYWithOffset(1), this.getZWithOffset(2, 4)))) { hasMadeChest = true; //Chest with random Flan's Mod bits BlockPos chestPos = new BlockPos(this.getXWithOffset(2, 4), this.getYWithOffset(1), this.getZWithOffset(2, 4)); IBlockState chestState = Blocks.CHEST.correctFacing(worldIn, chestPos, Blocks.CHEST.getDefaultState()); worldIn.setBlockState(chestPos, Blocks.CHEST.correctFacing(worldIn, chestPos, chestState), 2); TileEntity tileentity = worldIn.getTileEntity(chestPos); if(tileentity instanceof TileEntityChest) { FlansModApocalypse.getLootGenerator().fillVillageChest(p_74875_2_, (TileEntityChest)tileentity); } //Dead skeleton with weapon BlockPos skeletonPos = new BlockPos(this.getXWithOffset(5, 4), this.getYWithOffset(1), this.getZWithOffset(5, 4)); worldIn.setBlockState(skeletonPos, FlansModApocalypse.slumpedSkeleton.getStateFromMeta((4 - Blocks.CHEST.getMetaFromState(chestState)) % 4), 2); FlansModApocalypse.getLootGenerator().addRandomLoot((TileEntityItemHolder)worldIn.getTileEntity(skeletonPos), p_74875_2_, false); } this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 1, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 1, 2, 0, p_74875_3_); if(this.getBlockStateFromPos(worldIn, 1, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, 1, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 1, 0, -1, p_74875_3_); } for(l = 0; l < 6; ++l) { for(int i1 = 0; i1 < 9; ++i1) { this.clearCurrentPositionBlocksUpwards(worldIn, i1, 9, l, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), i1, -1, l, p_74875_3_); } } this.spawnVillagers(worldIn, p_74875_3_, 2, 1, 2, 1); return true; } protected int func_180779_c(int p_180779_1_, int p_180779_2_) { return 1; } } public static class Blacksmith extends StructureAbandonedVillagePieces.Village { /** * List of items that Village's Blacksmith chest can contain. */ //private static final List villageBlacksmithChestContents = Lists.newArrayList(new WeightedRandomChestContent[] {new WeightedRandomChestContent(Items.diamond, 0, 1, 3, 3), new WeightedRandomChestContent(Items.iron_ingot, 0, 1, 5, 10), new WeightedRandomChestContent(Items.gold_ingot, 0, 1, 3, 5), new WeightedRandomChestContent(Items.bread, 0, 1, 3, 15), new WeightedRandomChestContent(Items.apple, 0, 1, 3, 15), new WeightedRandomChestContent(Items.iron_pickaxe, 0, 1, 1, 5), new WeightedRandomChestContent(Items.iron_sword, 0, 1, 1, 5), new WeightedRandomChestContent(Items.iron_chestplate, 0, 1, 1, 5), new WeightedRandomChestContent(Items.iron_helmet, 0, 1, 1, 5), new WeightedRandomChestContent(Items.iron_leggings, 0, 1, 1, 5), new WeightedRandomChestContent(Items.iron_boots, 0, 1, 1, 5), new WeightedRandomChestContent(Item.getItemFromBlock(Blocks.OBSIDIAN), 0, 3, 7, 5), new WeightedRandomChestContent(Item.getItemFromBlock(Blocks.sapling), 0, 3, 7, 5), new WeightedRandomChestContent(Items.saddle, 0, 1, 1, 3), new WeightedRandomChestContent(Items.iron_horse_armor, 0, 1, 1, 1), new WeightedRandomChestContent(Items.golden_horse_armor, 0, 1, 1, 1), new WeightedRandomChestContent(Items.diamond_horse_armor, 0, 1, 1, 1)}); private boolean hasMadeChest; private static final String __OBFID = "CL_00000526"; public Blacksmith() { } public Blacksmith(StructureAbandonedVillagePieces.Start p_i45563_1_, int p_i45563_2_, Random p_i45563_3_, StructureBoundingBox p_i45563_4_, EnumFacing p_i45563_5_) { super(p_i45563_1_, p_i45563_2_); this.setCoordBaseMode(p_i45563_5_); this.boundingBox = p_i45563_4_; } public static StructureAbandonedVillagePieces.Blacksmith func_175855_a(StructureAbandonedVillagePieces.Start p_175855_0_, List p_175855_1_, Random p_175855_2_, int p_175855_3_, int p_175855_4_, int p_175855_5_, EnumFacing p_175855_6_, int p_175855_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175855_3_, p_175855_4_, p_175855_5_, 0, 0, 0, 10, 6, 7, p_175855_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175855_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.Blacksmith(p_175855_0_, p_175855_7_, p_175855_2_, structureboundingbox, p_175855_6_) : null; } /** * (abstract) Helper method to write subclass data to NBT */ protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setBoolean("Chest", this.hasMadeChest); } /** * (abstract) Helper method to read subclass data from NBT */ protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.hasMadeChest = p_143011_1_.getBoolean("Chest"); } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random rand, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 6 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 0, 9, 4, 6, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 9, 0, 6, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 0, 9, 4, 6, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 5, 0, 9, 5, 6, Blocks.STONE_SLAB.getDefaultState(), Blocks.STONE_SLAB.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 5, 1, 8, 5, 5, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); //Front wall this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 0, 2, 3, 0, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 0, 1, 1, 0, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 0, 0, 4, 0, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 3, 1, 0, 3, 4, 0, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 6, 0, 4, 6, Blocks.LOG.getDefaultState(), Blocks.LOG.getDefaultState(), false); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 3, 3, 1, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 3, 1, 2, 3, 3, 2, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 1, 3, 5, 3, 3, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); //Broken side wall this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 1, 0, 3, 5, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 3, 0, 1, 5, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 2, 5, 0, 2, 5, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); //Broken back wall this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 6, 5, 3, 6, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 6, 5, 1, 6, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 6, 3, 2, 6, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 3, 6, 1, 3, 6, Blocks.PLANKS.getDefaultState(), Blocks.AIR.getDefaultState(), false); // this.fillWithBlocks(worldIn, p_74875_3_, 5, 1, 0, 5, 3, 0, Blocks.OAK_FENCE.getDefaultState(), Blocks.OAK_FENCE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 9, 1, 0, 9, 3, 0, Blocks.OAK_FENCE.getDefaultState(), Blocks.OAK_FENCE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 6, 1, 4, 9, 4, 6, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 7, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.IRON_BARS.getDefaultState(), 9, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.IRON_BARS.getDefaultState(), 9, 2, 4, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 7, 2, 4, 8, 2, 5, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 6, 1, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.FURNACE.getDefaultState(), 6, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.FURNACE.getDefaultState(), 6, 3, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.DOUBLE_STONE_SLAB.getDefaultState(), 8, 1, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 4, 2, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 2, 1, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.WOODEN_PRESSURE_PLATE.getDefaultState(), 2, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 1, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), 2, 1, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.EAST), 1, 1, 4, p_74875_3_); if(!this.hasMadeChest && p_74875_3_.isVecInside(new BlockPos(this.getXWithOffset(5, 5), this.getYWithOffset(1), this.getZWithOffset(5, 5)))) { this.hasMadeChest = true; BlockPos blockpos = new BlockPos(this.getXWithOffset(5, 5), this.getYWithOffset(1), this.getZWithOffset(5, 5)); if(p_74875_3_.isVecInside(blockpos) && worldIn.getBlockState(blockpos).getBlock() != Blocks.CHEST) { IBlockState iblockstate = Blocks.CHEST.getDefaultState(); worldIn.setBlockState(blockpos, Blocks.CHEST.correctFacing(worldIn, blockpos, iblockstate), 2); TileEntity tileentity = worldIn.getTileEntity(blockpos); if(tileentity instanceof TileEntityChest) { //WeightedRandomChestContent.generateChestContents(p_180778_3_, p_180778_7_, (TileEntityChest)tileentity, p_180778_8_); FlansModApocalypse.getLootGenerator().fillVillageChest(rand, (TileEntityChest)tileentity); } } } int i; for(i = 6; i <= 8; ++i) { if(this.getBlockStateFromPos(worldIn, i, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, i, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), i, 0, -1, p_74875_3_); } } for(i = 0; i < 7; ++i) { for(int j = 0; j < 10; ++j) { this.clearCurrentPositionBlocksUpwards(worldIn, j, 6, i, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), j, -1, i, p_74875_3_); } } int[][] destruction = { {0, 0, 0, 0, 0, 0, 4, 4, 4, 4}, {0, 0, 0, 0, 0, 0, 0, 4, 4, 4}, {0, 0, 0, 0, 0, 0, 0, 0, 4, 4}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; destroyBuilding(worldIn, destruction, p_74875_3_); this.spawnVillagers(worldIn, p_74875_3_, 7, 1, 1, 1); return true; } protected int func_180779_c(int p_180779_1_, int p_180779_2_) { return 3; } } public static class House3 extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000530"; public House3() { } public House3(StructureAbandonedVillagePieces.Start p_i45561_1_, int p_i45561_2_, Random p_i45561_3_, StructureBoundingBox p_i45561_4_, EnumFacing p_i45561_5_) { super(p_i45561_1_, p_i45561_2_); this.setCoordBaseMode(p_i45561_5_); this.boundingBox = p_i45561_4_; } public static StructureAbandonedVillagePieces.House3 func_175849_a(StructureAbandonedVillagePieces.Start p_175849_0_, List p_175849_1_, Random p_175849_2_, int p_175849_3_, int p_175849_4_, int p_175849_5_, EnumFacing p_175849_6_, int p_175849_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175849_3_, p_175849_4_, p_175849_5_, 0, 0, 0, 9, 7, 12, p_175849_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175849_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.House3(p_175849_0_, p_175849_7_, p_175849_2_, structureboundingbox, p_175849_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 7 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 7, 4, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 1, 6, 8, 4, 10, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 0, 5, 8, 0, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 7, 0, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 0, 3, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 8, 0, 0, 8, 3, 10, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 0, 7, 2, 0, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 5, 2, 1, 5, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 2, 0, 6, 2, 3, 10, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 3, 0, 10, 7, 3, 10, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 0, 7, 3, 0, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 2, 5, 2, 3, 5, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 1, 8, 4, 1, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 4, 4, 3, 4, 4, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 5, 2, 8, 5, 3, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 0, 4, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 0, 4, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 4, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 4, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 4, 4, p_74875_3_); int k; int l; for(k = -1; k <= 2; ++k) { for(l = 0; l <= 8; ++l) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.WEST), l, 4 + k, k, p_74875_3_); if((k > -1 || l <= 1) && (k > 0 || l <= 3) && (k > 1 || l <= 4 || l >= 6)) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.SOUTH), l, 4 + k, 5 - k, p_74875_3_); } } } this.fillWithBlocks(worldIn, p_74875_3_, 3, 4, 5, 3, 4, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 7, 4, 2, 7, 4, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 5, 4, 4, 5, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 6, 5, 4, 6, 5, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 5, 6, 3, 5, 6, 10, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); int i1; for(l = 4; l >= 1; --l) { this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), l, 2 + l, 7 - l, p_74875_3_); for(i1 = 8 - l; i1 <= 10; ++i1) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.NORTH), l, 2 + l, i1, p_74875_3_); } } this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 6, 6, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 7, 5, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.EAST), 6, 6, 4, p_74875_3_); int j1; for(i1 = 6; i1 <= 8; ++i1) { for(j1 = 5; j1 <= 10; ++j1) { this.setBlockState(worldIn, Blocks.OAK_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, EnumFacing.EAST), i1, 12 - i1, j1, p_74875_3_); } } this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 0, 2, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 0, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 0, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 4, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 5, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 6, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 8, 2, 5, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 8, 2, 8, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 8, 2, 9, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 2, 2, 6, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 7, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 8, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 2, 2, 9, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 4, 4, 10, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 5, 4, 10, p_74875_3_); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 6, 4, 10, p_74875_3_); this.setBlockState(worldIn, Blocks.PLANKS.getDefaultState(), 5, 5, 10, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode()), 2, 3, 1, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, -1, 3, 2, -1, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); if(this.getBlockStateFromPos(worldIn, 2, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, 2, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getStateFromMeta(3), 2, 0, -1, p_74875_3_); } for(i1 = 0; i1 < 5; ++i1) { for(j1 = 0; j1 < 9; ++j1) { this.clearCurrentPositionBlocksUpwards(worldIn, j1, 7, i1, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), j1, -1, i1, p_74875_3_); } } for(i1 = 5; i1 < 11; ++i1) { for(j1 = 2; j1 < 9; ++j1) { this.clearCurrentPositionBlocksUpwards(worldIn, j1, 7, i1, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), j1, -1, i1, p_74875_3_); } } this.spawnVillagers(worldIn, p_74875_3_, 4, 1, 2, 2); return true; } } public static class House4Garden extends StructureAbandonedVillagePieces.Village { private boolean isRoofAccessible; private static final String __OBFID = "CL_00000523"; public House4Garden() { } public House4Garden(StructureAbandonedVillagePieces.Start p_i45566_1_, int p_i45566_2_, Random p_i45566_3_, StructureBoundingBox p_i45566_4_, EnumFacing p_i45566_5_) { super(p_i45566_1_, p_i45566_2_); this.setCoordBaseMode(p_i45566_5_); this.boundingBox = p_i45566_4_; this.isRoofAccessible = p_i45566_3_.nextBoolean(); } /** * (abstract) Helper method to write subclass data to NBT */ protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setBoolean("Terrace", this.isRoofAccessible); } /** * (abstract) Helper method to read subclass data from NBT */ protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.isRoofAccessible = p_143011_1_.getBoolean("Terrace"); } public static StructureAbandonedVillagePieces.House4Garden func_175858_a(StructureAbandonedVillagePieces.Start p_175858_0_, List p_175858_1_, Random p_175858_2_, int p_175858_3_, int p_175858_4_, int p_175858_5_, EnumFacing p_175858_6_, int p_175858_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175858_3_, p_175858_4_, p_175858_5_, 0, 0, 0, 5, 6, 5, p_175858_6_); return StructureComponent.findIntersecting(p_175858_1_, structureboundingbox) != null ? null : new StructureAbandonedVillagePieces.House4Garden(p_175858_0_, p_175858_7_, p_175858_2_, structureboundingbox, p_175858_6_); } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 6 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 4, 0, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 0, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 0, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 0, 1, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 1, 4, p_74875_3_); this.setBlockState(worldIn, Blocks.COBBLESTONE.getDefaultState(), 4, 2, 4, p_74875_3_); this.fillWithBlocks(worldIn, p_74875_3_, 0, 1, 1, 0, 1, 3, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 4, 1, 1, 4, 1, 2, Blocks.PLANKS.getDefaultState(), Blocks.PLANKS.getDefaultState(), false); if(this.getBlockStateFromPos(worldIn, 2, 0, -1, p_74875_3_).getMaterial() == Material.AIR && this.getBlockStateFromPos(worldIn, 2, -1, -1, p_74875_3_).getMaterial() != Material.AIR) { this.setBlockState(worldIn, Blocks.STONE_STAIRS.getStateFromMeta(3), 2, 0, -1, p_74875_3_); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 3, 3, 3, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); for(int i = 0; i < 5; ++i) { for(int j = 0; j < 5; ++j) { this.clearCurrentPositionBlocksUpwards(worldIn, j, 6, i, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), j, -1, i, p_74875_3_); } } this.spawnVillagers(worldIn, p_74875_3_, 1, 1, 2, 1); return true; } } public static class Path extends StructureAbandonedVillagePieces.Road { private int averageGroundLevel; private static final String __OBFID = "CL_00000528"; public Path() { } public Path(StructureAbandonedVillagePieces.Start p_i45562_1_, int p_i45562_2_, Random p_i45562_3_, StructureBoundingBox p_i45562_4_, EnumFacing p_i45562_5_) { super(p_i45562_1_, p_i45562_2_); this.setCoordBaseMode(p_i45562_5_); this.boundingBox = p_i45562_4_; this.averageGroundLevel = Math.max(p_i45562_4_.getXSize(), p_i45562_4_.getZSize()); } /** * (abstract) Helper method to write subclass data to NBT */ protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setInteger("Length", this.averageGroundLevel); } /** * (abstract) Helper method to read subclass data from NBT */ protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.averageGroundLevel = p_143011_1_.getInteger("Length"); } /** * Initiates construction of the Structure Component picked, at the current Location of StructGen */ public void buildComponent(StructureComponent p_74861_1_, List p_74861_2_, Random p_74861_3_) { boolean flag = false; int i; StructureComponent structurecomponent1; for(i = p_74861_3_.nextInt(5); i < this.averageGroundLevel - 8; i += 2 + p_74861_3_.nextInt(5)) { structurecomponent1 = this.getNextComponentNN((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, 0, i); if(structurecomponent1 != null) { i += Math.max(structurecomponent1.getBoundingBox().getXSize(), structurecomponent1.getBoundingBox().getZSize()); flag = true; } } for(i = p_74861_3_.nextInt(5); i < this.averageGroundLevel - 8; i += 2 + p_74861_3_.nextInt(5)) { structurecomponent1 = this.getNextComponentPP((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, 0, i); if(structurecomponent1 != null) { i += Math.max(structurecomponent1.getBoundingBox().getXSize(), structurecomponent1.getBoundingBox().getZSize()); flag = true; } } if(flag && p_74861_3_.nextInt(3) > 0 && this.getCoordBaseMode() != null) { switch(StructureAbandonedVillagePieces.SwitchEnumFacing.field_176064_a[this.getCoordBaseMode().ordinal()]) { case 1: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX - 1, this.boundingBox.minY, this.boundingBox.minZ, EnumFacing.WEST, this.getComponentType()); break; case 2: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX - 1, this.boundingBox.minY, this.boundingBox.maxZ - 2, EnumFacing.WEST, this.getComponentType()); break; case 3: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX, this.boundingBox.minY, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType()); break; case 4: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.maxX - 2, this.boundingBox.minY, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType()); } } if(flag && p_74861_3_.nextInt(3) > 0 && this.getCoordBaseMode() != null) { switch(StructureAbandonedVillagePieces.SwitchEnumFacing.field_176064_a[this.getCoordBaseMode().ordinal()]) { case 1: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.maxX + 1, this.boundingBox.minY, this.boundingBox.minZ, EnumFacing.EAST, this.getComponentType()); break; case 2: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.maxX + 1, this.boundingBox.minY, this.boundingBox.maxZ - 2, EnumFacing.EAST, this.getComponentType()); break; case 3: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX, this.boundingBox.minY, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType()); break; case 4: StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.maxX - 2, this.boundingBox.minY, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType()); } } } public static StructureBoundingBox func_175848_a(StructureAbandonedVillagePieces.Start p_175848_0_, List p_175848_1_, Random p_175848_2_, int p_175848_3_, int p_175848_4_, int p_175848_5_, EnumFacing p_175848_6_) { for(int l = 7 * MathHelper.getInt(p_175848_2_, 3, 5); l >= 7; l -= 7) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175848_3_, p_175848_4_, p_175848_5_, 0, 0, 0, 3, 3, l, p_175848_6_); if(StructureComponent.findIntersecting(p_175848_1_, structureboundingbox) == null) { return structureboundingbox; } } return null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { IBlockState iblockstate = this.func_175847_a(Blocks.GRAVEL.getDefaultState()); IBlockState iblockstate1 = this.func_175847_a(Blocks.COBBLESTONE.getDefaultState()); for(int i = this.boundingBox.minX; i <= this.boundingBox.maxX; ++i) { for(int j = this.boundingBox.minZ; j <= this.boundingBox.maxZ; ++j) { BlockPos blockpos = new BlockPos(i, 64, j); if(p_74875_3_.isVecInside(blockpos)) { blockpos = worldIn.getTopSolidOrLiquidBlock(blockpos).down(); worldIn.setBlockState(blockpos, iblockstate, 2); worldIn.setBlockState(blockpos.down(), iblockstate1, 2); } } } return true; } } public static class PieceWeight { /** * The Class object for the represantation of this village piece. */ public Class villagePieceClass; public final int villagePieceWeight; public int villagePiecesSpawned; public int villagePiecesLimit; private static final String __OBFID = "CL_00000521"; public PieceWeight(Class p_i2098_1_, int p_i2098_2_, int p_i2098_3_) { this.villagePieceClass = p_i2098_1_; this.villagePieceWeight = p_i2098_2_; this.villagePiecesLimit = p_i2098_3_; } public boolean canSpawnMoreVillagePiecesOfType(int p_75085_1_) { return this.villagePiecesLimit == 0 || this.villagePiecesSpawned < this.villagePiecesLimit; } public boolean canSpawnMoreVillagePieces() { return this.villagePiecesLimit == 0 || this.villagePiecesSpawned < this.villagePiecesLimit; } } public abstract static class Road extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000532"; public Road() { } protected Road(StructureAbandonedVillagePieces.Start p_i2108_1_, int p_i2108_2_) { super(p_i2108_1_, p_i2108_2_); } } public static class Start extends StructureAbandonedVillagePieces.Well { public BiomeProvider worldChunkMngr; /** * Boolean that determines if the village is in a desert or not. */ public boolean inDesert; /** * World terrain type, 0 for normal, 1 for flap map */ public int terrainType; public StructureAbandonedVillagePieces.PieceWeight structVillagePieceWeight; /** * Contains List of all spawnable Structure Piece Weights. If no more Pieces of a type can be spawned, they * are removed from this list */ public List structureVillageWeightedPieceList; public List pendingHouses = Lists.newArrayList(); public List pendingRoads = Lists.newArrayList(); private static final String __OBFID = "CL_00000527"; public Biome biome; public Start() { } public Start(BiomeProvider p_i2104_1_, int p_i2104_2_, Random p_i2104_3_, int p_i2104_4_, int p_i2104_5_, List p_i2104_6_, int p_i2104_7_) { super(null, 0, p_i2104_3_, p_i2104_4_, p_i2104_5_); this.worldChunkMngr = p_i2104_1_; this.structureVillageWeightedPieceList = p_i2104_6_; this.terrainType = p_i2104_7_; Biome biome = p_i2104_1_.getBiome(new BlockPos(p_i2104_4_, 0, p_i2104_5_), Biomes.DEFAULT); this.inDesert = biome == Biomes.DESERT || biome == Biomes.DESERT_HILLS; this.biome = biome; this.func_175846_a(this.inDesert); } public BiomeProvider getBiomeProvider() { return this.worldChunkMngr; } } static final class SwitchEnumFacing { static final int[] field_176064_a = new int[EnumFacing.values().length]; private static final String __OBFID = "CL_00001968"; static { try { field_176064_a[EnumFacing.NORTH.ordinal()] = 1; } catch(NoSuchFieldError var4) { } try { field_176064_a[EnumFacing.SOUTH.ordinal()] = 2; } catch(NoSuchFieldError var3) { } try { field_176064_a[EnumFacing.WEST.ordinal()] = 3; } catch(NoSuchFieldError var2) { } try { field_176064_a[EnumFacing.EAST.ordinal()] = 4; } catch(NoSuchFieldError var1) { } } } public static class Torch extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000520"; public Torch() { } public Torch(StructureAbandonedVillagePieces.Start p_i45568_1_, int p_i45568_2_, Random p_i45568_3_, StructureBoundingBox p_i45568_4_, EnumFacing p_i45568_5_) { super(p_i45568_1_, p_i45568_2_); this.setCoordBaseMode(p_i45568_5_); this.boundingBox = p_i45568_4_; } public static StructureBoundingBox func_175856_a(StructureAbandonedVillagePieces.Start p_175856_0_, List p_175856_1_, Random p_175856_2_, int p_175856_3_, int p_175856_4_, int p_175856_5_, EnumFacing p_175856_6_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175856_3_, p_175856_4_, p_175856_5_, 0, 0, 0, 3, 4, 2, p_175856_6_); return StructureComponent.findIntersecting(p_175856_1_, structureboundingbox) != null ? null : structureboundingbox; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 4 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 2, 3, 1, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 1, 0, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 1, 1, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 1, 2, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.WOOL.getStateFromMeta(EnumDyeColor.WHITE.getDyeDamage()), 1, 3, 0, p_74875_3_); boolean flag = this.getCoordBaseMode() == EnumFacing.EAST || this.getCoordBaseMode() == EnumFacing.NORTH; this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode().rotateY()), flag ? 2 : 0, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode()), 1, 3, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode().rotateYCCW()), flag ? 0 : 2, 3, 0, p_74875_3_); this.setBlockState(worldIn, Blocks.TORCH.getDefaultState().withProperty(BlockTorch.FACING, this.getCoordBaseMode().getOpposite()), 1, 3, -1, p_74875_3_); return true; } } public abstract static class Village extends StructureComponent { protected int field_143015_k = -1; /** * The number of villagers that have been spawned in this component. */ private int villagersSpawned; private boolean field_143014_b; private static final String __OBFID = "CL_00000531"; private StructureAbandonedVillagePieces.Start startPiece; public Village() { } protected Village(StructureAbandonedVillagePieces.Start p_i2107_1_, int p_i2107_2_) { super(p_i2107_2_); if(p_i2107_1_ != null) { this.field_143014_b = p_i2107_1_.inDesert; startPiece = p_i2107_1_; } } /** * (abstract) Helper method to write subclass data to NBT */ @Override protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { p_143012_1_.setInteger("HPos", this.field_143015_k); p_143012_1_.setInteger("VCount", this.villagersSpawned); p_143012_1_.setBoolean("Desert", this.field_143014_b); } /** * (abstract) Helper method to read subclass data from NBT */ @Override protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager p_143011_2_) { this.field_143015_k = p_143011_1_.getInteger("HPos"); this.villagersSpawned = p_143011_1_.getInteger("VCount"); this.field_143014_b = p_143011_1_.getBoolean("Desert"); } /** * Gets the next village component, with the bounding box shifted -1 in the X and Z direction. */ protected StructureComponent getNextComponentNN(StructureAbandonedVillagePieces.Start p_74891_1_, List p_74891_2_, Random p_74891_3_, int p_74891_4_, int p_74891_5_) { if(this.getCoordBaseMode() != null) { switch(StructureAbandonedVillagePieces.SwitchEnumFacing.field_176064_a[this.getCoordBaseMode().ordinal()]) { case 1: return StructureAbandonedVillagePieces.func_176066_d(p_74891_1_, p_74891_2_, p_74891_3_, this.boundingBox.minX - 1, this.boundingBox.minY + p_74891_4_, this.boundingBox.minZ + p_74891_5_, EnumFacing.WEST, this.getComponentType()); case 2: return StructureAbandonedVillagePieces.func_176066_d(p_74891_1_, p_74891_2_, p_74891_3_, this.boundingBox.minX - 1, this.boundingBox.minY + p_74891_4_, this.boundingBox.minZ + p_74891_5_, EnumFacing.WEST, this.getComponentType()); case 3: return StructureAbandonedVillagePieces.func_176066_d(p_74891_1_, p_74891_2_, p_74891_3_, this.boundingBox.minX + p_74891_5_, this.boundingBox.minY + p_74891_4_, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType()); case 4: return StructureAbandonedVillagePieces.func_176066_d(p_74891_1_, p_74891_2_, p_74891_3_, this.boundingBox.minX + p_74891_5_, this.boundingBox.minY + p_74891_4_, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType()); } } return null; } /** * Gets the next village component, with the bounding box shifted +1 in the X and Z direction. */ protected StructureComponent getNextComponentPP(StructureAbandonedVillagePieces.Start p_74894_1_, List p_74894_2_, Random p_74894_3_, int p_74894_4_, int p_74894_5_) { if(this.getCoordBaseMode() != null) { switch(StructureAbandonedVillagePieces.SwitchEnumFacing.field_176064_a[this.getCoordBaseMode().ordinal()]) { case 1: return StructureAbandonedVillagePieces.func_176066_d(p_74894_1_, p_74894_2_, p_74894_3_, this.boundingBox.maxX + 1, this.boundingBox.minY + p_74894_4_, this.boundingBox.minZ + p_74894_5_, EnumFacing.EAST, this.getComponentType()); case 2: return StructureAbandonedVillagePieces.func_176066_d(p_74894_1_, p_74894_2_, p_74894_3_, this.boundingBox.maxX + 1, this.boundingBox.minY + p_74894_4_, this.boundingBox.minZ + p_74894_5_, EnumFacing.EAST, this.getComponentType()); case 3: return StructureAbandonedVillagePieces.func_176066_d(p_74894_1_, p_74894_2_, p_74894_3_, this.boundingBox.minX + p_74894_5_, this.boundingBox.minY + p_74894_4_, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType()); case 4: return StructureAbandonedVillagePieces.func_176066_d(p_74894_1_, p_74894_2_, p_74894_3_, this.boundingBox.minX + p_74894_5_, this.boundingBox.minY + p_74894_4_, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType()); } } return null; } /** * Discover the y coordinate that will serve as the ground level of the supplied BoundingBox. (A median of * all the levels in the BB's horizontal rectangle). */ protected int getAverageGroundLevel(World worldIn, StructureBoundingBox p_74889_2_) { int i = 0; int j = 0; for(int k = this.boundingBox.minZ; k <= this.boundingBox.maxZ; ++k) { for(int l = this.boundingBox.minX; l <= this.boundingBox.maxX; ++l) { BlockPos blockpos = new BlockPos(l, 64, k); if(p_74889_2_.isVecInside(blockpos)) { i += Math.max(worldIn.getTopSolidOrLiquidBlock(blockpos).getY(), worldIn.provider.getAverageGroundLevel()); ++j; } } } if(j == 0) { return -1; } else { return i / j; } } protected static boolean canVillageGoDeeper(StructureBoundingBox p_74895_0_) { return p_74895_0_ != null && p_74895_0_.minY > 10; } /** * Spawns a number of villagers in this component. Parameters: world, component bounding box, x offset, y * offset, z offset, number of villagers */ protected void spawnVillagers(World worldIn, StructureBoundingBox p_74893_2_, int p_74893_3_, int p_74893_4_, int p_74893_5_, int p_74893_6_) { } protected int func_180779_c(int p_180779_1_, int p_180779_2_) { return p_180779_2_; } protected IBlockState func_175847_a(IBlockState p_175847_1_) { BiomeEvent.GetVillageBlockID event = new BiomeEvent.GetVillageBlockID(startPiece == null ? null : startPiece.biome, p_175847_1_); MinecraftForge.TERRAIN_GEN_BUS.post(event); if(event.getResult() == Result.DENY) return event.getReplacement(); if(this.field_143014_b) { if(p_175847_1_.getBlock() == Blocks.LOG || p_175847_1_.getBlock() == Blocks.LOG2) { return Blocks.SANDSTONE.getDefaultState(); } if(p_175847_1_.getBlock() == Blocks.COBBLESTONE) { return Blocks.SANDSTONE.getStateFromMeta(BlockSandStone.EnumType.DEFAULT.getMetadata()); } if(p_175847_1_.getBlock() == Blocks.PLANKS) { return Blocks.SANDSTONE.getStateFromMeta(BlockSandStone.EnumType.SMOOTH.getMetadata()); } if(p_175847_1_.getBlock() == Blocks.OAK_STAIRS) { return Blocks.SANDSTONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, p_175847_1_.getValue(BlockStairs.FACING)); } if(p_175847_1_.getBlock() == Blocks.STONE_STAIRS) { return Blocks.SANDSTONE_STAIRS.getDefaultState().withProperty(BlockStairs.FACING, p_175847_1_.getValue(BlockStairs.FACING)); } if(p_175847_1_.getBlock() == Blocks.GRAVEL) { return Blocks.SANDSTONE.getDefaultState(); } } return p_175847_1_; } protected void setBlockState(World worldIn, IBlockState p_175811_2_, int p_175811_3_, int p_175811_4_, int p_175811_5_, StructureBoundingBox p_175811_6_) { IBlockState iblockstate1 = this.func_175847_a(p_175811_2_); super.setBlockState(worldIn, iblockstate1, p_175811_3_, p_175811_4_, p_175811_5_, p_175811_6_); } protected void fillWithBlocks(World worldIn, StructureBoundingBox box, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, IBlockState outerBlock, IBlockState innerBlock, boolean doNotReplaceAir) { IBlockState outerBlock2 = this.func_175847_a(outerBlock); IBlockState innerBlock2 = this.func_175847_a(innerBlock); super.fillWithBlocks(worldIn, box, minX, minY, minZ, maxX, maxY, maxZ, outerBlock2, innerBlock2, doNotReplaceAir); } protected void replaceAirAndLiquidDownwards(World worldIn, IBlockState p_175808_2_, int p_175808_3_, int p_175808_4_, int p_175808_5_, StructureBoundingBox p_175808_6_) { IBlockState iblockstate1 = this.func_175847_a(p_175808_2_); super.replaceAirAndLiquidDownwards(worldIn, iblockstate1, p_175808_3_, p_175808_4_, p_175808_5_, p_175808_6_); } protected void func_175846_a(boolean p_175846_1_) { this.field_143014_b = p_175846_1_; } protected void destroyBuilding(World world, int x, int z, int blocksToDestroy, StructureBoundingBox box) { BlockPos blockpos = new BlockPos(this.getXWithOffset(z, x), this.boundingBox.maxY, this.getZWithOffset(z, x)); for(int i = 0; i < blocksToDestroy; i++) { world.setBlockState(blockpos, Blocks.AIR.getDefaultState(), 2); blockpos = blockpos.down(); } } protected void destroyBuilding(World world, int[][] blocksToDestroy, StructureBoundingBox box) { for(int i = 0; i < blocksToDestroy.length; i++) for(int j = 0; j < blocksToDestroy[i].length; j++) destroyBuilding(world, i, j, blocksToDestroy[i][j], box); } } public static class Well extends StructureAbandonedVillagePieces.Village { private static final String __OBFID = "CL_00000533"; public Well() { } public Well(StructureAbandonedVillagePieces.Start p_i2109_1_, int p_i2109_2_, Random p_i2109_3_, int p_i2109_4_, int p_i2109_5_) { super(p_i2109_1_, p_i2109_2_); this.setCoordBaseMode(EnumFacing.Plane.HORIZONTAL.random(p_i2109_3_)); switch(StructureAbandonedVillagePieces.SwitchEnumFacing.field_176064_a[this.getCoordBaseMode().ordinal()]) { case 1: case 2: this.boundingBox = new StructureBoundingBox(p_i2109_4_, 64, p_i2109_5_, p_i2109_4_ + 6 - 1, 78, p_i2109_5_ + 6 - 1); break; default: this.boundingBox = new StructureBoundingBox(p_i2109_4_, 64, p_i2109_5_, p_i2109_4_ + 6 - 1, 78, p_i2109_5_ + 6 - 1); } } /** * Initiates construction of the Structure Component picked, at the current Location of StructGen */ public void buildComponent(StructureComponent p_74861_1_, List p_74861_2_, Random p_74861_3_) { StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX - 1, this.boundingBox.maxY - 4, this.boundingBox.minZ + 1, EnumFacing.WEST, this.getComponentType()); StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.maxX + 1, this.boundingBox.maxY - 4, this.boundingBox.minZ + 1, EnumFacing.EAST, this.getComponentType()); StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX + 1, this.boundingBox.maxY - 4, this.boundingBox.minZ - 1, EnumFacing.NORTH, this.getComponentType()); StructureAbandonedVillagePieces.func_176069_e((StructureAbandonedVillagePieces.Start)p_74861_1_, p_74861_2_, p_74861_3_, this.boundingBox.minX + 1, this.boundingBox.maxY - 4, this.boundingBox.maxZ + 1, EnumFacing.SOUTH, this.getComponentType()); } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 3, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 4, 12, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.setBlockState(worldIn, Blocks.FLOWING_WATER.getDefaultState(), 2, 1, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 12, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 3, 12, 2, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 2, 12, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.AIR.getDefaultState(), 3, 12, 3, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 1, 13, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 4, 13, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 4, 14, 1, p_74875_3_); this.setBlockState(worldIn, Blocks.OAK_FENCE.getDefaultState(), 4, 13, 4, p_74875_3_); for(int i = 0; i <= 5; ++i) { for(int j = 0; j <= 5; ++j) { if(j == 0 || j == 5 || i == 0 || i == 5) { this.setBlockState(worldIn, Blocks.GRAVEL.getDefaultState(), j, 11, i, p_74875_3_); this.clearCurrentPositionBlocksUpwards(worldIn, j, 12, i, p_74875_3_); } } } return true; } } public static class WoodHut extends StructureAbandonedVillagePieces.Village { private boolean isTallHouse; private int tablePosition; private static final String __OBFID = "CL_00000524"; public WoodHut() { } public WoodHut(StructureAbandonedVillagePieces.Start p_i45565_1_, int p_i45565_2_, Random p_i45565_3_, StructureBoundingBox p_i45565_4_, EnumFacing p_i45565_5_) { super(p_i45565_1_, p_i45565_2_); this.setCoordBaseMode(p_i45565_5_); this.boundingBox = p_i45565_4_; this.isTallHouse = p_i45565_3_.nextBoolean(); this.tablePosition = p_i45565_3_.nextInt(3); } /** * (abstract) Helper method to write subclass data to NBT */ @Override protected void writeStructureToNBT(NBTTagCompound p_143012_1_) { super.writeStructureToNBT(p_143012_1_); p_143012_1_.setInteger("T", this.tablePosition); p_143012_1_.setBoolean("C", this.isTallHouse); } /** * (abstract) Helper method to read subclass data from NBT */ @Override protected void readStructureFromNBT(NBTTagCompound p_143011_1_, TemplateManager man) { super.readStructureFromNBT(p_143011_1_, man); this.tablePosition = p_143011_1_.getInteger("T"); this.isTallHouse = p_143011_1_.getBoolean("C"); } public static StructureAbandonedVillagePieces.WoodHut func_175853_a(StructureAbandonedVillagePieces.Start p_175853_0_, List p_175853_1_, Random p_175853_2_, int p_175853_3_, int p_175853_4_, int p_175853_5_, EnumFacing p_175853_6_, int p_175853_7_) { StructureBoundingBox structureboundingbox = StructureBoundingBox.getComponentToAddBoundingBox(p_175853_3_, p_175853_4_, p_175853_5_, 0, 0, 0, 4, 6, 5, p_175853_6_); return canVillageGoDeeper(structureboundingbox) && StructureComponent.findIntersecting(p_175853_1_, structureboundingbox) == null ? new StructureAbandonedVillagePieces.WoodHut(p_175853_0_, p_175853_7_, p_175853_2_, structureboundingbox, p_175853_6_) : null; } /** * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes * Mineshafts at the end, it adds Fences... */ public boolean addComponentParts(World worldIn, Random p_74875_2_, StructureBoundingBox p_74875_3_) { if(this.field_143015_k < 0) { this.field_143015_k = this.getAverageGroundLevel(worldIn, p_74875_3_); if(this.field_143015_k < 0) { return true; } this.boundingBox.offset(0, this.field_143015_k - this.boundingBox.maxY + 6 - 1, 0); } this.fillWithBlocks(worldIn, p_74875_3_, 1, 1, 1, 3, 5, 4, Blocks.AIR.getDefaultState(), Blocks.AIR.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 0, 0, 0, 3, 0, 4, Blocks.COBBLESTONE.getDefaultState(), Blocks.COBBLESTONE.getDefaultState(), false); this.fillWithBlocks(worldIn, p_74875_3_, 1, 0, 1, 2, 0, 3, Blocks.DIRT.getDefaultState(), Blocks.DIRT.getDefaultState(), false); this.setBlockState(worldIn, Blocks.LOG.getDefaultState(), 1, 1, 0, p_74875_3_); for(int i = 0; i < 5; ++i) { for(int j = 0; j < 4; ++j) { this.clearCurrentPositionBlocksUpwards(worldIn, j, 6, i, p_74875_3_); this.replaceAirAndLiquidDownwards(worldIn, Blocks.COBBLESTONE.getDefaultState(), j, -1, i, p_74875_3_); } } this.spawnVillagers(worldIn, p_74875_3_, 1, 1, 2, 1); return true; } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenAbandonedPortal.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.entity.EntityAIMecha; import com.flansmod.common.BlockItemHolder; import com.flansmod.common.FlansMod; import com.flansmod.common.ModuloHelper; import com.flansmod.common.TileEntityItemHolder; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.mechas.EnumMechaSlotType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ShootableType; import net.minecraft.block.BlockChest; import net.minecraft.block.BlockFlowerPot; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityBrewingStand; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; public class WorldGenAbandonedPortal extends WorldGenFlan { @Override public boolean generate(World world, Random rand, BlockPos pos) { int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); // Base replaceEmpty(world, x + 0, y - 3, z + 0, x + 12, y - 2, z + 12, FlansModApocalypse.blockLabStone.getDefaultState()); replaceEmpty(world, x + 1, y - 2, z + 1, x + 11, y - 1, z + 11, FlansModApocalypse.blockLabStone.getDefaultState()); replaceEmpty(world, x + 2, y - 1, z + 2, x + 10, y - 0, z + 10, FlansModApocalypse.blockLabStone.getDefaultState()); replaceEmpty(world, x + 3, y - 0, z + 3, x + 9, y + 1, z + 9, FlansModApocalypse.blockLabStone.getDefaultState()); //Teleporter Room { fillArea(world, x + 4, y + 1, z + 4, x + 8, y + 2, z + 8, Blocks.OBSIDIAN.getDefaultState()); for(int n = 0; n < 2; n++) { world.setBlockState(new BlockPos(x + 4 + rand.nextInt(2) * 3, y + 2, z + 4 + rand.nextInt(2) * 3), FlansModApocalypse.blockPowerCube.getDefaultState()); } BlockPos chestPos = new BlockPos(x + 3 + rand.nextInt(2) * 5, y + 1, z + 3 + rand.nextInt(2) * 5); world.setBlockState(chestPos, Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, EnumFacing.SOUTH)); //Fill chests TileEntity tileentity = world.getTileEntity(chestPos); if(tileentity instanceof TileEntityChest) { TileEntityChest chest = (TileEntityChest)tileentity; FlansModApocalypse.getLootGenerator().fillWeaponChest(rand, chest); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(Blocks.OBSIDIAN, rand.nextInt(8) + 1)); chest.setInventorySlotContents(rand.nextInt(chest.getSizeInventory()), new ItemStack(FlansModApocalypse.itemBlockPowerCube)); } } return false; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenBossPillar.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import com.flansmod.common.ModuloHelper; import net.minecraft.block.BlockColored; import net.minecraft.init.Blocks; import net.minecraft.item.EnumDyeColor; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenerator; public class WorldGenBossPillar extends WorldGenerator { public static final double kPillarInnerEdge = 12d; public static final double kPillarInnerRadius = kPillarInnerEdge * Math.sqrt(2); public static final double kPillarOuterEdge = 300d; public static final double kPillarMaxHeight = 240d; public static final double kBossSpawnHeight = 220d; //private static final double kA = kPillarMaxHeight * Math.exp(kPillarInnerEdge); private static final double kB = -Math.log(kPillarMaxHeight) / (kPillarOuterEdge - kPillarInnerRadius); private static final double kA = Math.exp(-kB * kPillarOuterEdge); @Override public boolean generate(World world, Random rand, BlockPos pos) { for(int i = 8; i < 24; i++) { for(int k = 8; k < 24; k++) { BlockPos p = pos.add(i, 0, k); if(Math.abs(p.getX()) > kPillarInnerEdge && Math.abs(p.getZ()) > kPillarInnerEdge) { double dist = p.getDistance(0, 0, 0); double theta = Math.atan2(p.getZ(), p.getX()); double pillarBaseHeight = kA * Math.exp(kB * dist); if(pillarBaseHeight > 1d) { BlockPos downIterate = p.add(0,pillarBaseHeight,0); //world.setBlockState(p.add(0,pillarBaseHeight,0), Blocks.BEDROCK.getDefaultState()); while(world.isAirBlock(downIterate) && downIterate.getY() > 1d) { if((Math.abs(p.getX()) == kPillarInnerEdge + 1 || Math.abs(p.getZ()) == kPillarInnerEdge + 1) && rand.nextInt(500) == 0) { world.setBlockState(downIterate, Blocks.MAGMA.getDefaultState()); } else { world.setBlockState(downIterate, Blocks.BEDROCK.getDefaultState()); } downIterate = downIterate.down(); } } } } } return false; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenDeadTree.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class WorldGenDeadTree extends WorldGenFlan { @Override public boolean generate(World world, Random rand, BlockPos pos) { for(; pos.getY() < 256; pos = pos.up()) { if(world.isAirBlock(pos) && world.isSideSolid(pos.down(), EnumFacing.UP)) { int treeHeight = rand.nextInt(3) + 3; for(int i = 0; i < treeHeight; i++) { world.setBlockState(pos.add(0, i, 0), Blocks.LOG.getDefaultState()); } for(int j = 0; j < rand.nextInt(2) + 2; j++) { int dx = 0, dy = 0, dz = 0; int branchXDir = rand.nextInt(3) - 1; int branchZDir = rand.nextInt(3) - 1; int branchStartPoint = rand.nextInt(treeHeight / 2) + treeHeight / 2; for(int i = 0; i < treeHeight; i++) { if(rand.nextBoolean()) { dx += branchXDir; dz += branchZDir; } dy++; world.setBlockState(pos.add(dx, dy + treeHeight - 1, dz), Blocks.LOG.getDefaultState()); } } break; } } return false; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenDyeFactory.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import net.minecraft.block.BlockLog; import net.minecraft.entity.item.EntityArmorStand; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.world.BiomeApocalypse; import com.flansmod.common.FlansMod; public class WorldGenDyeFactory extends WorldGenFlan { @Override public boolean generate(World world, Random rand, BlockPos pos) { if(world.getBiome(pos) != BiomeApocalypse.deepCanyon) return false; int maxHeight = 0; int minHeight = 128; for(int i = 0; i < 16; i++) { for(int k = 0; k < 16; k++) { //Find the ground height at this block BlockPos testPos = new BlockPos(pos.getX() + i, 128, pos.getZ() + k); for(; world.isAirBlock(testPos); testPos = testPos.down()) { } int height = testPos.getY(); //Compare to our existing min and max if(height < minHeight) minHeight = height; if(height > maxHeight) maxHeight = height; } } //Chunk is too bumpy if(maxHeight - minHeight > 3) { return false; } int x = pos.getX(); int y = maxHeight + 1; int z = pos.getZ(); //Set our base fillArea(world, x, minHeight, z, x + 16, maxHeight + 1, z + 16, Blocks.SAND.getStateFromMeta(1)); //Build walls fillArea(world, x, y, z, x + 6, y + 1, z + 16, Blocks.COBBLESTONE.getDefaultState()); fillArea(world, x, y + 1, z, x + 6, y + 5, z + 16, Blocks.PLANKS.getDefaultState()); //Horizontal logs fillArea(world, x, y + 4, z, x + 6, y + 5, z + 1, Blocks.LOG.getDefaultState().withProperty(BlockLog.LOG_AXIS, BlockLog.EnumAxis.X)); fillArea(world, x, y + 4, z + 15, x + 6, y + 5, z + 16, Blocks.LOG.getDefaultState().withProperty(BlockLog.LOG_AXIS, BlockLog.EnumAxis.X)); fillArea(world, x, y + 4, z, x + 1, y + 5, z + 16, Blocks.LOG.getDefaultState().withProperty(BlockLog.LOG_AXIS, BlockLog.EnumAxis.Z)); fillArea(world, x + 5, y + 4, z, x + 6, y + 5, z + 16, Blocks.LOG.getDefaultState().withProperty(BlockLog.LOG_AXIS, BlockLog.EnumAxis.Z)); //Vertical logs for(int i = 0; i < 6; i += 5) for(int k = 0; k < 16; k += 5) fillArea(world, x + i, y + 1, z + k, x + i + 1, y + 6, z + k + 1, Blocks.LOG.getDefaultState()); //Hollow out fillArea(world, x + 1, y, z + 1, x + 5, y + 4, z + 15, Blocks.AIR.getDefaultState()); //Open door fillArea(world, x + 5, y, z + 6, x + 6, y + 4, z + 10, Blocks.AIR.getDefaultState()); //Add tables (two random, one gun modification and one vehicle crafting) world.setBlockState(new BlockPos(x + 1, y, z + 6), FlansModApocalypse.getLootGenerator().getRandomWeaponBox(rand).getDefaultState()); world.setBlockState(new BlockPos(x + 1, y, z + 7), FlansMod.workbench.getDefaultState()); world.setBlockState(new BlockPos(x + 1, y, z + 8), FlansMod.workbench.getStateFromMeta(1)); world.setBlockState(new BlockPos(x + 1, y, z + 9), FlansModApocalypse.getLootGenerator().getRandomWeaponBox(rand).getDefaultState()); //Build chest racks for(int i = 1; i < 6; i += 3) for(int k = 1; k < 6; k += 3) fillArea(world, x + i, y, z + k, x + i + 1, y + 3, z + k + 1, Blocks.OAK_FENCE.getDefaultState()); for(int j = 0; j < 3; j += 2) { fillArea(world, x + 1, y + j, z + 2, x + 2, y + j + 1, z + 4, Blocks.CHEST.getDefaultState()); fillArea(world, x + 4, y + j, z + 2, x + 5, y + j + 1, z + 4, Blocks.CHEST.getDefaultState()); fillArea(world, x + 2, y + j, z + 1, x + 4, y + j + 1, z + 2, Blocks.CHEST.getDefaultState()); fillChest(world, rand, x + 1, y + j, z + 2); fillChest(world, rand, x + 1, y + j, z + 3); fillChest(world, rand, x + 4, y + j, z + 2); fillChest(world, rand, x + 4, y + j, z + 3); fillChest(world, rand, x + 2, y + j, z + 1); fillChest(world, rand, x + 3, y + j, z + 1); } //Build sewing table fillArea(world, x + 1, y, z + 11, x + 2, y + 1, z + 15, Blocks.CRAFTING_TABLE.getDefaultState()); fillArea(world, x + 1, y, z + 12, x + 2, y + 1, z + 14, Blocks.WOODEN_SLAB.getStateFromMeta(8)); for(int k = 0; k < 2; k++) { EntityArmorStand stand = new EntityArmorStand(world, x + 4.5D, y, z + 11.5D + k * 2D); stand.rotationYaw = 90F; FlansModApocalypse.getLootGenerator().dressMeUp(stand, rand); world.spawnEntity(stand); } //Build vats for(int k = 1; k < 16; k += 5) buildVat(world, rand, x + 11, y, z + k); return true; } private void fillChest(World world, Random rand, int i, int j, int k) { TileEntityChest chest = (TileEntityChest)world.getTileEntity(new BlockPos(i, j, k)); FlansModApocalypse.getLootGenerator().fillDyeFactoryChest(chest, rand); } private void buildVat(World world, Random rand, int x, int y, int z) { boolean tall = rand.nextBoolean(); //Create square tank fillArea(world, x, y, z, x + 4, y + 1, z + 4, Blocks.COBBLESTONE.getDefaultState()); fillArea(world, x, y + 1, z, x + 4, y + (tall ? 3 : 2), z + 4, Blocks.PLANKS.getDefaultState()); //Cut out corners for(int i = 0; i < 4; i += 3) for(int k = 0; k < 4; k += 3) fillArea(world, x + i, y, z + k, x + i + 1, y + 3, z + k + 1, Blocks.AIR.getDefaultState()); //Fill tank with wool fillArea(world, x + 1, y, z + 1, x + 3, y + 3, z + 3, Blocks.AIR.getDefaultState()); fillArea(world, x + 1, y, z + 1, x + 3, y + (tall ? 2 : 1), z + 3, Blocks.WOOL.getStateFromMeta(rand.nextInt(16))); } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenFlan.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenerator; public abstract class WorldGenFlan extends WorldGenerator { protected void fillArea(World world, int x1, int y1, int z1, int x2, int y2, int z2, IBlockState state) { fillArea(world, x1, y1, z1, x2, y2, z2, state, state); } protected void fillArea(World world, int x1, int y1, int z1, int x2, int y2, int z2, IBlockState state, IBlockState innerState) { for(int i = x1; i < x2; i++) { for(int j = y1; j < y2; j++) { for(int k = z1; k < z2; k++) { if(i == x1 || i == x2 - 1 || j == y1 || j == y2 - 1 || k == z1 || k == z2 - 1) world.setBlockState(new BlockPos(i, j, k), state, 2); else world.setBlockState(new BlockPos(i, j, k), innerState, 2); } } } } protected void replaceEmpty(World world, int x1, int y1, int z1, int x2, int y2, int z2, IBlockState state) { for(int i = x1; i < x2; i++) { for(int j = y1; j < y2; j++) { for(int k = z1; k < z2; k++) { BlockPos pos = new BlockPos(i, j, k); if(world.isAirBlock(pos)) world.setBlockState(pos, state, 2); } } } } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenResearchLab.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import net.minecraft.block.BlockChest; import net.minecraft.block.BlockFlowerPot; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityBrewingStand; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.apocalypse.common.entity.EntityAIMecha; import com.flansmod.common.BlockItemHolder; import com.flansmod.common.FlansMod; import com.flansmod.common.ModuloHelper; import com.flansmod.common.TileEntityItemHolder; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.mechas.EnumMechaSlotType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.parts.PartType; public class WorldGenResearchLab extends WorldGenFlan { @Override public boolean generate(World world, Random rand, BlockPos pos) { int chunkX = ModuloHelper.divide(pos.getX(), 16); int chunkZ = ModuloHelper.divide(pos.getZ(), 16); int structureX = ModuloHelper.divide(chunkX, 3); int structureZ = ModuloHelper.divide(chunkZ, 3); int pieceX = ModuloHelper.modulo(chunkX, 3); int pieceZ = ModuloHelper.modulo(chunkZ, 3); int topLayerHeight = 99; //Generate empty rooms for(int i = (pieceX == 1 & pieceZ == 1 ? -1 : 0); i < 8; i++) { fillArea(world, chunkX * 16, topLayerHeight - 8 * i, chunkZ * 16, chunkX * 16 + 16, topLayerHeight - 8 * i + 8, chunkZ * 16 + 16, FlansModApocalypse.blockLabStone.getDefaultState(), Blocks.AIR.getDefaultState()); fillArea(world, chunkX * 16, topLayerHeight - 8 * i + 6, chunkZ * 16, chunkX * 16 + 16, topLayerHeight - 8 * i + 7, chunkZ * 16 + 16, FlansModApocalypse.blockLabStone.getDefaultState()); //Add glowstone lights for(int j = 0; j < 2; j++) { for(int k = 0; k < 2; k++) { fillArea(world, chunkX * 16 + 3 + 8 * j, topLayerHeight - 8 * i + 6, chunkZ * 16 + 3 + 8 * k, chunkX * 16 + 5 + 8 * j, topLayerHeight - 8 * i + 7, chunkZ * 16 + 5 + 8 * k, Blocks.GLOWSTONE.getDefaultState()); if(world.isRemote) { for(int x = 0; x < 2; x++) { for(int z = 0; z < 2; z++) { world.setLightFor(EnumSkyBlock.BLOCK, new BlockPos(chunkX * 16 + 3 + 8 * j + x, topLayerHeight - 8 * i + 6, chunkZ * 16 + 3 + 8 * k + z), 15); world.getLightFromNeighborsFor(EnumSkyBlock.BLOCK, new BlockPos(chunkX * 16 + 3 + 8 * j + x, topLayerHeight - 8 * i + 5, chunkZ * 16 + 3 + 8 * k + z)); } } } } } //Make doors if(pieceX != 0) fillArea(world, chunkX * 16 + 0, topLayerHeight - 8 * i + 1, chunkZ * 16 + 7, chunkX * 16 + 1, topLayerHeight - 8 * i + 4, chunkZ * 16 + 9, Blocks.AIR.getDefaultState()); if(pieceX != 2) fillArea(world, chunkX * 16 + 15, topLayerHeight - 8 * i + 1, chunkZ * 16 + 7, chunkX * 16 + 16, topLayerHeight - 8 * i + 4, chunkZ * 16 + 9, Blocks.AIR.getDefaultState()); if(pieceZ != 0) fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 0, chunkX * 16 + 9, topLayerHeight - 8 * i + 4, chunkZ * 16 + 1, Blocks.AIR.getDefaultState()); if(pieceZ != 2) fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 15, chunkX * 16 + 9, topLayerHeight - 8 * i + 4, chunkZ * 16 + 16, Blocks.AIR.getDefaultState()); for(int j = 0; j < 16; j++) { for(int k = 0; k < 16; k++) { //world.checkLightFor(EnumSkyBlock.BLOCK, new BlockPos(chunkX * 16 + j, topLayerHeight - 8 * i + 4, chunkZ * 18 + k)); } } } //Populate rooms for(int i = 0; i < 8; i++) { if(i == 7 && pieceX == 1 && pieceZ == 1) { //Teleporter Room fillArea(world, chunkX * 16 + 3, topLayerHeight - 8 * i, chunkZ * 16 + 3, chunkX * 16 + 13, topLayerHeight - 8 * i + 1, chunkZ * 16 + 13, Blocks.GLOWSTONE.getDefaultState()); fillArea(world, chunkX * 16 + 4, topLayerHeight - 8 * i, chunkZ * 16 + 4, chunkX * 16 + 12, topLayerHeight - 8 * i + 1, chunkZ * 16 + 12, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 6, topLayerHeight - 8 * i + 1, chunkZ * 16 + 6, chunkX * 16 + 10, topLayerHeight - 8 * i + 2, chunkZ * 16 + 10, Blocks.OBSIDIAN.getDefaultState()); fillArea(world, chunkX * 16 + 6, topLayerHeight - 8 * i + 1, chunkZ * 16 + 7, chunkX * 16 + 7, topLayerHeight - 8 * i + 2, chunkZ * 16 + 9, Blocks.STONE_SLAB.getStateFromMeta(7)); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i + 1, chunkZ * 16 + 7, chunkX * 16 + 10, topLayerHeight - 8 * i + 2, chunkZ * 16 + 9, Blocks.STONE_SLAB.getStateFromMeta(7)); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 6, chunkX * 16 + 9, topLayerHeight - 8 * i + 2, chunkZ * 16 + 7, Blocks.STONE_SLAB.getStateFromMeta(7)); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 9, chunkX * 16 + 9, topLayerHeight - 8 * i + 2, chunkZ * 16 + 10, Blocks.STONE_SLAB.getStateFromMeta(7)); world.setBlockState(new BlockPos(chunkX * 16 + 6, topLayerHeight - 8 * i + 2, chunkZ * 16 + 6), FlansModApocalypse.blockPowerCube.getDefaultState()); for(int k = 0; k < 8; k++) spawnMecha(world, rand, chunkX * 16 + 4 + rand.nextInt(8), topLayerHeight - 8 * i + 2, chunkZ * 16 + 4 + rand.nextInt(8)); } //Build entrance else if(i == 0 && pieceX == 1 && pieceZ == 1) { i--; //Make hole fillArea(world, chunkX * 16 + 4, topLayerHeight - 8 * i + 1, chunkZ * 16 + 4, chunkX * 16 + 12, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.NETHER_BRICK_FENCE.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 2, chunkZ * 16 + 5, chunkX * 16 + 11, topLayerHeight - 8 * i + 2, chunkZ * 16 + 11, Blocks.AIR.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 11, chunkX * 16 + 9, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.AIR.getDefaultState()); //Build stairs fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 1, chunkZ * 16 + 9, chunkX * 16 + 9, topLayerHeight - 8 * i, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, chunkX * 16 + 7, topLayerHeight - 8 * i - 1, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, chunkX * 16 + 11, topLayerHeight - 8 * i - 1, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, chunkX * 16 + 11, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, chunkX * 16 + 7, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 4, chunkZ * 16 + 5, chunkX * 16 + 11, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 5, chunkZ * 16 + 7, chunkX * 16 + 9, topLayerHeight - 8 * i - 4, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 6, chunkZ * 16 + 9, chunkX * 16 + 9, topLayerHeight - 8 * i - 5, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 7, chunkZ * 16 + 11, chunkX * 16 + 9, topLayerHeight - 8 * i - 6, chunkZ * 16 + 13, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 7, chunkZ * 16 + 9, chunkX * 16 + 7, topLayerHeight - 8 * i - 6, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 7, chunkZ * 16 + 9, chunkX * 16 + 11, topLayerHeight - 8 * i - 6, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); i++; } else { boolean spawnMecha = true; switch(i == 6 && pieceX == 1 && pieceZ == 1 ? 4 : rand.nextInt(7)) { case 0: //Stairs { //Make hole fillArea(world, chunkX * 16 + 4, topLayerHeight - 8 * i + 1, chunkZ * 16 + 4, chunkX * 16 + 12, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.NETHER_BRICK_FENCE.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 2, chunkZ * 16 + 5, chunkX * 16 + 11, topLayerHeight - 8 * i + 2, chunkZ * 16 + 11, Blocks.AIR.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i + 1, chunkZ * 16 + 11, chunkX * 16 + 9, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.AIR.getDefaultState()); //Build stairs fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 1, chunkZ * 16 + 9, chunkX * 16 + 9, topLayerHeight - 8 * i, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, chunkX * 16 + 7, topLayerHeight - 8 * i - 1, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, chunkX * 16 + 11, topLayerHeight - 8 * i - 1, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, chunkX * 16 + 11, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, chunkX * 16 + 7, topLayerHeight - 8 * i - 2, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 4, chunkZ * 16 + 5, chunkX * 16 + 11, topLayerHeight - 8 * i - 3, chunkZ * 16 + 7, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 5, chunkZ * 16 + 7, chunkX * 16 + 9, topLayerHeight - 8 * i - 4, chunkZ * 16 + 9, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 6, chunkZ * 16 + 9, chunkX * 16 + 9, topLayerHeight - 8 * i - 5, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 7, topLayerHeight - 8 * i - 7, chunkZ * 16 + 11, chunkX * 16 + 9, topLayerHeight - 8 * i - 6, chunkZ * 16 + 13, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 5, topLayerHeight - 8 * i - 7, chunkZ * 16 + 9, chunkX * 16 + 7, topLayerHeight - 8 * i - 6, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, chunkX * 16 + 9, topLayerHeight - 8 * i - 7, chunkZ * 16 + 9, chunkX * 16 + 11, topLayerHeight - 8 * i - 6, chunkZ * 16 + 11, FlansModApocalypse.blockLabStone.getDefaultState()); i++; spawnMecha = false; break; } case 1: //Liquids room { for(int j = 0; j < 2; j++) { for(int k = 0; k < 2; k++) { if(rand.nextInt(3) == 0) { generateLiquidsLab(world, rand, chunkX * 16 + 1 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1 + 8 * k); } else generateLiquidContainer(world, rand, chunkX * 16 + 2 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 2 + 8 * k, getRandomLiquid(rand)); } } break; } case 2: //Gun range { for(int j = 0; j < 2; j++) { generateTarget(world, rand, chunkX * 16 + 2 + 7 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1); } fillArea(world, chunkX * 16 + 3, topLayerHeight - 8 * i + 1, chunkZ * 16 + 6, chunkX * 16 + 4, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.PLANKS.getDefaultState()); fillArea(world, chunkX * 16 + 12, topLayerHeight - 8 * i + 1, chunkZ * 16 + 6, chunkX * 16 + 13, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.PLANKS.getDefaultState()); fillArea(world, chunkX * 16 + 4, topLayerHeight - 8 * i + 1, chunkZ * 16 + 11, chunkX * 16 + 12, topLayerHeight - 8 * i + 2, chunkZ * 16 + 12, Blocks.STONE_SLAB.getStateFromMeta(10)); world.setBlockState(new BlockPos(chunkX * 16 + 6, topLayerHeight - 8 * i + 1, chunkZ * 16 + 11), Blocks.PLANKS.getDefaultState()); world.setBlockState(new BlockPos(chunkX * 16 + 9, topLayerHeight - 8 * i + 1, chunkZ * 16 + 11), Blocks.PLANKS.getDefaultState()); generateGunRack(world, rand, chunkX * 16 + 1, topLayerHeight - 8 * i + 1, chunkZ * 16 + 14); generateGunRack(world, rand, chunkX * 16 + 4, topLayerHeight - 8 * i + 1, chunkZ * 16 + 14); generateGunRack(world, rand, chunkX * 16 + 10, topLayerHeight - 8 * i + 1, chunkZ * 16 + 14); generateGunRack(world, rand, chunkX * 16 + 13, topLayerHeight - 8 * i + 1, chunkZ * 16 + 14); break; } case 3: //Plant room { for(int j = 0; j < 2; j++) { for(int k = 0; k < 2; k++) { switch(rand.nextInt(2)) { case 0: generatePlantPots(world, rand, chunkX * 16 + 1 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1 + 8 * k); break; case 1: generateFarm(world, rand, chunkX * 16 + 9 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 9 * k); break; } } } break; } case 4: //Forge { for(int j = 0; j < 2; j++) { if(rand.nextBoolean()) generateFurnace(world, rand, chunkX * 16 + 2 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1); else { if(rand.nextBoolean()) world.setBlockState(new BlockPos(chunkX * 16 + 2 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1), Blocks.CRAFTING_TABLE.getDefaultState()); else world.setBlockState(new BlockPos(chunkX * 16 + 2 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1), FlansMod.workbench.getStateFromMeta(1)); world.setBlockState(new BlockPos(chunkX * 16 + 4 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1), Blocks.IRON_BLOCK.getDefaultState()); world.setBlockState(new BlockPos(chunkX * 16 + 5 + 8 * j, topLayerHeight - 8 * i + 2, chunkZ * 16 + 1), Blocks.IRON_BLOCK.getDefaultState()); world.setBlockState(new BlockPos(chunkX * 16 + 5 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 1), Blocks.IRON_BLOCK.getDefaultState()); world.setBlockState(new BlockPos(chunkX * 16 + 4 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 4), Blocks.ANVIL.getDefaultState()); } { generateWeapons(world, rand, chunkX * 16 + 2 + 8 * j, topLayerHeight - 8 * i + 1, chunkZ * 16 + 10); } } break; } case 5: //Power Room { generateServerRack(world, rand, chunkX * 16 + 1, topLayerHeight - 8 * i + 1, chunkZ * 16 + 2, true); generateServerRack(world, rand, chunkX * 16 + 1, topLayerHeight - 8 * i + 1, chunkZ * 16 + 5, false); generateServerRack(world, rand, chunkX * 16 + 1, topLayerHeight - 8 * i + 1, chunkZ * 16 + 10, false); generateServerRack(world, rand, chunkX * 16 + 1, topLayerHeight - 8 * i + 1, chunkZ * 16 + 13, true); generateServerRack(world, rand, chunkX * 16 + 10, topLayerHeight - 8 * i + 1, chunkZ * 16 + 2, true); generateServerRack(world, rand, chunkX * 16 + 12, topLayerHeight - 8 * i + 1, chunkZ * 16 + 5, false); generateServerRack(world, rand, chunkX * 16 + 12, topLayerHeight - 8 * i + 1, chunkZ * 16 + 10, false); generateServerRack(world, rand, chunkX * 16 + 10, topLayerHeight - 8 * i + 1, chunkZ * 16 + 13, true); generateServerPower(world, rand, chunkX * 16 + 6, topLayerHeight - 8 * i + 1, chunkZ * 16 + 6); spawnMecha = false; break; } } if(spawnMecha && rand.nextBoolean()) { spawnMecha(world, rand, chunkX * 16 + 8, topLayerHeight - 8 * i + 1, chunkZ * 16 + 8); } } } return false; } private void spawnMecha(World world, Random rand, int x, int y, int z) { MechaType type = FlansModApocalypse.getLootGenerator().getRandomDungeonMecha(rand); NBTTagCompound tags = new NBTTagCompound(); PartType engine = FlansModApocalypse.getLootGenerator().getRandomEngine(type, rand); if(engine == null && PlaneType.types.size() > 0) { engine = FlansModApocalypse.getLootGenerator().getRandomEngine(PlaneType.types.get(0), rand); } if(engine == null && PartType.parts.size() > 0) engine = PartType.parts.get(0); tags.setString("Engine", engine.shortName); tags.setString("Type", type.shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } for(int k = 0; k < 2; k++) { ItemStack randomGun = FlansModApocalypse.getLootGenerator().getRandomLoadedGun(rand, false); GunType gunType = ((ItemGun)randomGun.getItem()).GetType(); tags.setTag(k == 1 ? EnumMechaSlotType.rightTool.toString() : EnumMechaSlotType.leftTool.toString(), randomGun.writeToNBT(new NBTTagCompound())); if(gunType.nonExplosiveAmmo.size() > 0) { for(int j = 0; j < 1 + rand.nextInt(2); j++) { ShootableType ammo = gunType.nonExplosiveAmmo.get(rand.nextInt(gunType.nonExplosiveAmmo.size())); tags.setTag("Cargo " + rand.nextInt(type.numCargoSlots), new ItemStack(ammo.item, (ammo.maxStackSize > 1 ? rand.nextInt(ammo.maxStackSize - 1) + 1 : 1)).writeToNBT(new NBTTagCompound())); } } } EntityAIMecha entity = new EntityAIMecha(world, x + 0.5D, y, z + 0.5D, type, new DriveableData(tags), tags); world.spawnEntity(entity); } private void generateServerPower(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 2, y + 3, z + 2, Blocks.OBSIDIAN.getDefaultState()); fillArea(world, x + 1, y, z + 1, x + 3, y + 3, z + 3, Blocks.OBSIDIAN.getDefaultState()); fillArea(world, x + 2, y, z + 2, x + 4, y + 3, z + 4, Blocks.OBSIDIAN.getDefaultState()); world.setBlockState(new BlockPos(x + 1, y + 1, z + 1), FlansModApocalypse.blockPowerCube.getDefaultState()); world.setBlockState(new BlockPos(x + 2, y + 1, z + 2), Blocks.AIR.getDefaultState()); world.setBlockState(new BlockPos(x + 1, y + 2, z + 1), Blocks.IRON_TRAPDOOR.getStateFromMeta(8)); world.setBlockState(new BlockPos(x + 2, y + 2, z + 2), Blocks.IRON_TRAPDOOR.getStateFromMeta(8)); } private void generateServerRack(World world, Random rand, int x, int y, int z, boolean big) { fillArea(world, x, y, z, x + 3, y + 3, z + 1, Blocks.OBSIDIAN.getDefaultState()); fillArea(world, x + 1, y, z, x + 2, y + 3, z + 1, Blocks.QUARTZ_BLOCK.getStateFromMeta(3)); if(big) { fillArea(world, x + 3, y, z, x + 4, y + 3, z + 1, Blocks.QUARTZ_BLOCK.getStateFromMeta(3)); fillArea(world, x + 4, y, z, x + 5, y + 3, z + 1, Blocks.OBSIDIAN.getDefaultState()); } } private void generateWeapons(World world, Random rand, int x, int y, int z) { fillArea(world, x + 1, y, z, x + 3, y + 1, z + 2, Blocks.PLANKS.getDefaultState()); fillArea(world, x, y, z, x + 1, y + 1, z + 2, Blocks.CHEST.getDefaultState()); fillArea(world, x + 3, y, z, x + 4, y + 1, z + 2, Blocks.CHEST.getDefaultState()); fillArea(world, x + 1, y + 1, z, x + 3, y + 2, z + 1, FlansModApocalypse.gunRack.getDefaultState().withProperty(BlockItemHolder.FACING, EnumFacing.SOUTH)); fillArea(world, x + 1, y + 1, z + 1, x + 3, y + 2, z + 2, FlansModApocalypse.gunRack.getDefaultState().withProperty(BlockItemHolder.FACING, EnumFacing.NORTH)); for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) if(rand.nextInt(3) != 0) FlansModApocalypse.getLootGenerator().addRandomLoot((TileEntityItemHolder)world.getTileEntity(new BlockPos(x + 1 + i, y + 1, z + j)), rand, true); for(int i = 0; i < 2; i++) { FlansModApocalypse.getLootGenerator().fillWeaponChest(rand, ((TileEntityChest)world.getTileEntity(new BlockPos(x, y, z + i)))); FlansModApocalypse.getLootGenerator().fillWeaponChest(rand, ((TileEntityChest)world.getTileEntity(new BlockPos(x + 3, y, z + i)))); } } private void generateFurnace(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 1, y + 2, z + 2, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x + 3, y, z, x + 4, y + 2, z + 2, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x + 1, y, z + 2, x + 3, y + 1, z + 3, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x + 1, y + 2, z, x + 3, y + 3, z + 2, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x + 1, y + 3, z, x + 3, y + 5, z + 1, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x + 1, y, z, x + 3, y + 1, z + 2, Blocks.LAVA.getDefaultState()); } private void generatePlantPots(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 6, y + 1, z + 1, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x + 1, y, z, x + 5, y + 1, z + 1, Blocks.STONE_SLAB.getStateFromMeta(15)); for(int i = 0; i < 6; i++) world.setBlockState(new BlockPos(x + i, y + 1, z), Blocks.FLOWER_POT.getDefaultState().withProperty(BlockFlowerPot.LEGACY_DATA, rand.nextInt(14))); fillArea(world, x, y, z + 5, x + 6, y + 1, z + 6, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x + 1, y, z + 5, x + 5, y + 1, z + 6, Blocks.STONE_SLAB.getStateFromMeta(15)); for(int i = 0; i < 6; i++) world.setBlockState(new BlockPos(x + i, y + 1, z + 5), Blocks.FLOWER_POT.getDefaultState().withProperty(BlockFlowerPot.LEGACY_DATA, rand.nextInt(14))); } private void generateFarm(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 7, y + 1, z + 7, FlansModApocalypse.blockLabStone.getDefaultState()); if(world.isRemote) { for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { world.setBlockState(new BlockPos(x + 1 + 4 * i, y + 2, z + 1 + 4 * j), Blocks.GLOWSTONE.getDefaultState()); world.setLightFor(EnumSkyBlock.BLOCK, new BlockPos(x + 1 + 4 * i, y + 2, z + 1 + 4 * j), 15); world.getLightFromNeighborsFor(EnumSkyBlock.BLOCK, new BlockPos(x + 1 + 4 * i, y + 1, z + 1 + 4 * j)); world.setBlockState(new BlockPos(x + 1 + 4 * i, y + 3, z + 1 + 4 * j), Blocks.OAK_FENCE.getDefaultState()); world.setBlockState(new BlockPos(x + 1 + 4 * i, y + 4, z + 1 + 4 * j), Blocks.OAK_FENCE.getDefaultState()); } } } fillArea(world, x + 1, y, z + 1, x + 6, y + 1, z + 6, Blocks.FARMLAND.getStateFromMeta(7)); switch(rand.nextInt(3)) { case 0: fillArea(world, x + 1, y + 1, z + 1, x + 6, y + 2, z + 6, Blocks.WHEAT.getStateFromMeta(rand.nextInt(5) + 2)); break; case 1: fillArea(world, x + 1, y + 1, z + 1, x + 6, y + 2, z + 6, Blocks.CARROTS.getStateFromMeta(rand.nextInt(5) + 2)); break; case 2: fillArea(world, x + 1, y + 1, z + 1, x + 6, y + 2, z + 6, Blocks.POTATOES.getStateFromMeta(rand.nextInt(5) + 2)); break; } world.setBlockState(new BlockPos(x + 3, y + 1, z + 3), Blocks.AIR.getDefaultState()); world.setBlockState(new BlockPos(x + 3, y, z + 3), Blocks.WATER.getDefaultState()); } private void generateGunRack(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 2, y + 1, z + 1, Blocks.PLANKS.getDefaultState()); fillArea(world, x, y + 1, z, x + 2, y + 2, z + 1, FlansModApocalypse.gunRack.getDefaultState().withProperty(BlockItemHolder.FACING, EnumFacing.SOUTH)); for(int i = 0; i < 2; i++) { if(rand.nextInt(3) != 0) FlansModApocalypse.getLootGenerator().addRandomLoot((TileEntityItemHolder)world.getTileEntity(new BlockPos(x + i, y + 1, z)), rand, true); } } private void generateTarget(World world, Random rand, int x, int y, int z) { fillArea(world, x + 1, y + 1, z, x + 4, y + 4, z + 1, Blocks.WOOL.getStateFromMeta(14)); world.setBlockState(new BlockPos(x + 2, y, z), Blocks.WOOL.getStateFromMeta(14)); world.setBlockState(new BlockPos(x + 2, y + 4, z), Blocks.WOOL.getStateFromMeta(14)); world.setBlockState(new BlockPos(x, y + 2, z), Blocks.WOOL.getStateFromMeta(14)); world.setBlockState(new BlockPos(x + 4, y + 2, z), Blocks.WOOL.getStateFromMeta(14)); world.setBlockState(new BlockPos(x + 2, y + 1, z), Blocks.WOOL.getDefaultState()); world.setBlockState(new BlockPos(x + 2, y + 3, z), Blocks.WOOL.getDefaultState()); world.setBlockState(new BlockPos(x + 1, y + 2, z), Blocks.WOOL.getDefaultState()); world.setBlockState(new BlockPos(x + 3, y + 2, z), Blocks.WOOL.getDefaultState()); } private void generateLiquidsLab(World world, Random rand, int x, int y, int z) { fillArea(world, x, y, z, x + 4, y + 1, z + 1, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x + 1, y, z, x + 3, y + 1, z + 1, Blocks.STONE_SLAB.getStateFromMeta(15)); fillArea(world, x, y, z + 5, x + 5, y + 1, z + 6, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x + 1, y, z + 5, x + 4, y + 1, z + 6, Blocks.STONE_SLAB.getStateFromMeta(15)); world.setBlockState(new BlockPos(x + 5, y, z + 5), Blocks.CAULDRON.getStateFromMeta(rand.nextInt(4))); world.setBlockState(new BlockPos(x + 4, y, z), Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, EnumFacing.SOUTH)); world.setBlockState(new BlockPos(x + 5, y, z), Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, EnumFacing.SOUTH)); //Fill chests TileEntity tileentity = world.getTileEntity(new BlockPos(x + 4, y, z)); if(tileentity instanceof TileEntityChest) { FlansModApocalypse.getLootGenerator().fillLiquidLabChest(rand, (TileEntityChest)tileentity); } tileentity = world.getTileEntity(new BlockPos(x + 5, y, z)); if(tileentity instanceof TileEntityChest) { FlansModApocalypse.getLootGenerator().fillLiquidLabChest(rand, (TileEntityChest)tileentity); } //Brewing stands BlockPos pos = new BlockPos(x + rand.nextInt(4), y + 1, z); world.setBlockState(pos, Blocks.BREWING_STAND.getDefaultState()); tileentity = world.getTileEntity(pos); if(tileentity instanceof TileEntityBrewingStand) { FlansModApocalypse.getLootGenerator().fillBrewingStand(rand, (TileEntityBrewingStand)tileentity); } pos = new BlockPos(x + rand.nextInt(5), y + 1, z + 5); world.setBlockState(pos, Blocks.BREWING_STAND.getDefaultState()); tileentity = world.getTileEntity(pos); if(tileentity instanceof TileEntityBrewingStand) { FlansModApocalypse.getLootGenerator().fillBrewingStand(rand, (TileEntityBrewingStand)tileentity); } } private void generateLiquidContainer(World world, Random rand, int x, int y, int z, IBlockState liquid) { fillArea(world, x, y, z, x + 4, y + 5, z + 4, FlansModApocalypse.blockLabStone.getDefaultState()); fillArea(world, x, y + 1, z, x + 4, y + 4, z + 4, Blocks.GLASS.getDefaultState()); fillArea(world, x + 1, y, z + 1, x + 3, y + 5, z + 3, Blocks.AIR.getDefaultState()); fillArea(world, x + 1, y, z + 1, x + 3, y + rand.nextInt(4), z + 3, liquid); fillArea(world, x, y, z, x + 1, y + 5, z + 1, Blocks.AIR.getDefaultState()); fillArea(world, x + 3, y, z, x + 4, y + 5, z + 1, Blocks.AIR.getDefaultState()); fillArea(world, x + 3, y, z + 3, x + 4, y + 5, z + 4, Blocks.AIR.getDefaultState()); fillArea(world, x, y, z + 3, x + 1, y + 5, z + 4, Blocks.AIR.getDefaultState()); } private IBlockState getRandomLiquid(Random rand) { switch(rand.nextInt(3)) { case 0: return Blocks.WATER.getDefaultState(); case 1: return Blocks.LAVA.getDefaultState(); case 2: return FlansModApocalypse.blockSulphuricAcid.getDefaultState(); } return Blocks.WATER.getDefaultState(); } private void generateRoom(World world, Random rand, int chunkX, int layerY, int chunkZ) { } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenRoads.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.BlockItemHolder; import com.flansmod.common.ModuloHelper; import com.flansmod.common.TileEntityItemHolder; import net.minecraft.block.BlockColored; import net.minecraft.init.Blocks; import net.minecraft.item.EnumDyeColor; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenerator; public class WorldGenRoads extends WorldGenerator { // Ring road private static final double kRingRoadInner = 400d, kRingRoadMid = 410d, kRingRoadOuter = 420d, kRingRoadEdgeWidth = 1.5d; private static final double dashLength = 10.0d; private static final double archLength = 16.0d; private static final double kAxisRoadWidth = 10.0d; private static final double kRepeatDistance = 600d; @Override public boolean generate(World world, Random rand, BlockPos pos) { for(int i = 8; i < 24; i++) { for(int k = 8; k < 24; k++) { BlockPos p = pos.add(i, 0, k); double dist = p.getDistance(0, 0, 0); double theta = Math.atan2(p.getZ(), p.getX()); double r = ModuloHelper.modulo(dist, kRepeatDistance); int repeat = (int) Math.floor(dist / kRepeatDistance); double circumfrence = (kRingRoadMid + kRepeatDistance * repeat) * Math.PI * 2d; double archArcLength = Math.PI * 2d * archLength / circumfrence; double dashArcLength = Math.PI * 2d * dashLength / circumfrence; int doRoad = 0; boolean doEdge = false; boolean doDash = false; double archHeight = 128d; double tunnelHeight = 0d; if(kRingRoadInner <= r && r <= kRingRoadOuter) { doRoad++; doEdge = r <= kRingRoadInner + kRingRoadEdgeWidth || kRingRoadOuter - kRingRoadEdgeWidth <= r; doDash = kRingRoadMid - 0.5d <= r && r <= kRingRoadMid + 0.5d && ModuloHelper.modulo(theta, (dashArcLength * 2d)) < dashArcLength; archHeight = 20 + 38 * Math.abs(Math.sin(theta / archArcLength)); double t = (r - kRingRoadInner) / (kRingRoadOuter - kRingRoadInner); tunnelHeight = 70 + 7 * Math.sin(t * Math.PI); } double x = Math.abs(p.getX()); if(x < kAxisRoadWidth) { doRoad++; doEdge = x > kAxisRoadWidth - kRingRoadEdgeWidth; doDash = x < 0.5d && ModuloHelper.modulo(p.getZ(), 2 * dashLength) < dashLength; archHeight = Math.min(archHeight, 20 + 38 * Math.abs(Math.sin(p.getZ() * Math.PI / (archLength * 3.0d)))); tunnelHeight = Math.max(tunnelHeight, 70 + 7 * Math.cos((x / kAxisRoadWidth) * Math.PI * 0.5d)); } double z = Math.abs(p.getZ()); if(z < kAxisRoadWidth) { doRoad++; doEdge = z > kAxisRoadWidth - kRingRoadEdgeWidth; doDash = z < 0.5d && ModuloHelper.modulo(p.getX(), 2 * dashLength) < dashLength; archHeight = Math.min(archHeight, 20 + 38 * Math.abs(Math.sin(p.getX() * Math.PI / (archLength * 3.0d)))); tunnelHeight = Math.max(tunnelHeight, 70 + 7 * Math.cos((z / kAxisRoadWidth) * Math.PI * 0.5d)); } if(doRoad > 1) doEdge = false; if(doEdge) { world.setBlockState(p.add(0,64,0), Blocks.DOUBLE_STONE_SLAB.getDefaultState()); } else if(doRoad > 0) { world.setBlockState(p.add(0,64,0), Blocks.CONCRETE.getDefaultState().withProperty(BlockColored.COLOR, doDash ? EnumDyeColor.WHITE : EnumDyeColor.BLACK), 0); } if(doRoad > 0) { BlockPos downIterate = p.add(0,63,0); while(world.isAirBlock(downIterate) && downIterate.getY() > archHeight) { world.setBlockState(downIterate, Blocks.STONE.getDefaultState()); downIterate = downIterate.down(); } BlockPos upIterate = p.add(0, 65, 0); while(upIterate.getY() < tunnelHeight) { world.setBlockToAir(upIterate); upIterate = upIterate.up(); } } } } return false; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenRunway.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import net.minecraft.block.BlockChest; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.FlansMod; import com.flansmod.common.ModuloHelper; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EnumDriveablePart; public class WorldGenRunway extends WorldGenFlan { @Override public boolean generate(World world, Random rand, BlockPos pos) { int chunkX = ModuloHelper.divide(pos.getX(), 16); int x = pos.getX(); int z = pos.getZ(); int yHeight = 108; //Create runway for(int j = 1; j < 8; j++) { fillArea(world, x, yHeight - j, z + j, x + 16, yHeight - j + 1, z + 16 - j, Blocks.STONE.getDefaultState()); } fillArea(world, x, yHeight, z, x + 16, yHeight + 1, z + 16, Blocks.STAINED_HARDENED_CLAY.getStateFromMeta(15)); fillArea(world, x + 2, yHeight, z + 7, x + 6, yHeight + 1, z + 9, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x + 10, yHeight, z + 7, x + 14, yHeight + 1, z + 9, Blocks.QUARTZ_BLOCK.getDefaultState()); fillArea(world, x, yHeight + 1, z, x + 16, yHeight + 11, z + 16, Blocks.AIR.getDefaultState()); if(ModuloHelper.modulo(chunkX, 4) == 1) { //Create hangar fillArea(world, x, yHeight + 1, z, x + 16, yHeight + 5, z + 1, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 5, z + 1, x + 16, yHeight + 7, z + 2, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 7, z + 2, x + 16, yHeight + 8, z + 3, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 8, z + 3, x + 16, yHeight + 9, z + 5, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 9, z + 5, x + 16, yHeight + 10, z + 11, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 8, z + 11, x + 16, yHeight + 9, z + 13, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 7, z + 13, x + 16, yHeight + 8, z + 14, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 5, z + 14, x + 16, yHeight + 7, z + 15, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 1, z + 15, x + 16, yHeight + 5, z + 16, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 1, z + 1, x + 1, yHeight + 5, z + 15, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 5, z + 2, x + 1, yHeight + 7, z + 14, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 7, z + 3, x + 1, yHeight + 8, z + 13, Blocks.WOOL.getStateFromMeta(13)); fillArea(world, x, yHeight + 8, z + 5, x + 1, yHeight + 9, z + 11, Blocks.WOOL.getStateFromMeta(13)); world.setBlockState(new BlockPos(x + 1, yHeight + 1, z + 1), Blocks.CRAFTING_TABLE.getDefaultState()); world.setBlockState(new BlockPos(x + 2, yHeight + 1, z + 1), FlansMod.workbench.getStateFromMeta(0)); world.setBlockState(new BlockPos(x + 1, yHeight + 1, z + 14), FlansMod.workbench.getStateFromMeta(0)); world.setBlockState(new BlockPos(x + 1, yHeight + 4, z + 14), Blocks.GLOWSTONE.getDefaultState(), 2); world.setBlockState(new BlockPos(x + 1, yHeight + 4, z + 1), Blocks.GLOWSTONE.getDefaultState(), 2); world.setBlockState(new BlockPos(x + 1, yHeight + 7, z + 12), Blocks.GLOWSTONE.getDefaultState(), 2); world.setBlockState(new BlockPos(x + 1, yHeight + 7, z + 3), Blocks.GLOWSTONE.getDefaultState(), 2); world.setBlockState(new BlockPos(x + 3, yHeight + 1, z + 14), FlansModApocalypse.getLootGenerator().getRandomWeaponBox(rand).getDefaultState()); world.setBlockState(new BlockPos(x + 4, yHeight + 1, z + 14), FlansModApocalypse.getLootGenerator().getRandomWeaponBox(rand).getDefaultState()); world.setBlockState(new BlockPos(x + 4, yHeight + 1, z + 1), Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, EnumFacing.NORTH), 2); world.setBlockState(new BlockPos(x + 5, yHeight + 1, z + 1), Blocks.CHEST.getDefaultState().withProperty(BlockChest.FACING, EnumFacing.NORTH), 2); BlockPos chestPos = new BlockPos(x + 4, yHeight + 1, z + 1); TileEntity tileentity = world.getTileEntity(chestPos); if(tileentity instanceof TileEntityChest) { FlansModApocalypse.getLootGenerator().fillVillageChest(rand, (TileEntityChest)tileentity); } chestPos = new BlockPos(x + 5, yHeight + 1, z + 1); tileentity = world.getTileEntity(chestPos); if(tileentity instanceof TileEntityChest) { FlansModApocalypse.getLootGenerator().fillVillageChest(rand, (TileEntityChest)tileentity); } } if(ModuloHelper.modulo(chunkX, 4) == 0) { //Spawn a plane DriveableType type = FlansModApocalypse.getLootGenerator().getRandomPlane(rand); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Engine", FlansModApocalypse.getLootGenerator().getRandomEngine(type, rand).shortName); tags.setString("Type", type.shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : rand.nextInt(type.health.get(part).health)); tags.setBoolean(part.getShortName() + "_Fire", false); } EntityDriveable entity = type.createDriveable(world, x + 8, yHeight + 3, z + 8, new DriveableData(tags)); entity.setRotation(0F, 0, 0); world.spawnEntity(entity); } return false; } } ================================================ FILE: src/main/java/com/flansmod/apocalypse/common/world/buildings/WorldGenSkeleton.java ================================================ package com.flansmod.apocalypse.common.world.buildings; import java.util.Random; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.WorldGenerator; import com.flansmod.apocalypse.common.FlansModApocalypse; import com.flansmod.common.BlockItemHolder; import com.flansmod.common.TileEntityItemHolder; public class WorldGenSkeleton extends WorldGenerator { @Override public boolean generate(World world, Random rand, BlockPos pos) { for(; pos.getY() < 256; pos = pos.up()) { if(world.isAirBlock(pos) && world.isSideSolid(pos.down(), EnumFacing.UP)) { world.setBlockState(pos, FlansModApocalypse.skeleton.getDefaultState().withProperty(BlockItemHolder.FACING, EnumFacing.HORIZONTALS[rand.nextInt(4)]), 2); FlansModApocalypse.getLootGenerator().addRandomLoot((TileEntityItemHolder)world.getTileEntity(pos), rand, false); break; } } return false; } } ================================================ FILE: src/main/java/com/flansmod/client/ClientProxy.java ================================================ package com.flansmod.client; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.util.DamageSource; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.resource.VanillaResourceType; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.FMLModContainer; import net.minecraftforge.fml.common.MetadataCollection; import net.minecraftforge.fml.common.discovery.ContainerType; import net.minecraftforge.fml.common.discovery.ModCandidate; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.debug.EntityDebugAABB; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.client.debug.RenderDebugAABB; import com.flansmod.client.debug.RenderDebugDot; import com.flansmod.client.debug.RenderDebugVector; import com.flansmod.client.gui.GuiArmourBox; import com.flansmod.client.gui.GuiDriveableCrafting; import com.flansmod.client.gui.GuiDriveableFuel; import com.flansmod.client.gui.GuiDriveableInventory; import com.flansmod.client.gui.GuiDriveableMenu; import com.flansmod.client.gui.GuiDriveableRepair; import com.flansmod.client.gui.GuiGunBox; import com.flansmod.client.gui.GuiGunModTable; import com.flansmod.client.gui.GuiMechaInventory; import com.flansmod.client.gui.GuiPaintjobTable; import com.flansmod.client.handlers.ClientEventHandler; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.handlers.KeyInputHandler; import com.flansmod.client.model.RenderAAGun; import com.flansmod.client.model.RenderBullet; import com.flansmod.client.model.RenderFlag; import com.flansmod.client.model.RenderFlagpole; import com.flansmod.client.model.RenderGrenade; import com.flansmod.client.model.RenderGun; import com.flansmod.client.model.RenderGunItem; import com.flansmod.client.model.RenderItemHolder; import com.flansmod.client.model.RenderMG; import com.flansmod.client.model.RenderMecha; import com.flansmod.client.model.RenderNull; import com.flansmod.client.model.RenderParachute; import com.flansmod.client.model.RenderPlane; import com.flansmod.client.model.RenderVehicle; import com.flansmod.common.CommonProxy; import com.flansmod.common.EntityItemCustomRender; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.TileEntityItemHolder; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.EntityWheel; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.guns.EntityAAGun; import com.flansmod.common.guns.EntityBullet; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.EntityMG; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.guns.boxes.BlockGunBox; import com.flansmod.common.guns.boxes.BoxType; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.network.PacketBuyArmour; import com.flansmod.common.network.PacketBuyWeapon; import com.flansmod.common.network.PacketCraftDriveable; import com.flansmod.common.network.PacketRepairDriveable; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.paintjob.TileEntityPaintjobTable; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.teams.BlockArmourBox; import com.flansmod.common.teams.EntityFlag; import com.flansmod.common.teams.EntityFlagpole; import com.flansmod.common.teams.TileEntitySpawner; import com.flansmod.common.tools.EntityParachute; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; import com.flansmod.common.vector.Vector3f; @SideOnly(Side.CLIENT) public class ClientProxy extends CommonProxy { public static String modelDir = "com.flansmod.client.model."; /* These renderers handle rendering in hand items */ public static RenderGun gunRenderer; public List eventsToRegister = new ArrayList<>(); private FlansModClient flansModClient; @Override public void preInit() { MinecraftForge.EVENT_BUS.register(this); } @Override public void init() { flansModClient = new FlansModClient(); flansModClient.load(); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityItemHolder.class, new RenderItemHolder()); // Create one event handler for the client and register it with MC Forge and FML ClientEventHandler eventHandler = new ClientEventHandler(); MinecraftForge.EVENT_BUS.register(eventHandler); } @SubscribeEvent public void registerSoundEvents(RegistryEvent.Register event) { FlansMod.log.info("Registering sounds."); for(SoundEvent sound : eventsToRegister) { event.getRegistry().register(sound); } event.getRegistry().register(FlansModResourceHandler.getSoundEvent("bulletFlyby")); event.getRegistry().register(FlansModResourceHandler.getSoundEvent("UnlockNotch")); } @SubscribeEvent public void registerModels(ModelRegistryEvent event) { //ItemModelMesher mesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher(); FlansMod.log.info("Registering models."); //Register a null vanilla renderer to avoid error messages spamming chat - doesn't work. for(InfoType type : InfoType.infoTypes.values()) { if(type != null && type.item != null) { if(type instanceof PaintableType) { for(Paintjob paintjob : ((PaintableType)type).paintjobs) { ModelLoader.registerItemVariants(type.item, new ResourceLocation("flansmod:" + type.shortName + (paintjob.iconName.equals("") ? "" : ("_" + paintjob.iconName)))); ModelLoader.setCustomModelResourceLocation(type.item, paintjob.ID, new ModelResourceLocation("flansmod:" + type.shortName + (paintjob.iconName.equals("") ? "" : ("_" + paintjob.iconName)), "inventory")); } } else ModelLoader.setCustomModelResourceLocation(type.item, 0, new ModelResourceLocation("flansmod:" + type.shortName, "inventory")); } } FlansMod.Assert(FlansMod.workbenchItem == Item.getItemFromBlock(FlansMod.workbench), "ItemBlock Mismatch"); ModelLoader.setCustomModelResourceLocation(FlansMod.workbenchItem, 0, new ModelResourceLocation("flansmod:flansworkbench_guns", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.workbenchItem, 0, new ModelResourceLocation("flansmod:flansworkbench_guns", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.workbenchItem, 1, new ModelResourceLocation("flansmod:flansworkbench_vehicles", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.workbenchItem, 2, new ModelResourceLocation("flansmod:flansworkbench_parts", "inventory")); ModelLoader.registerItemVariants(FlansMod.workbenchItem, new ResourceLocation("flansmod:flansWorkbench_guns"), new ResourceLocation("flansmod:flansWorkbench_parts"), new ResourceLocation("flansmod:flansWorkbench_vehicles")); ModelLoader.setCustomModelResourceLocation(FlansMod.opStick, 0, new ModelResourceLocation("flansmod:opstick_Ownership", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.opStick, 1, new ModelResourceLocation("flansmod:opstick_Connecting", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.opStick, 2, new ModelResourceLocation("flansmod:opstick_Mapping", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.opStick, 3, new ModelResourceLocation("flansmod:opstick_Destruction", "inventory")); ModelLoader.registerItemVariants(FlansMod.opStick, new ResourceLocation("flansmod:opstick_Ownership"), new ResourceLocation("flansmod:opstick_Connecting"), new ResourceLocation("flansmod:opstick_Mapping"), new ResourceLocation("flansmod:opstick_Destruction")); ModelLoader.setCustomModelResourceLocation(FlansMod.spawnerItem, 0, new ModelResourceLocation("flansmod:teamsSpawner_items", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.spawnerItem, 1, new ModelResourceLocation("flansmod:teamsSpawner_players", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.spawnerItem, 2, new ModelResourceLocation("flansmod:teamsSpawner_vehicles", "inventory")); ModelLoader.registerItemVariants(FlansMod.spawnerItem, new ResourceLocation("flansmod:teamsSpawner_items"), new ResourceLocation("flansmod:teamsSpawner_players"), new ResourceLocation("flansmod:teamsSpawner_vehicles")); ModelLoader.setCustomModelResourceLocation(FlansMod.flag, 0, new ModelResourceLocation("flansmod:flagpole", "inventory")); ModelLoader.setCustomModelResourceLocation(FlansMod.rainbowPaintcan, 0, new ModelResourceLocation("flansmod:rainbowPaintcan", "inventory")); ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(FlansMod.paintjobTable), 0, new ModelResourceLocation("flansmod:paintjobTable", "inventory")); ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(FlansMod.gunpowderBlock), 0, new ModelResourceLocation("flansmod:gunpowderblock", "inventory")); ModelLoader.registerItemVariants(Item.getItemFromBlock(FlansMod.paintjobTable), new ResourceLocation("flansmod:paintjobTable")); ModelLoader.setCustomModelResourceLocation(FlansMod.crosshairsymbol, 0, new ModelResourceLocation("flansmod:crosshairsymbol", "inventory")); } /** * This method reloads all textures from all mods and resource packs. It forces Minecraft to read images from the content packs added after mod init */ @Override public void forceReload() { FMLClientHandler.instance().refreshResources(VanillaResourceType.MODELS, VanillaResourceType.TEXTURES, VanillaResourceType.SOUNDS, VanillaResourceType.LANGUAGES); } /** * This method grabs all the content packs and puts them in a list. The client side part registers them as FMLModContainers which adds their resources to the game after a refresh */ @Override public void LoadAssetsFromFlanFolder() { // Icons, Skins, Models // Get the classloader in order to load the images ClassLoader classloader = (net.minecraft.client.Minecraft.class).getClassLoader(); Method method = null; try { method = (java.net.URLClassLoader.class).getDeclaredMethod("addURL", java.net.URL.class); method.setAccessible(true); } catch(Exception e) { FlansMod.log.error("Failed to get class loader. All content loading will now fail."); FlansMod.log.throwing(e); } for(File file : FlansMod.flanDir.listFiles()) { if(file.isDirectory() || zipJar.matcher(file.getName()).matches()) { try { method.invoke(classloader, file.toURI().toURL()); HashMap map = new HashMap<>(); map.put("modid", FlansMod.MODID); map.put("name", "Flan's Mod : " + file.getName()); map.put("version", "1"); FMLModContainer container = new FMLModContainer("com.flansmod.common.FlansMod", new ModCandidate(file, file, file.isDirectory() ? ContainerType.DIR : ContainerType.JAR), map); container.bindMetadata(MetadataCollection.from(null, "")); FMLClientHandler.instance().addModAsResource(container); } catch(Exception e) { FlansMod.log.error("Failed to load images for content pack : " + file.getName()); FlansMod.log.throwing(e); } // Add the directory to the content pack list FlansMod.log.info("Loaded content pack : " + file.getName()); } } FlansMod.log.info("Loaded textures and models."); } /** * Register entity renderers */ @Override public void registerRenderers() { FlansMod.log.info("Registering Renderers"); RenderingRegistry.registerEntityRenderingHandler(EntityBullet.class, new RenderBullet.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityGrenade.class, new RenderGrenade.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityPlane.class, new RenderPlane.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityVehicle.class, new RenderVehicle.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityAAGun.class, new RenderAAGun.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityFlagpole.class, new RenderFlagpole.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityFlag.class, new RenderFlag.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntitySeat.class, new RenderNull.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityWheel.class, new RenderNull.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityMG.class, new RenderMG.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityParachute.class, new RenderParachute.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityDebugDot.class, new RenderDebugDot.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityDebugVector.class, new RenderDebugVector.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityDebugAABB.class, new RenderDebugAABB.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityMecha.class, new RenderMecha.Factory()); RenderingRegistry.registerEntityRenderingHandler(EntityItemCustomRender.class, new RenderGunItem.Factory()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntitySpawner.class, new TileEntitySpawnerRenderer()); } /** * Old one time tutorial code that displays messages the first time you enter a plane / vehicle. Needs reworking */ @Override public void doTutorialStuff(EntityPlayer player, EntityDriveable entityType) { if(!FlansModClient.doneTutorial) { FlansModClient.doneTutorial = true; player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.vehicleMenuKey.getKeyCode()) + " to open the menu")); player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(Minecraft.getMinecraft().gameSettings.keyBindSneak.getKeyCode()) + " to get out")); player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.controlSwitchKey.getKeyCode()) + " to switch controls")); player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.modeKey.getKeyCode()) + " to switch VTOL mode")); if(entityType instanceof EntityPlane) { if(PlaneType.getPlane(((EntityPlane)entityType).driveableType).hasGear) player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.gearKey.getKeyCode()) + " to switch the gear")); if(PlaneType.getPlane(((EntityPlane)entityType).driveableType).hasDoor) player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.doorKey.getKeyCode()) + " to switch the doors")); if(PlaneType.getPlane(((EntityPlane)entityType).driveableType).hasWing) player.sendMessage(new TextComponentString("Press " + Keyboard.getKeyName(KeyInputHandler.modeKey.getKeyCode()) + " to switch the wings")); } } } /** * Adds the client side text message regarding mouse control mode switching */ @Override public void changeControlMode(EntityPlayer player) { if(FlansModClient.flipControlMode()) player.sendMessage(new TextComponentString("Mouse Control mode is now set to " + FlansModClient.controlModeMouse)); } /** * Whether the player is in mouse control mode for planes. Now the default setting for planes, but it can be deactivated to look around while flying */ @Override public boolean mouseControlEnabled() { return FlansModClient.controlModeMouse; } /** * Client GUI object getter */ @Override public Object getClientGui(int ID, EntityPlayer player, World world, int x, int y, int z) { //Null riding entity, don't open GUI in this case if(((ID >= 6 && ID <= 10) || ID == 12) && player.getRidingEntity() == null) return null; switch(ID) { case 0: return new GuiDriveableCrafting(player.inventory); case 1: return new GuiDriveableRepair(player); case 2: return new GuiGunModTable(player.inventory, world); case 5: return new GuiGunBox(player.inventory, ((BlockGunBox)world.getBlockState(new BlockPos(x, y, z)).getBlock()).type); case 6: return new GuiDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 0); case 7: return new GuiDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 1); case 8: return new GuiDriveableFuel(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable); case 9: return new GuiDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 2); case 10: return new GuiMechaInventory(player.inventory, world, (EntityMecha)((EntitySeat)player.getRidingEntity()).driveable); case 11: return new GuiArmourBox(player.inventory, ((BlockArmourBox)world.getBlockState(new BlockPos(x, y, z)).getBlock()).type); case 12: return new GuiDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 3); case 13: return new GuiPaintjobTable(player.inventory, world, (TileEntityPaintjobTable)world.getTileEntity(new BlockPos(x, y, z))); } return null; } /** * Called when the player presses the plane inventory key. Opens menu client side */ @Override public void openDriveableMenu(EntityPlayer player, World world, EntityDriveable driveable) { FMLClientHandler.instance().getClient().displayGuiScreen(new GuiDriveableMenu(player.inventory, world, driveable)); } /** * Helper method that sorts out packages with model name input * For example, the model class "com.flansmod.client.model.mw.ModelMP5" * is referenced in the type file by the string "mw.MP5" */ private String getModelName(String in) { //Split about dots String[] split = in.split("\\."); //If there is no dot, our model class is in the default model package if(split.length == 1) return modelDir + "Model" + in; //Otherwise, we need to slightly rearrange the wording of the string for it to make sense else if(split.length > 1) { if(split.length == 2 && FlansMod.modelDirectories.containsKey(split[0])) { return FlansMod.modelDirectories.get(split[0]) + ".Model" + split[1]; } else { String out = "Model" + split[split.length - 1]; for(int i = split.length - 2; i >= 0; i--) { out = split[i] + "." + out; } return modelDir + out; } } return modelDir + in; } /** * Generic model loader method for getting model classes and casting them to the required class type */ @Override public T loadModel(String s, String shortName, Class typeClass) { if(s == null || shortName == null) return null; try { return typeClass.cast(Class.forName(getModelName(s)).getConstructor().newInstance()); } catch(Exception e) { FlansMod.log.error("Failed to load model : " + shortName + " (" + s + ")"); FlansMod.log.throwing(e); } return null; } /** * Sound loading method. Defers to FlansModResourceHandler */ @Override public void loadSound(String contentPack, String type, String sound) { SoundEvent event = FlansModResourceHandler.getSoundEvent(sound); if(event == null) { FlansMod.log.warn("Null sound event"); return; } if(!eventsToRegister.contains(event)) { eventsToRegister.add(event); } } /** * Checks whether "player" is the current player. Always false on server, since there is no current player */ @Override public boolean isThePlayer(EntityPlayer player) { return player == FMLClientHandler.instance().getClient().player; } /* Gun and armour box crafting methods */ @Override public void buyGun(GunBoxType type, InfoType gun) { FlansMod.getPacketHandler().sendToServer(new PacketBuyWeapon(type, gun)); PlayerData data = PlayerHandler.getPlayerData(Minecraft.getMinecraft().player); data.shootTimeLeft = data.shootTimeRight = 10; } @Override public void buyArmour(String shortName, int piece, ArmourBoxType box) { FlansMod.getPacketHandler().sendToServer(new PacketBuyArmour(box.shortName, shortName, piece)); PlayerData data = PlayerHandler.getPlayerData(Minecraft.getMinecraft().player); data.shootTimeLeft = data.shootTimeRight = 10; } @Override public void craftDriveable(EntityPlayer player, DriveableType type) { //Craft it this side (so the inventory updates immediately) and then send a packet to the server so that it is crafted that side too super.craftDriveable(player, type); if(player.world.isRemote) FlansMod.getPacketHandler().sendToServer(new PacketCraftDriveable(type.shortName)); } @Override public void repairDriveable(EntityPlayer driver, EntityDriveable driving, DriveablePart part) { //Repair it this side (so the inventory updates immediately) and then send a packet to the server so that it is repaired that side too super.repairDriveable(driver, driving, part); if(driver.world.isRemote) FlansMod.getPacketHandler().sendToServer(new PacketRepairDriveable(part.type)); } /** * Helper method that returns whether there is a GUI open */ @Override public boolean isScreenOpen() { return Minecraft.getMinecraft().currentScreen != null; } /** * Mecha input getters */ @Override public boolean isKeyDown(int key) { switch(key) { case 0: //Press Forwards return keyDown(Minecraft.getMinecraft().gameSettings.keyBindForward.getKeyCode()); case 1: //Press Backwards return keyDown(Minecraft.getMinecraft().gameSettings.keyBindBack.getKeyCode()); case 2: //Press Left return keyDown(Minecraft.getMinecraft().gameSettings.keyBindLeft.getKeyCode()); case 3: //Press Right return keyDown(Minecraft.getMinecraft().gameSettings.keyBindRight.getKeyCode()); case 4: //Press Jump return keyDown(Minecraft.getMinecraft().gameSettings.keyBindJump.getKeyCode()); } return false; } /** * Helper method that deals with the way Minecraft handles binding keys to the mouse */ @Override public boolean keyDown(int keyCode) { return (keyCode < 0 ? Mouse.isButtonDown(keyCode + 100) : Keyboard.isKeyDown(keyCode)); } @SubscribeEvent public void playerClick(PlayerInteractEvent event) { Vec3d eye = event.getEntityPlayer().getPositionEyes(0f); Vec3d look = event.getEntityPlayer().getLookVec(); double interactDistance = event.getEntityPlayer().getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue(); look.normalize(); look.scale(interactDistance); if(event instanceof PlayerInteractEvent.LeftClickBlock || event instanceof PlayerInteractEvent.RightClickBlock) interactDistance = Math.min(interactDistance, Math.sqrt(event.getPos().distanceSq(eye.x, eye.y, eye.z))); if(event instanceof PlayerInteractEvent.EntityInteractSpecific) interactDistance = Math.min(interactDistance, ((PlayerInteractEvent.EntityInteractSpecific)event).getLocalPos().distanceTo(eye)); if(event instanceof PlayerInteractEvent.EntityInteract) interactDistance = Math.min(interactDistance, ((PlayerInteractEvent.EntityInteract)event).getTarget().getDistance(eye.x, eye.y, eye.z)); for(Entity entity : event.getWorld().getLoadedEntityList()) { if(entity instanceof EntityDriveable) { EntityDriveable d = (EntityDriveable)entity; // Quick sphere ray intersect test Vec3d L = entity.getPositionVector().subtract(eye); double tca = L.dotProduct(look); if (tca < 0) continue; double d2 = L.dotProduct(L) - tca * tca; if (d2 > d.getDriveableType().hitboxRadius) continue; // Check against collision boxes DriveablePart partHit = d.raytraceParts(new Vector3f(eye), new Vector3f(look)); if(event instanceof PlayerInteractEvent.LeftClickEmpty || event instanceof PlayerInteractEvent.LeftClickBlock) Minecraft.getMinecraft().playerController.attackEntity(event.getEntityPlayer(), d); if(event instanceof PlayerInteractEvent.RightClickEmpty || event instanceof PlayerInteractEvent.RightClickBlock) Minecraft.getMinecraft().playerController.interactWithEntity(event.getEntityPlayer(), d, event.getHand()); if(event instanceof PlayerInteractEvent.RightClickItem) { event.setCanceled(true); } } } } @Override public void addMissingJSONs(HashMap types) { for(InfoType type : types.values()) { try { EnumType typeToCheckFor = EnumType.getFromObject(type); File contentPackDir = new File(FlansMod.flanDir, type.contentPack); if(contentPackDir.isDirectory()) { File itemModelsDir = new File(contentPackDir, "/assets/flansmod/models/item"); if(!itemModelsDir.exists()) itemModelsDir.mkdirs(); File blockModelsDir = new File(contentPackDir, "/assets/flansmod/models/block"); if(!blockModelsDir.exists()) blockModelsDir.mkdirs(); File blockstatesDir = new File(contentPackDir, "/assets/flansmod/blockstates"); if(!blockstatesDir.exists()) blockstatesDir.mkdirs(); //Do block json for boxes if(typeToCheckFor == EnumType.armourBox || typeToCheckFor == EnumType.box) { BoxType box = (BoxType)type; createJSONFile(new File(itemModelsDir, type.shortName.toLowerCase() + "_item.json"), "{ \"parent\": \"flansmod:block/" + type.shortName + "\", \"display\": { \"thirdperson\": { \"rotation\": [ 10, -45, 170 ], \"translation\": [ 0, 1.5, -2.75 ], \"scale\": [ 0.375, 0.375, 0.375 ] } } }"); createJSONFile(new File(blockModelsDir, type.shortName.toLowerCase() + ".json"), "{ \"parent\": \"block/cube\", \"textures\": { \"particle\": \"flansmod:blocks/" + box.sideTexturePath + "\", \"down\": \"flansmod:blocks/" + box.bottomTexturePath + "\", \"up\": \"flansmod:blocks/" + box.topTexturePath + "\", \"north\": \"flansmod:blocks/" + box.sideTexturePath + "\", \"east\": \"flansmod:blocks/" + box.sideTexturePath + "\", \"south\": \"flansmod:blocks/" + box.sideTexturePath + "\", \"west\": \"flansmod:blocks/" + box.sideTexturePath + "\" } } "); createJSONFile(new File(blockstatesDir, type.shortName.toLowerCase() + ".json"), "{ \"variants\": { \"normal\": { \"model\": \"flansmod:" + type.shortName + "\" } } }"); } else if(type instanceof PaintableType && type.GetModel() != null) { for(Paintjob paintjob : ((PaintableType)type).paintjobs) { createJSONFile(new File(itemModelsDir, (type.shortName + (paintjob.iconName.equals("") ? "" : ("_" + paintjob.iconName)) + ".json").toLowerCase()), "{ \"parent\": \"builtin/generated\", \"textures\": { \"layer0\": \"flansmod:items/" + type.iconPath + (paintjob.iconName.equals("") ? "" : ("_" + paintjob.iconName)) + "\" }," + " \"display\": { " + "\"thirdperson_righthand\": { \"rotation\": [ 0, 90, -45 ], \"translation\": [ 0, 2, -2 ], \"scale\": [ 0, 0, 0 ] }," + " \"thirdperson_lefthand\": { \"rotation\": [ 0, 90, -45 ], \"translation\": [ 0, 2, -2 ], \"scale\": [ 0, 0, 0 ] }," + " \"firstperson_righthand\": { \"rotation\": [ 0, -135, 25 ], \"translation\": [ 0, 4, 2 ], \"scale\": [ 1, 1, 1 ] }," + " \"firstperson_lefthand\": { \"rotation\": [ 0, -135, 25 ], \"translation\": [ 0, 4, 2 ], \"scale\": [ 1, 1, 1 ] } " + "} }"); } } else if(typeToCheckFor == EnumType.itemHolder) { createJSONFile(new File(blockstatesDir, type.shortName.toLowerCase() + ".json"), "{ \"variants\": { \"facing=north\": { \"model\": \"flansmod:" + type.shortName + "\" }, \"facing=east\": { \"model\": \"flansmod:" + type.shortName + "\" }, \"facing=south\": { \"model\": \"flansmod:" + type.shortName + "\" }, \"facing=west\": { \"model\": \"flansmod:" + type.shortName + "\" } } }"); createJSONFile(new File(blockModelsDir, type.shortName.toLowerCase() + ".json"), "{ \"ambientocclusion\": false, \"textures\": { \"particle\": \"flansmod:items/" + type.iconPath + "\" }, \"elements\": [ {\"from\": [ 0, 0, 0 ],\"to\": [ 0, 0, 0 ], \"faces\": { \"down\": { \"texture\": \"#down\", \"cullface\": \"down\" }, \"up\": { \"texture\": \"#up\", \"cullface\": \"up\" }, \"north\": { \"texture\": \"#north\", \"cullface\": \"north\" }, \"south\": { \"texture\": \"#south\", \"cullface\": \"south\" }, \"west\": { \"texture\": \"#west\", \"cullface\": \"west\" }, \"east\": { \"texture\": \"#east\", \"cullface\": \"east\" } } } ] }"); createJSONFile(new File(itemModelsDir, type.shortName.toLowerCase() + "_item.json"), "{ \"parent\": \"builtin/generated\", \"textures\": { \"layer0\": \"flansmod:items/" + type.iconPath + "\" }, \"display\": { \"thirdperson\": { \"rotation\": [ -90, 0, 0 ], \"translation\": [ 0, 1, -3 ], \"scale\": [ 0.55, 0.55, 0.55 ] }, \"firstperson\": { \"rotation\": [ 0, -135, 25 ], \"translation\": [ 0, 4, 2 ], \"scale\": [ 1.7, 1.7, 1.7 ] } } }"); } //Create the item JSON for normal items else if(typeToCheckFor != EnumType.team && typeToCheckFor != EnumType.playerClass) { createJSONFile(new File(itemModelsDir, type.shortName.toLowerCase() + ".json"), "{ \"parent\": \"builtin/generated\", \"textures\": { \"layer0\": \"flansmod:items/" + type.iconPath + "\" }, \"display\": { " + "\"thirdperson_lefthand\": { \"rotation\": [ 0, 90, -35 ], \"translation\": [ 0, 1.25, -2.5 ], \"scale\": [ 0.85, 0.85, 0.85 ] }, " + "\"thirdperson_righthand\": { \"rotation\": [ 0, 90, -35 ], \"translation\": [ 0, 1.25, -2.5 ], \"scale\": [ 0.85, 0.85, 0.85 ] }, " + "\"firstperson_lefthand\": { \"rotation\": [ 0, -45, 25 ], \"translation\": [ 0, 4, 2 ], \"scale\": [ 0.85, 0.85, 0.85 ] }, " + "\"firstperson_righthand\": { \"rotation\": [ 0, -45, 25 ], \"translation\": [ 0, 4, 2 ], \"scale\": [ 0.85, 0.85, 0.85 ] }" + " } }"); } } } catch(Exception e) { FlansMod.log.throwing(e); } } } private void createJSONFile(File file, String contents) throws Exception { if(FlansMod.forceUpdateJSONs) { if(file.exists()) { if(!file.delete()) FlansMod.log.warn("FAILED TO DELETE"); } file.createNewFile(); BufferedWriter out = new BufferedWriter(new FileWriter(file)); out.write(contents); out.close(); } else if(!file.exists()) { file.createNewFile(); BufferedWriter out = new BufferedWriter(new FileWriter(file)); out.write(contents); out.close(); } } } ================================================ FILE: src/main/java/com/flansmod/client/ClientRenderHooks.java ================================================ package com.flansmod.client; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.util.glu.Project; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.model.ModelBiped.ArmPose; import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderLivingBase; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.MouseHelper; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraftforge.client.event.EntityViewRenderEvent.CameraSetup; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; import net.minecraftforge.client.event.RenderItemInFrameEvent; import net.minecraftforge.client.event.RenderLivingEvent; import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.event.RenderSpecificHandEvent; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.client.gui.teams.GuiTeamScores; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.model.CustomItemRenderType; import com.flansmod.client.model.CustomItemRenderer; import com.flansmod.client.model.RenderGrenade; import com.flansmod.client.model.RenderGun; import com.flansmod.client.model.RenderMecha; import com.flansmod.client.model.RenderPlane; import com.flansmod.client.model.RenderVehicle; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.network.PacketTeamInfo; import com.flansmod.common.network.PacketTeamInfo.PlayerScoreData; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.teams.ItemTeamArmour; import com.flansmod.common.teams.Team; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; @SideOnly(Side.CLIENT) public class ClientRenderHooks { public static final ResourceLocation hitMarker = new ResourceLocation("flansmod", "gui/hitMarker.png"); private Minecraft mc; private float fovModifierHand; private float equippedProgress, prevEquippedProgress; private ItemStack itemToRender = ItemStack.EMPTY.copy(); private int equippedItemSlot; private float partialTicks; private MouseHelper constantMouseHelper = new MouseHelper() { @Override public void mouseXYChange() { deltaX = 0; deltaY = 0; } }; private static RenderItem itemRenderer = Minecraft.getMinecraft().getRenderItem(); private static List killMessages = new ArrayList<>(); private CustomItemRenderer[] customRenderers = new CustomItemRenderer[EnumType.values().length]; public ClientRenderHooks() { mc = Minecraft.getMinecraft(); RenderManager rm = Minecraft.getMinecraft().getRenderManager(); customRenderers[EnumType.gun.ordinal()] = ClientProxy.gunRenderer = new RenderGun(); customRenderers[EnumType.grenade.ordinal()] = new RenderGrenade(rm); customRenderers[EnumType.plane.ordinal()] = new RenderPlane(rm); customRenderers[EnumType.vehicle.ordinal()] = new RenderVehicle(rm); customRenderers[EnumType.mecha.ordinal()] = new RenderMecha(rm); } /** * Render guns in 3D in item frames */ public void renderItemFrame(RenderItemInFrameEvent event) { if(event.getItem().getItem() instanceof ItemGun) { GunType type = ((ItemGun)event.getItem().getItem()).GetType(); if(type.model != null) { event.setCanceled(true); int rotation = event.getEntityItemFrame().getRotation(); GlStateManager.rotate(-rotation * 45F, 0F, 0F, 1F); RenderHelper.enableStandardItemLighting(); GlStateManager.rotate(rotation * 45F, 0F, 0F, 1F); GlStateManager.pushMatrix(); float scale = 0.75F; GlStateManager.scale(scale, scale, scale); GlStateManager.translate(0.15F, -0.15F, 0F); ClientProxy.gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, event.getItem()); GlStateManager.popMatrix(); } } } /** * When Minecraft would render a 2D gun item, instead cancel it and render the gun properly. Render the offhand gun * too. */ public void renderHeldItem(RenderSpecificHandEvent event) { ItemStack stack = event.getItemStack(); if(stack.getItem() instanceof IFlanItem) { InfoType type = ((IFlanItem)stack.getItem()).getInfoType(); // Muhahaha EnumType typeType = EnumType.getFromObject(type); if(customRenderers[typeType.ordinal()] != null && type.GetModel() != null) { // Cancel the hand render event so that we can do our own. event.setCanceled(true); float partialTicks = event.getPartialTicks(); EntityRenderer renderer = mc.entityRenderer; float farPlaneDistance = mc.gameSettings.renderDistanceChunks * 16F; ItemRenderer itemRenderer = mc.getItemRenderer(); //Unknown function. But definitely messes up the render pipeline, causing other mods and shaders to break //GlStateManager.clear(256); GlStateManager.matrixMode(5889); GlStateManager.loadIdentity(); Project.gluPerspective(getFOVModifier(partialTicks), (float)mc.displayWidth / (float)mc.displayHeight, 0.05F, farPlaneDistance * 2.0F); GlStateManager.matrixMode(5888); GlStateManager.loadIdentity(); GlStateManager.pushMatrix(); hurtCameraEffect(partialTicks); if(mc.gameSettings.viewBobbing) setupViewBobbing(partialTicks); boolean flag = mc.getRenderViewEntity() instanceof EntityLivingBase && ((EntityLivingBase)mc.getRenderViewEntity()).isPlayerSleeping(); if(mc.gameSettings.thirdPersonView == 0 && !flag && !mc.gameSettings.hideGUI && !mc.playerController.isSpectator()) { renderer.enableLightmap(); float f1 = 1.0F - (prevEquippedProgress + (equippedProgress - prevEquippedProgress) * partialTicks); EntityPlayerSP entityplayersp = this.mc.player; float f2 = entityplayersp.getSwingProgress(partialTicks); float f3 = entityplayersp.prevRotationPitch + (entityplayersp.rotationPitch - entityplayersp.prevRotationPitch) * partialTicks; float f4 = entityplayersp.prevRotationYaw + (entityplayersp.rotationYaw - entityplayersp.prevRotationYaw) * partialTicks; // Setup lighting GlStateManager.disableLighting(); GlStateManager.pushMatrix(); GlStateManager.rotate(f3, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(f4, 0.0F, 1.0F, 0.0F); RenderHelper.enableStandardItemLighting(); GlStateManager.popMatrix(); // Do lighting int i = this.mc.world.getCombinedLight(new BlockPos(entityplayersp.posX, entityplayersp.posY + (double)entityplayersp.getEyeHeight(), entityplayersp.posZ), 0); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)(i & 65535), (float)(i >> 16)); // Do hand rotations float f5 = entityplayersp.prevRenderArmPitch + (entityplayersp.renderArmPitch - entityplayersp.prevRenderArmPitch) * partialTicks; float f6 = entityplayersp.prevRenderArmYaw + (entityplayersp.renderArmYaw - entityplayersp.prevRenderArmYaw) * partialTicks; GlStateManager.rotate((entityplayersp.rotationPitch - f5) * 0.1F, 1.0F, 0.0F, 0.0F); GlStateManager.rotate((entityplayersp.rotationYaw - f6) * 0.1F, 0.0F, 1.0F, 0.0F); GlStateManager.enableRescaleNormal(); GlStateManager.pushMatrix(); // Do vanilla weapon swing float f7 = -0.4F * MathHelper.sin(MathHelper.sqrt(f2) * (float)Math.PI); float f8 = 0.2F * MathHelper.sin(MathHelper.sqrt(f2) * (float)Math.PI * 2.0F); float f9 = -0.2F * MathHelper.sin(f2 * (float)Math.PI); GlStateManager.translate(f7, f8, f9); GlStateManager.translate(0.56F, -0.52F, -0.71999997F); GlStateManager.translate(0.0F, f1 * -0.6F, 0.0F); GlStateManager.rotate(45.0F, 0.0F, 1.0F, 0.0F); float f10 = MathHelper.sin(f2 * f2 * (float)Math.PI); float f11 = MathHelper.sin(MathHelper.sqrt(f2) * (float)Math.PI); GlStateManager.rotate(f10 * -20.0F, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(f11 * -20.0F, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(f11 * -80.0F, 1.0F, 0.0F, 0.0F); GlStateManager.scale(0.4F, 0.4F, 0.4F); customRenderers[typeType.ordinal()] .renderItem(CustomItemRenderType.EQUIPPED_FIRST_PERSON, event.getHand(), stack, mc.world, mc.player); GlStateManager.popMatrix(); GlStateManager.disableRescaleNormal(); RenderHelper.disableStandardItemLighting(); renderer.disableLightmap(); } GlStateManager.popMatrix(); if(mc.gameSettings.thirdPersonView == 0 && !flag) { itemRenderer.renderOverlays(partialTicks); hurtCameraEffect(partialTicks); } if(mc.gameSettings.viewBobbing) { setupViewBobbing(partialTicks); } } } } private void hurtCameraEffect(float partialTicks) { if(this.mc.getRenderViewEntity() instanceof EntityLivingBase) { EntityLivingBase entitylivingbase = (EntityLivingBase)this.mc.getRenderViewEntity(); float f1 = (float)entitylivingbase.hurtTime - partialTicks; float f2; if(entitylivingbase.getHealth() <= 0.0F) { f2 = (float)entitylivingbase.deathTime + partialTicks; GlStateManager.rotate(40.0F - 8000.0F / (f2 + 200.0F), 0.0F, 0.0F, 1.0F); } if(f1 < 0.0F) { return; } f1 /= (float)entitylivingbase.maxHurtTime; f1 = MathHelper.sin(f1 * f1 * f1 * f1 * (float)Math.PI); f2 = entitylivingbase.attackedAtYaw; GlStateManager.rotate(-f2, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(-f1 * 14.0F, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(f2, 0.0F, 1.0F, 0.0F); } } private void setupViewBobbing(float partialTicks) { if(this.mc.getRenderViewEntity() instanceof EntityPlayer) { EntityPlayer entityplayer = (EntityPlayer)this.mc.getRenderViewEntity(); float f1 = entityplayer.distanceWalkedModified - entityplayer.prevDistanceWalkedModified; float f2 = -(entityplayer.distanceWalkedModified + f1 * partialTicks); float f3 = entityplayer.prevCameraYaw + (entityplayer.cameraYaw - entityplayer.prevCameraYaw) * partialTicks; float f4 = entityplayer.prevCameraPitch + (entityplayer.cameraPitch - entityplayer.prevCameraPitch) * partialTicks; GlStateManager.translate(MathHelper.sin(f2 * (float)Math.PI) * f3 * 0.5F, -Math.abs(MathHelper.cos(f2 * (float)Math.PI) * f3), 0.0F); GlStateManager.rotate(MathHelper.sin(f2 * (float)Math.PI) * f3 * 3.0F, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(Math.abs(MathHelper.cos(f2 * (float)Math.PI - 0.2F) * f3) * 5.0F, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(f4, 1.0F, 0.0F, 0.0F); } } private float getFOVModifier(float partialTicks) { Entity entity = this.mc.getRenderViewEntity(); float f1 = 70.0F; if(entity instanceof EntityLivingBase && ((EntityLivingBase)entity).getHealth() <= 0.0F) { float f2 = (float)((EntityLivingBase)entity).deathTime + partialTicks; f1 /= (1.0F - 500.0F / (f2 + 500.0F)) * 2.0F + 1.0F; } IBlockState state = ActiveRenderInfo.getBlockStateAtEntityViewpoint(this.mc.world, entity, partialTicks); if(state.getMaterial() == Material.WATER) f1 = f1 * 60.0F / 70.0F; return f1; } public void update() { for(Iterator it = killMessages.iterator(); it.hasNext(); ) { KillMessage message = it.next(); message.timer--; if(message.timer == 0) { it.remove(); } } // Update the FOV Modifier float fovModifier = 1.0F; if(mc.getRenderViewEntity() instanceof AbstractClientPlayer) { AbstractClientPlayer abstractclientplayer = (AbstractClientPlayer)this.mc.getRenderViewEntity(); fovModifier = abstractclientplayer.getFovModifier(); } // Adjust FOV modifier fovModifierHand += (fovModifier - fovModifierHand) * 0.5F; // Limit FOV modifier to a certain range if(fovModifierHand > 1.5F) fovModifierHand = 1.5F; if(fovModifierHand < 0.1F) fovModifierHand = 0.1F; // And update the itemToRender, for item switching prevEquippedProgress = equippedProgress; EntityPlayerSP player = mc.player; if(player != null) { ItemStack itemstack = player.inventory.getCurrentItem(); boolean equippedGun = false; if(itemToRender != null && !itemToRender.isEmpty() && !itemstack.isEmpty()) { if(!ItemStack.areItemsEqual(itemToRender, itemstack)) { if(!itemToRender.getItem().shouldCauseReequipAnimation(itemToRender, itemstack, equippedItemSlot != player.inventory.currentItem)) { itemToRender = itemstack; equippedItemSlot = player.inventory.currentItem; return; } equippedGun = true; } } else { equippedGun = (itemToRender != null && !itemToRender.isEmpty()) || !itemstack.isEmpty(); } float maxChange = 0.4F; float targetProgress = equippedGun ? 0.0F : 1.0F; float difference = MathHelper.clamp(targetProgress - equippedProgress, -maxChange, maxChange); equippedProgress += difference; if(equippedProgress < 0.1F) { itemToRender = itemstack; equippedItemSlot = player.inventory.currentItem; } // Render debug boxes for player snapshots PlayerData data = PlayerHandler.getPlayerData(player); if(FlansMod.DEBUG && data != null) { if(data.snapshots[0] != null) data.snapshots[0].renderSnapshot(); } } } public void setPartialTick(float partialTick) { this.partialTicks = partialTick; } public void renderThirdPersonWeapons(RenderLivingEvent.Pre event) { ModelBase mainModel = event.getRenderer().getMainModel(); EntityLivingBase entity = event.getEntity(); for(int i = 0; i < 2; i++) { EnumHand hand = EnumHand.values()[i]; entity.getHeldItem(hand); if(entity.getHeldItem(hand).getItem() instanceof ItemGun && mainModel instanceof ModelBiped) { ModelBiped biped = (ModelBiped)mainModel; ItemStack stack = entity.getHeldItem(hand); GunType type = ((ItemGun)stack.getItem()).GetType(); if(type.model == null) return; GlStateManager.pushMatrix(); GlStateManager.disableCull(); mainModel.swingProgress = entity.getSwingProgress(partialTicks); mainModel.isRiding = entity.isRiding(); mainModel.isChild = entity.isChild(); float f2 = this.interpolateRotation(entity.prevRenderYawOffset, entity.renderYawOffset, partialTicks); float f3 = this.interpolateRotation(entity.prevRotationYawHead, entity.rotationYawHead, partialTicks); float f4; float f5; if(Math.abs(entity.prevRenderYawOffset - entity.renderYawOffset) > 30F) f2 = entity.renderYawOffset; if(Math.abs(entity.prevRotationYawHead - entity.rotationYawHead) > 30F) f3 = entity.rotationYawHead; f4 = f3 - f2; if(entity.isRiding() && entity.getRidingEntity() instanceof EntityLivingBase) { EntityLivingBase entityLivingBase = (EntityLivingBase)entity.getRidingEntity(); f2 = this.interpolateRotation(entityLivingBase.prevRenderYawOffset, entityLivingBase.renderYawOffset, partialTicks); f4 = f3 - f2; f5 = MathHelper.wrapDegrees(f4); if(f5 < -85.0F) { f5 = -85.0F; } if(f5 >= 85.0F) { f5 = 85.0F; } f2 = f3 - f5; if(f5 * f5 > 2500.0F) { f2 += f5 * 0.2F; } } float f9 = entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * partialTicks; if(Math.abs(entity.prevRotationPitch - entity.rotationPitch) > 5F) f9 = entity.rotationPitch; GlStateManager.translate(event.getX(), event.getY(), event.getZ()); f5 = entity.ticksExisted + partialTicks; GlStateManager.rotate(180.0F - f2, 0.0F, 1.0F, 0.0F); GlStateManager.enableRescaleNormal(); GlStateManager.scale(-1.0F, -1.0F, 1.0F); GlStateManager.translate(0.0F, -1.5078125F, 0.0F); float f7 = entity.prevLimbSwingAmount + (entity.limbSwingAmount - entity.prevLimbSwingAmount) * partialTicks; float f8 = entity.limbSwing - entity.limbSwingAmount * (1.0F - partialTicks); if(entity.isChild()) { f8 *= 3.0F; } if(f7 > 1.0F) { f7 = 1.0F; } GlStateManager.enableAlpha(); biped.rightArmPose = ArmPose.BOW_AND_ARROW; biped.setLivingAnimations(entity, f8, f7, partialTicks); biped.setRotationAngles(f8, f7, f5, f4, f9, 0.0625F, entity); // Render main hand gun { GlStateManager.pushMatrix(); if(hand == EnumHand.MAIN_HAND) { biped.bipedRightArm.postRender(0.0625F); GlStateManager.translate(-0.05F, 0.4F, 0.05F); ClientProxy.gunRenderer .renderItem(CustomItemRenderType.EQUIPPED, hand, stack, mc.world, entity); } else if(entity instanceof EntityPlayer) { biped.bipedLeftArm.postRender(0.0625F); GlStateManager.rotate(-90F, 1F, 0F, 0F); GlStateManager.rotate(-90F, 0F, 1F, 0F); GlStateManager.translate(0.6F, 0F, -0.05F); ClientProxy.gunRenderer.renderOffHandGun((EntityPlayer)entity, stack); } GlStateManager.popMatrix(); } GlStateManager.depthMask(true); GlStateManager.disableRescaleNormal(); GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit); GlStateManager.enableTexture2D(); GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit); GlStateManager.enableCull(); GlStateManager.popMatrix(); } } } private float interpolateRotation(float prevYawOffset, float yawOffset, float partialTicks) { float f; f = yawOffset - prevYawOffset; while(f < -180.0F) { f += 360.0F; } while(f >= 180.0F) { f -= 360.0F; } return prevYawOffset + partialTicks * f; } // Handle player hiding / name tag removal for teams public void renderPlayer(RenderPlayerEvent.Pre event) { PlayerData data = PlayerHandler.getPlayerData(event.getEntityPlayer(), Side.CLIENT); RenderLivingBase.NAME_TAG_RANGE = 64F; RenderLivingBase.NAME_TAG_RANGE_SNEAK = 32F; if(event.getEntity() instanceof EntityPlayer && FlansModClient.teamInfo != null && FlansModClient.teamInfo.gametype != null && !"No Gametype".equals(FlansModClient.teamInfo.gametype)) { PlayerScoreData rendering = PacketTeamInfo.getPlayerScoreData(event.getEntity().getName()); PlayerScoreData player = PacketTeamInfo.getPlayerScoreData(mc.player.getName()); Team renderingTeam = rendering == null ? Team.spectators : rendering.team.team; Team thePlayerTeam = player == null ? Team.spectators : player.team.team; // Do custom skin overrides // If we have no stored skin, try to get it if(data.skin == null) data.skin = ((AbstractClientPlayer)event.getEntityPlayer()).getLocationSkin(); // Spectators see all if(thePlayerTeam == Team.spectators) return; // Nobody sees spectators if(renderingTeam == Team.spectators) { event.setCanceled(true); return; } // If we are on the other team, don't render the name tag if(renderingTeam != thePlayerTeam) { RenderLivingBase.NAME_TAG_RANGE = 0F; RenderLivingBase.NAME_TAG_RANGE_SNEAK = 0F; return; } // If its DM, don't render the name tag if(!FlansModClient.teamInfo.sortedByTeam) { RenderLivingBase.NAME_TAG_RANGE = 0F; RenderLivingBase.NAME_TAG_RANGE_SNEAK = 0F; } } } public void updatePlayerView() { if(mc.player != null && mc.player.getRidingEntity() instanceof IControllable) { if(!mc.mouseHelper.equals(constantMouseHelper)) { // Stops the player's hand/head jerking about by setting mouseHelper deltas to constant 0 Minecraft.getMinecraft().mouseHelper = constantMouseHelper; } EntitySeat seat = ((IControllable)mc.player.getRidingEntity()).getSeat(mc.player); if(seat != null && seat.isDriverSeat() && FlansMod.proxy.mouseControlEnabled()) { seat.applyOrientationToEntity(mc.player); } } else if(mc.mouseHelper.equals(constantMouseHelper)) { Minecraft.getMinecraft().mouseHelper = new MouseHelper(); } } public void cameraSetup(CameraSetup event) { if(mc.player.getRidingEntity() instanceof IControllable) { EntitySeat seat = ((IControllable)mc.player.getRidingEntity()).getSeat(mc.player); if(seat != null) { float roll = interpolateRotation(seat.getPrevPlayerRoll(), seat.getPlayerRoll(), (float)event.getRenderPartialTicks()); // Roll is disorientating when the player is not controlling it or is in third person if(!(seat.driveable instanceof EntityPlane) || mc.gameSettings.thirdPersonView == 1) { roll = 0F; } event.setRoll(roll); } } } public void modifyHUD(RenderGameOverlayEvent event) { ScaledResolution scaledresolution = new ScaledResolution(FlansModClient.minecraft); int i = scaledresolution.getScaledWidth(); int j = scaledresolution.getScaledHeight(); Tessellator tessellator = Tessellator.getInstance(); // Remove crosshairs if looking down the sights of a gun if(event.getType() == ElementType.CROSSHAIRS && FlansModClient.currentScope != null) { renderHitMarker(tessellator, i, j); event.setCanceled(true); return; } if(!event.isCancelable() && event.getType() == ElementType.HELMET) { renderScopeOverlay(i, j); } if(event.isCancelable() && event.getType() == ElementType.CROSSHAIRS) { renderHitMarker(tessellator, i, j); } if(!event.isCancelable() && event.getType() == ElementType.HOTBAR) { renderPlayerAmmo(i, j); renderTeamInfo(tessellator, i, j); renderKillMessages(i, j); renderVehicleDebug(); } } private void renderScopeOverlay(int i, int j) { // Scopes and helmet overlays String overlayTexture = null; if(FlansModClient.currentScope != null && FlansModClient.currentScope.hasZoomOverlay() && FMLClientHandler.instance().getClient().currentScreen == null && FlansModClient.zoomProgress > 0.8F) { overlayTexture = FlansModClient.currentScope.getZoomOverlay(); } else if(mc.player != null) { ItemStack stack = mc.player.getItemStackFromSlot(EntityEquipmentSlot.HEAD); if(stack.getItem() instanceof ItemTeamArmour) { overlayTexture = ((ItemTeamArmour)stack.getItem()).type.overlay; } } if(overlayTexture != null) { GlStateManager.disableDepth(); GlStateManager.depthMask(false); GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableAlpha(); mc.renderEngine.bindTexture(FlansModResourceHandler.getScope(overlayTexture)); WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2d - 2 * j, j, -90D, 0.0D, 1.0D); worldrenderer.addVertexWithUV(i / 2d + 2 * j, j, -90D, 1.0D, 1.0D); worldrenderer.addVertexWithUV(i / 2d + 2 * j, 0.0D, -90D, 1.0D, 0.0D); worldrenderer.addVertexWithUV(i / 2d - 2 * j, 0.0D, -90D, 0.0D, 0.0D); worldrenderer.draw(); GlStateManager.depthMask(true); GlStateManager.enableDepth(); GlStateManager.enableAlpha(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); } } private void renderHitMarker(Tessellator tessellator, int i, int j) { if(FlansModClient.hitMarkerTime > 0) { // Off-hand weapon graphics mc.renderEngine.bindTexture(hitMarker); GlStateManager.enableAlpha(); GlStateManager.enableBlend(); GlStateManager.color(1.0f, 1.0f, 1.0f, Math.max(((float)FlansModClient.hitMarkerTime - 10.0f + partialTicks) / 10.0f, 0.0f)); double zLevel = 0D; WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2d - 4d, j / 2d + 5d, zLevel, 0D / 16D, 9D / 16D); worldrenderer.addVertexWithUV(i / 2d + 5d, j / 2d + 5d, zLevel, 9D / 16D, 9D / 16D); worldrenderer.addVertexWithUV(i / 2d + 5d, j / 2d - 4d, zLevel, 9D / 16D, 0D / 16D); worldrenderer.addVertexWithUV(i / 2d - 4d, j / 2d - 4d, zLevel, 0D / 16D, 0D / 16D); worldrenderer.draw(); GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); GlStateManager.disableAlpha(); GlStateManager.disableBlend(); } } private void renderPlayerAmmo(int i, int j) { // Player ammo overlay if(mc.player != null) { int iNumHandsUsed = 0; for(EnumHand hand : EnumHand.values()) { ItemStack stack = mc.player.getHeldItem(hand); if(stack.getItem() instanceof ItemGun) { ItemGun gunItem = (ItemGun)stack.getItem(); GunType gunType = gunItem.GetType(); if(gunType.oneHanded) iNumHandsUsed++; else iNumHandsUsed += 2; } } if(iNumHandsUsed > 2) { mc.fontRenderer.drawString("Too many guns, not enough hands", i / 2 - 85, j - 35, 0x000000); mc.fontRenderer.drawString("Too many guns, not enough hands", i / 2 - 86, j - 36, 0xffffff); } else { for(EnumHand hand : EnumHand.values()) { ItemStack stack = mc.player.getHeldItem(hand); if(stack.getItem() instanceof ItemGun) { ItemGun gunItem = (ItemGun)stack.getItem(); GunType gunType = gunItem.GetType(); int x = 0; for(int n = 0; n < gunType.numAmmoItemsInGun; n++) { ItemStack bulletStack = ((ItemGun)stack.getItem()).getBulletItemStack(stack, n); if(bulletStack != null && !bulletStack.isEmpty() && bulletStack.getItemDamage() < bulletStack.getMaxDamage()) { RenderHelper.enableGUIStandardItemLighting(); GlStateManager.enableRescaleNormal(); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240F, 240F); int xPos = hand == EnumHand.MAIN_HAND ? i / 2 + 16 + x : i / 2 - 32 - x; drawSlotInventory(mc.fontRenderer, bulletStack, xPos, j - 65); GlStateManager.disableRescaleNormal(); RenderHelper.disableStandardItemLighting(); String s = (bulletStack.getMaxDamage() - bulletStack.getItemDamage()) + "/" + bulletStack.getMaxDamage(); if(bulletStack.getMaxDamage() == 1) s = ""; xPos = hand == EnumHand.MAIN_HAND ? i / 2 + 32 + x : i / 2 - 16 - x; mc.fontRenderer.drawString(s, xPos, j - 59, 0x000000); mc.fontRenderer.drawString(s, xPos + 1, j - 60, 0xffffff); x += 16 + mc.fontRenderer.getStringWidth(s); } } } } } } } private void renderTeamInfo(Tessellator tessellator, int i, int j) { PacketTeamInfo teamInfo = FlansModClient.teamInfo; if(teamInfo != null && FlansModClient.minecraft.player != null && (teamInfo.numTeams > 0 || !teamInfo.sortedByTeam) && PacketTeamInfo.getPlayerScoreData(FlansModClient.minecraft.player.getName()) != null) { GlStateManager.enableBlend(); GlStateManager.disableDepth(); GlStateManager.depthMask(false); GlStateManager.blendFunc(770, 771); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableAlpha(); mc.renderEngine.bindTexture(GuiTeamScores.texture); WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2d - 43, 27, -90D, 85D / 256D, 27D / 256D); worldrenderer.addVertexWithUV(i / 2d + 43, 27, -90D, 171D / 256D, 27D / 256D); worldrenderer.addVertexWithUV(i / 2d + 43, 0D, -90D, 171D / 256D, 0D / 256D); worldrenderer.addVertexWithUV(i / 2d - 43, 0D, -90D, 85D / 256D, 0D / 256D); worldrenderer.draw(); // If we are in a two team gametype, draw the team scores at the top of the screen if(teamInfo.numTeams == 2 && teamInfo.sortedByTeam) { if(teamInfo.teamData == null || teamInfo.teamData[0] == null || teamInfo.teamData[0].team == null || teamInfo.teamData[1] == null || teamInfo.teamData[1].team == null) { FlansMod.Assert(false, "Failure in team data overlay"); return; } // Draw team 1 colour bit int colour = teamInfo.teamData[0].team.teamColour; GlStateManager.color(((colour >> 16) & 0xff) / 256F, ((colour >> 8) & 0xff) / 256F, (colour & 0xff) / 256F, 1.0F); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2d - 43, 27, -90D, 0D / 256D, 125D / 256D); worldrenderer.addVertexWithUV(i / 2d - 19, 27, -90D, 24D / 256D, 125D / 256D); worldrenderer.addVertexWithUV(i / 2d - 19, 0D, -90D, 24D / 256D, 98D / 256D); worldrenderer.addVertexWithUV(i / 2d - 43, 0D, -90D, 0D / 256D, 98D / 256D); worldrenderer.draw(); // Draw team 2 colour bit colour = teamInfo.teamData[1].team.teamColour; GlStateManager.color(((colour >> 16) & 0xff) / 256F, ((colour >> 8) & 0xff) / 256F, (colour & 0xff) / 256F, 1.0F); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(i / 2d + 19, 27, -90D, 62D / 256D, 125D / 256D); worldrenderer.addVertexWithUV(i / 2d + 43, 27, -90D, 86D / 256D, 125D / 256D); worldrenderer.addVertexWithUV(i / 2d + 43, 0D, -90D, 86D / 256D, 98D / 256D); worldrenderer.addVertexWithUV(i / 2d + 19, 0D, -90D, 62D / 256D, 98D / 256D); worldrenderer.draw(); GlStateManager.depthMask(true); GlStateManager.enableDepth(); GlStateManager.enableAlpha(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); // Draw the team scores if(teamInfo.teamData[0] != null && teamInfo.teamData[1] != null) { mc.fontRenderer.drawString(teamInfo.teamData[0].score + "", i / 2 - 35, 9, 0x000000); mc.fontRenderer.drawString(teamInfo.teamData[0].score + "", i / 2 - 36, 8, 0xffffff); mc.fontRenderer.drawString(teamInfo.teamData[1].score + "", i / 2 + 35 - mc.fontRenderer.getStringWidth(teamInfo.teamData[1].score + ""), 9, 0x000000); mc.fontRenderer.drawString(teamInfo.teamData[1].score + "", i / 2 + 34 - mc.fontRenderer.getStringWidth(teamInfo.teamData[1].score + ""), 8, 0xffffff); } } mc.fontRenderer.drawString(teamInfo.gametype + "", i / 2 + 48, 9, 0x000000); mc.fontRenderer.drawString(teamInfo.gametype + "", i / 2 + 47, 8, 0xffffff); mc.fontRenderer .drawString(teamInfo.map + "", i / 2 - 47 - mc.fontRenderer.getStringWidth(teamInfo.map + ""), 9, 0x000000); mc.fontRenderer .drawString(teamInfo.map + "", i / 2 - 48 - mc.fontRenderer.getStringWidth(teamInfo.map + ""), 8, 0xffffff); int secondsLeft = teamInfo.timeLeft / 20; int minutesLeft = secondsLeft / 60; secondsLeft = secondsLeft % 60; String timeLeft = minutesLeft + ":" + (secondsLeft < 10 ? "0" + secondsLeft : secondsLeft); mc.fontRenderer .drawString(timeLeft, i / 2 - mc.fontRenderer.getStringWidth(timeLeft) / 2 - 1, 29, 0x000000); mc.fontRenderer.drawString(timeLeft, i / 2 - mc.fontRenderer.getStringWidth(timeLeft) / 2, 30, 0xffffff); GlStateManager.depthMask(true); GlStateManager.enableDepth(); GlStateManager.enableAlpha(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); String playerUsername = FlansModClient.minecraft.player.getName(); PlayerScoreData data = PacketTeamInfo.getPlayerScoreData(playerUsername); if(data != null) { mc.fontRenderer.drawString(data.score + "", i / 2 - 7, 1, 0x000000); mc.fontRenderer.drawString(data.kills + "", i / 2 - 7, 9, 0x000000); mc.fontRenderer.drawString(data.deaths + "", i / 2 - 7, 17, 0x000000); } } } private void renderKillMessages(int i, int j) { for(KillMessage killMessage : killMessages) { String message = "\u00a7" + killMessage.killerName + (killMessage.headshot ? " ":" ") + "\u00a7" + killMessage.killedName; mc.fontRenderer.drawString(message, i - mc.fontRenderer.getStringWidth(message) - 6, j - 32 - killMessage.line * 16, 0xffffff); } // Draw icons indicated weapons used RenderHelper.enableGUIStandardItemLighting(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableRescaleNormal(); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240F, 240F); for(KillMessage killMessage : killMessages) { drawSlotInventory(mc.fontRenderer, new ItemStack(killMessage.weapon.item, 1, killMessage.paint), i - mc.fontRenderer.getStringWidth((killMessage.headshot ? " ":" ") + killMessage.killedName), j - 36 - killMessage.line * 16); if (killMessage.headshot) drawSlotInventory(mc.fontRenderer, new ItemStack(FlansMod.crosshairsymbol), i - mc.fontRenderer.getStringWidth(" " + killMessage.killedName), j - 36 - killMessage.line * 16); } GlStateManager.disableBlend(); RenderHelper.disableStandardItemLighting(); } private void renderVehicleDebug() { // DEBUG vehicles if(mc.player.getRidingEntity() instanceof EntitySeat) { EntityDriveable ent = ((EntitySeat)mc.player.getRidingEntity()).driveable; if(ent != null) { double dX = ent.posX - ent.prevPosX; double dY = ent.posY - ent.prevPosY; double dZ = ent.posZ - ent.prevPosZ; // Convert to chunks per Minecraft hour float speed = (float)Math.sqrt(dX * dX + dY * dY + dZ * dZ) * 1000F / 16F; speed = (int)(speed * 10F) / 10F; mc.fontRenderer.drawString("Speed: " + speed + " chunks per hour", 2, 2, 0xffffff); if(FlansMod.DEBUG) { mc.fontRenderer.drawString("Throttle : " + ent.throttle, 2, 12, 0xffffff); } } } } private void drawSlotInventory(FontRenderer fontRenderer, ItemStack itemstack, int i, int j) { if(itemstack == null || itemstack.isEmpty()) return; itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); // May be something other than null } public static void addKillMessage(boolean headshot, InfoType infoType, String killer, String killed) { for(KillMessage killMessage : killMessages) { killMessage.line++; if(killMessage.line > 10) killMessage.timer = 0; } killMessages.add(new KillMessage(headshot, infoType, killer, killed)); } private static class KillMessage { public KillMessage(boolean head, InfoType infoType, String killer, String killed) { headshot = head; killerName = killer; killedName = killed; weapon = infoType; line = 0; timer = 200; // Get the player and see if they're still holding the gun they used to kill this player. // From that we can work out the paintjob for(Object o : Minecraft.getMinecraft().world.playerEntities) { if(((EntityPlayer)o).getDisplayNameString().equals(killerName)) { ItemStack stack = ((EntityPlayer)o).getHeldItemMainhand(); if(stack.getItem() instanceof IPaintableItem) { paint = stack.getItemDamage(); break; } } } } public String killerName = ""; public String killedName = ""; public InfoType weapon = null; public int paint = 0; public int timer = 0; public int line = 0; public boolean headshot; } } ================================================ FILE: src/main/java/com/flansmod/client/EntityCamera.java ================================================ package com.flansmod.client; import net.minecraft.entity.EntityLivingBase; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHandSide; import net.minecraft.world.World; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.vector.Vector3f; public class EntityCamera extends EntityLivingBase { public EntityDriveable driveable; public EntityCamera(World world) { super(world); setSize(0F, 0F); } public EntityCamera(World world, EntityDriveable d) { this(world); driveable = d; setPosition(d.posX, d.posY, d.posZ); } @Override public void onUpdate() { prevPosX = posX; prevPosY = posY; prevPosZ = posZ; Vector3f cameraPosition = new Vector3f(); cameraPosition = driveable.axes.findLocalVectorGlobally(cameraPosition); // Lerp it double dX = driveable.posX + cameraPosition.x - posX; double dY = driveable.posY + cameraPosition.y - posY; double dZ = driveable.posZ + cameraPosition.z - posZ; float lerpAmount = 0.1F; setPosition(posX + dX * lerpAmount, posY + dY * lerpAmount, posZ + dZ * lerpAmount); rotationYaw = driveable.axes.getYaw() - 90; rotationPitch = driveable.axes.getPitch(); while(rotationYaw - prevRotationYaw >= 180F) { rotationYaw -= 360F; } while(rotationYaw - prevRotationYaw < -180F) { rotationYaw += 360F; } } @Override public Iterable getArmorInventoryList() { return null; } @Override public ItemStack getItemStackFromSlot(EntityEquipmentSlot slotIn) { return ItemStack.EMPTY.copy(); } @Override public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack) { } @Override public EnumHandSide getPrimaryHand() { return EnumHandSide.RIGHT; } } ================================================ FILE: src/main/java/com/flansmod/client/FlansModClient.java ================================================ package com.flansmod.client; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.imageio.ImageIO; import org.lwjgl.input.Keyboard; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.Particle; import net.minecraft.client.settings.GameSettings; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3i; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import scala.actors.threadpool.Arrays; import com.flansmod.client.model.GunAnimations; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.ContentManager.ContentPackFlanFolder; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.EntityBullet; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.IScope; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.network.PacketTeamInfo; import com.flansmod.common.teams.Team; import com.flansmod.common.types.InfoType; @SideOnly(Side.CLIENT) public class FlansModClient extends FlansMod { // Plane / Vehicle control handling /** * Whether the player has received the vehicle tutorial text */ public static boolean doneTutorial = false; /** * Whether the player is in mouse control mode */ public static boolean controlModeMouse = true; /** * A delayer on the mouse control switch */ public static int controlModeSwitchTimer = 20; // Recoil variables /** * The recoil applied to the player view by shooting */ public static float playerRecoil; /** * The amount of compensation to apply to the recoil in order to bring it back to normal */ public static float antiRecoil; // Gun animations /** * Gun animation variables for each entity holding a gun. Currently only applicable to the player */ public static HashMap gunAnimationsRight = new HashMap<>(), gunAnimationsLeft = new HashMap<>(); // Scope variables /** * A delayer on the scope button to avoid repeat presses */ public static int scopeTime; /** * The scope that is currently being looked down */ public static IScope currentScope = null; /** * The transition variable for zooming in / out with a smoother. 0 = unscoped, 1 = scoped */ public static float zoomProgress = 0F, lastZoomProgress = 0F; /** * The zoom level of the last scope used, for transitioning out of being scoped, even after the scope is forgotten */ public static float lastZoomLevel = 1F, lastFOVZoomLevel = 1F; // Variables to hold the state of some settings so that after being hacked for scopes, they may be restored /** * The player's mouse sensitivity setting, as it was before being hacked by my mod */ public static float originalMouseSensitivity = 0.5F; /** * The player's original FOV */ public static float originalFOV = 90F; /** * The original third person mode, before being hacked */ public static int originalThirdPerson = 0; /** * Whether the player is in a plane or not */ public static boolean inPlane = false; public static int numVehicleExceptions = 0; /** * Packet containing teams mod information from the server */ public static PacketTeamInfo teamInfo; public static int hitMarkerTime = 0; public static List blockLightOverrides = new ArrayList<>(); public static int lightOverrideRefreshRate = 5; private static WorldRenderer wr; public static WorldRenderer getWorldRenderer() { return wr; } public void load() { log.info("Loading Flan's mod client side."); wr = new WorldRenderer(); } private static void DoTextureTrim() { for(File contentPack : FlansMod.INSTANCE.contentManager.GetFolderContentPacks()) { File skinFolder = new File(contentPack, "assets/flansmod/skins"); if(skinFolder.exists() && skinFolder.isDirectory()) { List skins = Arrays.asList(skinFolder.listFiles()); // Group together variant skins HashMap> skinGroups = new HashMap>(); for(File skin : skins) { String skinName = skin.getName().split("\\.")[0]; boolean foundParent = false; for(File other : skins) { String otherName = other.getName().split("\\.")[0]; // If we are a substring of any other skin, go to that group if(skinName.startsWith(otherName)) { if(!skinGroups.containsKey(otherName)) skinGroups.put(otherName, new ArrayList(8)); skinGroups.get(otherName).add(skin); foundParent = true; break; } } if(!foundParent) { if(!skinGroups.containsKey(skinName)) skinGroups.put(skinName, new ArrayList(8)); skinGroups.get(skinName).add(skin); } } // Now process for(HashMap.Entry> kvp : skinGroups.entrySet()) { String key = kvp.getKey(); // Calculate the size int x = 1, y = 1; for(File skin : kvp.getValue()) { try { BufferedImage img = ImageIO.read(skin); WritableRaster alpha = img.getAlphaRaster(); if(alpha != null) { for(int i = 0; i < alpha.getWidth(); i++) { for(int j = 0; j < alpha.getHeight(); j++) { // Skip the area we know we already contain if(i < x && j < y) continue; if(alpha.getSample(i, j, 0) > 0.0f) { if(i >= x && x < alpha.getWidth()) x *= 2; if(j >= y && y < alpha.getHeight()) y *= 2; } } } } } catch (Exception e) { //e.printStackTrace(); } } // Then apply boolean anyResizeApplied = false; for(File skin : kvp.getValue()) { try { BufferedImage img = ImageIO.read(skin); if(x < img.getWidth() || y < img.getHeight()) { Raster subImg = img.getData(new Rectangle(0, 0, x, y)); //img.setData(subImg); BufferedImage cropped = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB); cropped.setData(subImg); ImageIO.write(cropped, "PNG", skin); //new File("C:\\JavaProjects\\FlansMod1.12.2_3\\tests\\" + skin.getName())); anyResizeApplied = true; } } catch (Exception e) { //e.printStackTrace(); } } if(anyResizeApplied) FlansMod.log.info(key + " was resized to " + x + ", " + y); } } } } public static void tick() { if(minecraft.player == null || minecraft.world == null) return; if(teamInfo != null && teamInfo.timeLeft > 0) teamInfo.timeLeft--; ClientTeamsData.Tick(); /* if(Keyboard.isKeyDown(Keyboard.KEY_PAUSE)) DoTextureTrim(); */ // Force shutdown if too many vehicles break to prevent save data corruption if(numVehicleExceptions > 2) { log.error("Too many vehicle exceptions, shutting down."); minecraft.shutdown(); } // Guns if(scopeTime > 0) scopeTime--; if(playerRecoil > 0) playerRecoil *= 0.8F; if(hitMarkerTime > 0) hitMarkerTime--; minecraft.player.rotationPitch -= playerRecoil; antiRecoil += playerRecoil; minecraft.player.rotationPitch += antiRecoil * 0.2F; antiRecoil *= 0.8F; // Update gun animations for the gun in hand for(GunAnimations g : gunAnimationsRight.values()) { g.update(); } for(GunAnimations g : gunAnimationsLeft.values()) { g.update(); } // If the currently held item is not a gun or is the wrong gun, unscope ItemStack itemstackInHand = minecraft.player.inventory.getCurrentItem(); Item itemInHand = itemstackInHand.getItem(); if(currentScope != null) { // If we've opened a GUI page, or we switched weapons, close the current scope if(FMLClientHandler.instance().getClient().currentScreen != null || !(itemInHand instanceof ItemGun) || ((ItemGun)itemInHand).GetType().getCurrentScope(itemstackInHand) != currentScope) { currentScope = null; minecraft.gameSettings.fovSetting = originalFOV; minecraft.gameSettings.mouseSensitivity = originalMouseSensitivity; minecraft.gameSettings.thirdPersonView = originalThirdPerson; } } // Calculate new zoom variables lastZoomProgress = zoomProgress; if(currentScope == null) { zoomProgress *= 0.66F; } else { zoomProgress = 1F - (1F - zoomProgress) * 0.66F; } if(controlModeSwitchTimer > 0) controlModeSwitchTimer--; if(minecraft.getRenderViewEntity() == null || minecraft.getRenderViewEntity().isDead) { minecraft.setRenderViewEntity(minecraft.player); } } public static void setScope(IScope scope) { GameSettings gameSettings = FMLClientHandler.instance().getClient().gameSettings; if(scopeTime <= 0 && FMLClientHandler.instance().getClient().currentScreen == null) { if(currentScope == null) { currentScope = scope; lastZoomLevel = scope.getZoomFactor(); lastFOVZoomLevel = scope.getFOVFactor(); float f = originalMouseSensitivity = gameSettings.mouseSensitivity; gameSettings.mouseSensitivity = f / (float)Math.sqrt(scope.getZoomFactor()); originalThirdPerson = gameSettings.thirdPersonView; gameSettings.thirdPersonView = 0; originalFOV = gameSettings.fovSetting; } else { currentScope = null; gameSettings.mouseSensitivity = originalMouseSensitivity; gameSettings.thirdPersonView = originalThirdPerson; gameSettings.fovSetting = originalFOV; } scopeTime = 10; } } public static void updateCameraZoom(float smoothing) { // If the zoom has changed sufficiently, update it if(Math.abs(zoomProgress - lastZoomProgress) > 0.0001F) { float actualZoomProgress = lastZoomProgress + (zoomProgress - lastZoomProgress) * smoothing; float botchedZoomProgress = zoomProgress > 0.8F ? 1F : 0F; double zoomLevel = botchedZoomProgress * lastZoomLevel + (1 - botchedZoomProgress); float FOVZoomLevel = actualZoomProgress * lastFOVZoomLevel + (1 - actualZoomProgress); if(Math.abs(zoomLevel - 1F) < 0.01F) zoomLevel = 1.0D; float zoomToApply = Math.max(FOVZoomLevel, (float)zoomLevel); minecraft.gameSettings.fovSetting = (((originalFOV * 40 + 70) / zoomToApply) - 70) / 40; } } public static boolean flipControlMode() { if(controlModeSwitchTimer > 0) return false; controlModeMouse = !controlModeMouse; controlModeSwitchTimer = 40; return true; } public static void reloadModels(boolean reloadSkins) { for(InfoType type : InfoType.infoTypes.values()) { type.reloadModel(); } if(reloadSkins) proxy.forceReload(); } public static Minecraft minecraft = FMLClientHandler.instance().getClient(); /** * Gets the team class from an ID */ public static Team getTeam(int spawnerTeamID) { if(teamInfo == null) return null; else return teamInfo.getTeam(spawnerTeamID); } public static boolean isCurrentMap(String map) { return !(teamInfo == null || teamInfo.mapShortName == null) && teamInfo.mapShortName.equals(map); } @SideOnly(Side.CLIENT) public static Particle getParticle(String s, World w, double x, double y, double z) { Minecraft mc = Minecraft.getMinecraft(); int particleID = 0; int[] data = new int[0]; if(s.equals("hugeexplosion")) particleID = EnumParticleTypes.EXPLOSION_HUGE.getParticleID(); else if(s.equals("largeexplode")) particleID = EnumParticleTypes.EXPLOSION_LARGE.getParticleID(); else if(s.equals("explode")) particleID = EnumParticleTypes.EXPLOSION_NORMAL.getParticleID(); else if(s.equals("fireworksSpark")) particleID = EnumParticleTypes.FIREWORKS_SPARK.getParticleID(); else if(s.equals("bubble")) particleID = EnumParticleTypes.WATER_BUBBLE.getParticleID(); else if(s.equals("splash")) particleID = EnumParticleTypes.WATER_SPLASH.getParticleID(); else if(s.equals("wake")) particleID = EnumParticleTypes.WATER_WAKE.getParticleID(); else if(s.equals("drop")) particleID = EnumParticleTypes.WATER_DROP.getParticleID(); else if(s.equals("suspended")) particleID = EnumParticleTypes.SUSPENDED.getParticleID(); else if(s.equals("depthsuspend")) particleID = EnumParticleTypes.SUSPENDED_DEPTH.getParticleID(); else if(s.equals("townaura")) particleID = EnumParticleTypes.TOWN_AURA.getParticleID(); else if(s.equals("crit")) particleID = EnumParticleTypes.CRIT.getParticleID(); else if(s.equals("magicCrit")) particleID = EnumParticleTypes.CRIT_MAGIC.getParticleID(); else if(s.equals("smoke")) particleID = EnumParticleTypes.SMOKE_NORMAL.getParticleID(); else if(s.equals("largesmoke")) particleID = EnumParticleTypes.SMOKE_LARGE.getParticleID(); else if(s.equals("spell")) particleID = EnumParticleTypes.SPELL.getParticleID(); else if(s.equals("instantSpell")) particleID = EnumParticleTypes.SPELL_INSTANT.getParticleID(); else if(s.equals("mobSpell")) particleID = EnumParticleTypes.SPELL_MOB.getParticleID(); else if(s.equals("mobSpellAmbient")) particleID = EnumParticleTypes.SPELL_MOB_AMBIENT.getParticleID(); else if(s.equals("witchMagic")) particleID = EnumParticleTypes.SPELL_WITCH.getParticleID(); else if(s.equals("dripWater")) particleID = EnumParticleTypes.DRIP_WATER.getParticleID(); else if(s.equals("dripLava")) particleID = EnumParticleTypes.DRIP_LAVA.getParticleID(); else if(s.equals("angryVillager")) particleID = EnumParticleTypes.VILLAGER_ANGRY.getParticleID(); else if(s.equals("happyVillager")) particleID = EnumParticleTypes.VILLAGER_HAPPY.getParticleID(); else if(s.equals("note")) particleID = EnumParticleTypes.NOTE.getParticleID(); else if(s.equals("portal")) particleID = EnumParticleTypes.PORTAL.getParticleID(); else if(s.equals("enchantmenttable")) particleID = EnumParticleTypes.ENCHANTMENT_TABLE.getParticleID(); else if(s.equals("flame")) particleID = EnumParticleTypes.FLAME.getParticleID(); else if(s.equals("lava")) particleID = EnumParticleTypes.LAVA.getParticleID(); else if(s.equals("footstep")) particleID = EnumParticleTypes.FOOTSTEP.getParticleID(); else if(s.equals("cloud")) particleID = EnumParticleTypes.CLOUD.getParticleID(); else if(s.equals("reddust")) particleID = EnumParticleTypes.REDSTONE.getParticleID(); else if(s.equals("snowballpoof")) particleID = EnumParticleTypes.SNOWBALL.getParticleID(); else if(s.equals("snowshovel")) particleID = EnumParticleTypes.SNOW_SHOVEL.getParticleID(); else if(s.equals("slime")) particleID = EnumParticleTypes.SLIME.getParticleID(); else if(s.equals("heart")) particleID = EnumParticleTypes.HEART.getParticleID(); else if(s.equals("barrier")) particleID = EnumParticleTypes.BARRIER.getParticleID(); else if(s.contains("_")) { String[] split = s.split("_", 3); if(split[0].equals("iconcrack")) { data = new int[]{Item.getIdFromItem(InfoType.getRecipeElement(split[1], 1, 0).getItem())}; particleID = EnumParticleTypes.ITEM_CRACK.getParticleID(); } else { data = new int[]{ Block.getIdFromBlock(Block.getBlockFromItem(InfoType.getRecipeElement(split[1], 1, 0).getItem()))}; if(split[0].equals("blockcrack")) { particleID = EnumParticleTypes.BLOCK_CRACK.getParticleID(); } else if(split[0].equals("blockdust")) { particleID = EnumParticleTypes.BLOCK_DUST.getParticleID(); } } } return mc.effectRenderer.spawnEffectParticle(particleID, x, y, z, 0D, 0D, 0D, data); } public static GunAnimations getGunAnimations(EntityLivingBase living, EnumHand hand) { GunAnimations animations; if(hand == EnumHand.OFF_HAND) { if(FlansModClient.gunAnimationsLeft.containsKey(living)) animations = FlansModClient.gunAnimationsLeft.get(living); else { animations = new GunAnimations(); FlansModClient.gunAnimationsLeft.put(living, animations); } } else { if(FlansModClient.gunAnimationsRight.containsKey(living)) animations = FlansModClient.gunAnimationsRight.get(living); else { animations = new GunAnimations(); FlansModClient.gunAnimationsRight.put(living, animations); } } return animations; } public static void addHitMarker() { hitMarkerTime = 20; } /** * Handle flashlight block light override */ public static void updateFlashlights(Minecraft mc) { // Handle lighting from flashlights and glowing bullets if(FlansMod.ticker % lightOverrideRefreshRate == 0 && mc.world != null) { // Check graphics setting and adjust refresh rate lightOverrideRefreshRate = mc.gameSettings.fancyGraphics ? 10 : 20; // Reset old light values blockLightOverrides.forEach(blockPos -> mc.world.checkLightFor(EnumSkyBlock.BLOCK, blockPos)); // Clear the list blockLightOverrides.clear(); //Find all flashlights for(EntityPlayer player : mc.world.playerEntities) { ItemStack currentHeldItem = player.getHeldItemMainhand(); if(currentHeldItem.getItem() instanceof ItemGun) { GunType type = ((ItemGun)currentHeldItem.getItem()).GetType(); AttachmentType grip = type.getGrip(currentHeldItem); if(grip != null && grip.flashlight) { for(int i = 0; i < 2; i++) { RayTraceResult ray = player.rayTrace(grip.flashlightRange / 2F * (i + 1), 1F); if(ray != null) { int x = ray.getBlockPos().getX(); int y = ray.getBlockPos().getY(); int z = ray.getBlockPos().getZ(); EnumFacing side = ray.sideHit; switch(side) { case DOWN: y--; break; case UP: y++; break; case NORTH: z--; break; case SOUTH: z++; break; case WEST: x--; break; case EAST: x++; break; } BlockPos blockPos = new BlockPos(x, y, z); blockLightOverrides.add(blockPos); lightBlock(mc, blockPos, 12); } } } } } for(Entity entity : mc.world.loadedEntityList) { if(entity instanceof EntityBullet) { EntityBullet bullet = (EntityBullet)entity; if(!bullet.isDead && bullet.getFiredShot().getBulletType().hasLight) { int x = MathHelper.floor(bullet.posX); int y = MathHelper.floor(bullet.posY); int z = MathHelper.floor(bullet.posZ); BlockPos blockPos = new BlockPos(x, y, z); blockLightOverrides.add(blockPos); lightBlock(mc, blockPos, 15); } } else if(entity instanceof EntityMecha) { EntityMecha mecha = (EntityMecha)entity; int x = MathHelper.floor(mecha.posX); int y = MathHelper.floor(mecha.posY); int z = MathHelper.floor(mecha.posZ); if(mecha.lightLevel() > 0) { BlockPos blockPos = new BlockPos(x, y, z); int lightLevel = Math .max(mc.world.getLightFor(EnumSkyBlock.BLOCK, blockPos), mecha.lightLevel()); blockLightOverrides.add(blockPos); lightBlock(mc, blockPos, lightLevel); } if(mecha.forceDark()) { for(int i = -3; i <= 3; i++) { for(int j = -3; j <= 3; j++) { for(int k = -3; k <= 3; k++) { int xd = i + x; int yd = j + y; int zd = k + z; BlockPos blockPos = new BlockPos(xd, yd, zd); blockLightOverrides.add(blockPos); mc.world.setLightFor(EnumSkyBlock.SKY, blockPos, Math.abs(i) + Math.abs(j) + Math.abs(k)); } } } } } } } } private static void lightBlock(Minecraft mc, BlockPos blockPos, int lightValue) { mc.world.setLightFor(EnumSkyBlock.BLOCK, blockPos, lightValue); Vec3i diffVec = new Vec3i(1, 1, 1); BlockPos .getAllInBox(blockPos.subtract(diffVec), blockPos.add(diffVec)) .forEach(posToUpdate -> { if(!posToUpdate.equals(blockPos)) { mc.world.checkLightFor(EnumSkyBlock.BLOCK, posToUpdate); } }); } } ================================================ FILE: src/main/java/com/flansmod/client/MovingSoundDriveable.java ================================================ package com.flansmod.client; //TODO : Implement this! public class MovingSoundDriveable // extends MovingSound { /* private final EntityDriveable driveable; private float field_147669_l = 0.0F; public MovingSoundDriveable(ResourceLocation sound, EntityDriveable driveable) { super(sound); this.driveable = driveable; repeat = true; repeatDelay = 0; } public void update() { if(driveable.isDead) { donePlaying = true; } else { xPosF = (float)driveable.posX; yPosF = (float)driveable.posY; zPosF = (float)driveable.posZ; float f = MathHelper.sqrt(driveable.motionX * driveable.motionX + driveable.motionZ * driveable.motionZ); if ((double)f >= 0.01D) { field_147669_l = MathHelper.clamp_float(field_147669_l + 0.0025F, 0.0F, 1.0F); volume = 0.0F + MathHelper.clamp_float(f, 0.0F, 0.5F) * 0.7F; } else { field_147669_l = 0.0F; volume = 0.0F; } } } */ } ================================================ FILE: src/main/java/com/flansmod/client/TileEntitySpawnerRenderer.java ================================================ package com.flansmod.client; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TileEntitySpawner; public class TileEntitySpawnerRenderer extends TileEntitySpecialRenderer { @Override public void render(TileEntitySpawner te, double x, double y, double z, float f, int i, float alpha) { WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); int spawnerTeamID = te.getTeamID(); Team spawnerTeam = FlansModClient.getTeam(spawnerTeamID); boolean currentMap = FlansModClient.isCurrentMap(te.map); //Use default colours if(spawnerTeam == null || !currentMap) { switch(spawnerTeamID) { case 0: GlStateManager.color(0.5f, 0.5f, 0.5f); break; //No team : light grey case 1: GlStateManager.color(0.25f, 0.25f, 0.25f); break; //Spectators : dark grey case 2: GlStateManager.color(0.8f, 0.5f, 1.0f); break; //Team 1 : purple case 3: GlStateManager.color(1.0f, 0.5f, 0.8f); break; //Team 2 : pink } } else { float red = (float)((spawnerTeam.teamColour >> 16) & 0xff) / 255f; float green = (float)((spawnerTeam.teamColour >> 8) & 0xff) / 255f; float blue = (float)((spawnerTeam.teamColour >> 0) & 0xff) / 255f; GlStateManager.color(red, green, blue); } GlStateManager.disableTexture2D(); double inset = 0.0d; switch(te.getBlockMetadata()) { case 0: inset = 0.375d; break; case 1: inset = 0.25d; break; case 2: inset = 0.0625d; break; default: FlansMod.log.warn("" + te.getBlockMetadata()); } RenderBox(worldrenderer, x + inset, x + 1.0d - inset, y + 0.0625d, y + 0.125d, z + inset, z + 1.0d - inset); GlStateManager.enableTexture2D(); GlStateManager.color(1.0f, 1.0f, 1.0f); } private void RenderBox(WorldRenderer wr, double x0, double x1, double y0, double y1, double z0, double z1) { // Top wr.startDrawingQuads(); wr.addVertexWithUV(x0, y1, z0, 0d, 0d); wr.addVertexWithUV(x0, y1, z1, 0d, 0d); wr.addVertexWithUV(x1, y1, z1, 0d, 0d); wr.addVertexWithUV(x1, y1, z0, 0d, 0d); wr.draw(); // Bottom wr.startDrawingQuads(); wr.addVertexWithUV(x0, y0, z0, 0d, 0d); wr.addVertexWithUV(x1, y0, z0, 0d, 0d); wr.addVertexWithUV(x1, y0, z1, 0d, 0d); wr.addVertexWithUV(x0, y0, z1, 0d, 0d); wr.draw(); // Left wr.startDrawingQuads(); wr.addVertexWithUV(x0, y1, z1, 0d, 0d); wr.addVertexWithUV(x0, y0, z1, 0d, 0d); wr.addVertexWithUV(x1, y0, z1, 0d, 0d); wr.addVertexWithUV(x1, y1, z1, 0d, 0d); wr.draw(); // Right wr.startDrawingQuads(); wr.addVertexWithUV(x0, y0, z0, 0d, 0d); wr.addVertexWithUV(x0, y1, z0, 0d, 0d); wr.addVertexWithUV(x1, y1, z0, 0d, 0d); wr.addVertexWithUV(x1, y0, z0, 0d, 0d); wr.draw(); // Front wr.startDrawingQuads(); wr.addVertexWithUV(x1, y1, z0, 0d, 0d); wr.addVertexWithUV(x1, y1, z1, 0d, 0d); wr.addVertexWithUV(x1, y0, z1, 0d, 0d); wr.addVertexWithUV(x1, y0, z0, 0d, 0d); wr.draw(); // Front wr.startDrawingQuads(); wr.addVertexWithUV(x0, y0, z0, 0d, 0d); wr.addVertexWithUV(x0, y0, z1, 0d, 0d); wr.addVertexWithUV(x0, y1, z1, 0d, 0d); wr.addVertexWithUV(x0, y1, z0, 0d, 0d); wr.draw(); } } ================================================ FILE: src/main/java/com/flansmod/client/debug/EntityDebugAABB.java ================================================ package com.flansmod.client.debug; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.world.World; import com.flansmod.common.vector.Vector3f; public class EntityDebugAABB extends Entity { public Vector3f vector; public int life; public float red = 1F, green = 1F, blue = 1F; public float rotationRoll; /** * This is the offset after rotation */ public Vector3f offset; public EntityDebugAABB(World w, Vector3f u, Vector3f v, int i, float r, float g, float b, float yaw, float pitch, float roll, Vector3f offset) { super(w); setPosition(u.x, u.y, u.z); rotationYaw = yaw; rotationPitch = pitch; rotationRoll = roll; vector = v; life = i; red = r; green = g; blue = b; this.offset = offset; } public EntityDebugAABB(World w, Vector3f u, Vector3f v, int i, float r, float g, float b, float yaw, float pitch, float roll) { this(w, u, v, i, r, g, b, yaw, pitch, roll, new Vector3f()); } public EntityDebugAABB(World w, Vector3f u, Vector3f v, int i, float r, float g, float b) { this(w, u, v, i, r, g, b, 0F, 0F, 0F); } public EntityDebugAABB(World w, Vector3f u, Vector3f v, int i) { this(w, u, v, i, 1F, 1F, 1F); } @Override public void onUpdate() { life--; if(life <= 0) setDead(); } @Override public AxisAlignedBB getCollisionBoundingBox() { return null; } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { } @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { } } ================================================ FILE: src/main/java/com/flansmod/client/debug/EntityDebugColor.java ================================================ package com.flansmod.client.debug; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.world.World; /** * Class Skeleton for DebugEntities which use a color */ public abstract class EntityDebugColor extends Entity { private static final DataParameter COLOR_RED = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); private static final DataParameter COLOR_GREEN = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); private static final DataParameter COLOR_BLUE = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); /** * @param w World for Entity Constructor */ public EntityDebugColor(World w) { super(w); } @Override protected void entityInit() { this.dataManager.register(COLOR_RED, 1F); this.dataManager.register(COLOR_GREEN, 1F); this.dataManager.register(COLOR_BLUE, 1F); } @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { this.setColorRed(nbttagcompound.getFloat("color_red")); this.setColorGreen(nbttagcompound.getFloat("color_green")); this.setColorBlue(nbttagcompound.getFloat("color_blue")); } @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { nbttagcompound.setFloat("color_red", getColorRed()); nbttagcompound.setFloat("color_green", getColorGreen()); nbttagcompound.setFloat("color_blue", getColorBlue()); } /** * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @param red Red color value */ public void setColorRed(Float red) { this.dataManager.set(COLOR_RED, red); } /** * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @return Red color value */ public Float getColorRed() { return this.dataManager.get(COLOR_RED); } /** * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @param green Green color value */ public void setColorGreen(Float green) { this.dataManager.set(COLOR_GREEN, green); } /** * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @return Green color value */ public Float getColorGreen() { return dataManager.get(COLOR_GREEN); } /** * Color values range from 0 (Nonexistend) to 1 (Fully Visible) * * @param blue Blue color value */ public void setColorBlue(Float blue) { dataManager.set(COLOR_BLUE, blue); } /** * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @return Blue color value */ public Float getColorBlue() { return dataManager.get(COLOR_BLUE); } /** * Combined Setter for all three color values * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @param red Red color value * @param green Green color value * @param blue Blue color value */ public void setColor(Float red, Float green, Float blue) { setColorRed(red); setColorGreen(green); setColorBlue(blue); } } ================================================ FILE: src/main/java/com/flansmod/client/debug/EntityDebugDot.java ================================================ package com.flansmod.client.debug; import net.minecraft.world.World; import com.flansmod.common.vector.Vector3f; /** * Entity for debugging purposes * On the client side a dot, in the given color, at the location of the entity is rendered */ public class EntityDebugDot extends EntityDebugColor { public int life = 1000; /** * @param w World for Entity Constructor */ public EntityDebugDot(World w) { super(w); setSize(0.25F, 0.25F); } /** * Creates a white dot at the given location * * @param w World for Entity Constructor * @param pos Position of the dot * @param l Lifetime given in ticks */ public EntityDebugDot(World w, Vector3f pos, int l) { this(w, pos, l, 1F, 1F, 1F); } /** * Creates a dot * Color values range from 0 (Nonexistent) to 1 (Fully Visible) * * @param w World for Entity Constructor * @param pos Position of the dot * @param l Lifetime given in ticks * @param r Red color value * @param g Green color value * @param b Blue color value */ public EntityDebugDot(World w, Vector3f pos, int l, float r, float g, float b) { this(w); setPosition(pos.x, pos.y, pos.z); setColor(r, g, b); life = l; } @Override public void onUpdate() { life--; if(life <= 0) setDead(); } } ================================================ FILE: src/main/java/com/flansmod/client/debug/EntityDebugVector.java ================================================ package com.flansmod.client.debug; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.world.World; import com.flansmod.common.vector.Vector3f; /** * Entity for debugging purposes. * On the client side a line (Vector) between the position of the entity and its pointing location is rendered */ public class EntityDebugVector extends EntityDebugColor { private static final DataParameter POINTING_X = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); private static final DataParameter POINTING_Y = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); private static final DataParameter POINTING_Z = EntityDataManager.createKey(EntityDebugVector.class, DataSerializers.FLOAT); public int life = 1000; /** * @param w World for Entity Constructor */ public EntityDebugVector(World w) { super(w); setSize(0.25F, 0.25F); } /** * Spawns an EntityDebug Vector * * @param w World for Entity Constructor * @param u Position where the Vector starts * @param v Position where the Vector ends * @param i Lifetime given in ticks * @param r Red Color Value * @param g Green Color Value * @param b Blue Color Value */ public EntityDebugVector(World w, Vector3f u, Vector3f v, int i, float r, float g, float b) { this(w); setPosition(u.x, u.y, u.z); setPointing(v.x, v.y, v.z); setColor(r, g, b); life = i; } /** * @param w World for Entity Constructor * @param u Position where the Vector starts * @param v Position where the Vector ends * @param i Lifetime given in ticks */ public EntityDebugVector(World w, Vector3f u, Vector3f v, int i) { this(w, u, v, i, 1F, 1F, 1F); } @Override public void onUpdate() { life--; if(life <= 0) setDead(); } @Override protected void entityInit() { super.entityInit(); this.dataManager.register(POINTING_X, 1F); this.dataManager.register(POINTING_Y, 1F); this.dataManager.register(POINTING_Z, 1F); } @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { super.readEntityFromNBT(nbttagcompound); this.dataManager.set(POINTING_X, nbttagcompound.getFloat("pointing_x")); this.dataManager.set(POINTING_Y, nbttagcompound.getFloat("pointing_y")); this.dataManager.set(POINTING_Z, nbttagcompound.getFloat("pointing_z")); } @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { super.writeEntityToNBT(nbttagcompound); nbttagcompound.setFloat("pointing_x", getPointingX()); nbttagcompound.setFloat("pointing_y", getPointingY()); nbttagcompound.setFloat("pointing_z", getPointingZ()); } /** * @param x The X value of the Position the Vector points to (Relative to Entity Position) */ public void setPointingX(Float x) { dataManager.set(POINTING_X, x); } /** * @return The X value of the Position the Vector points to (Relative to Entity Position) */ public Float getPointingX() { return dataManager.get(POINTING_X); } /** * @param y The Y value of the Position the Vector points to (Relative to Entity Position) */ public void setPointingY(Float y) { dataManager.set(POINTING_Y, y); } /** * @return The Y value of the Position the Vector points to (Relative to Entity Position) */ public Float getPointingY() { return dataManager.get(POINTING_Y); } /** * @param z The Z value of the Position the Vector points to (Relative to Entity Position) */ public void setPointingZ(Float z) { dataManager.set(POINTING_Z, z); } /** * @return The Z value of the Position the Vector points to (Relative to Entity Position) */ public Float getPointingZ() { return dataManager.get(POINTING_Z); } /** * All Parameters are relative to the position of the Entity. * These 3 Parameters describe the location of the Position the Vector points to. * * @param x The X Coordinate * @param y The Y Coordinate * @param z The Z Coordinate */ public void setPointing(Float x, Float y, Float z) { setPointingX(x); setPointingY(y); setPointingZ(z); } } ================================================ FILE: src/main/java/com/flansmod/client/debug/RenderDebugAABB.java ================================================ package com.flansmod.client.debug; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.FlansMod; public class RenderDebugAABB extends Render { public RenderDebugAABB(RenderManager renderManager) { super(renderManager); } @Override public void doRender(EntityDebugAABB entity, double d0, double d1, double d2, float f, float f1) { if(!FlansMod.DEBUG) return; EntityDebugAABB ent = entity; GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.color(ent.red, ent.green, ent.blue, 0.2F); GlStateManager.pushMatrix(); GlStateManager.translate((float)d0, (float)d1, (float)d2); GlStateManager.rotate(-ent.rotationYaw, 0F, 1F, 0F); GlStateManager.rotate(ent.rotationPitch, 1F, 0F, 0F); GlStateManager.rotate(ent.rotationRoll, 0F, 0F, 1F); renderOffsetAABB(new AxisAlignedBB(ent.offset.x, ent.offset.y, ent.offset.z, ent.offset.x + ent.vector.x, ent.offset.y + ent.vector.y, ent.offset.z + ent.vector.z), 0, 0, 0); GlStateManager.popMatrix(); GlStateManager.disableBlend(); GlStateManager.enableTexture2D(); } @Override protected ResourceLocation getEntityTexture(EntityDebugAABB entity) { return null; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderDebugAABB(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/debug/RenderDebugDot.java ================================================ package com.flansmod.client.debug; import org.lwjgl.opengl.GL11; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.FlansMod; public class RenderDebugDot extends Render { public RenderDebugDot(RenderManager renderManager) { super(renderManager); } @Override public void doRender(EntityDebugDot entity, double d0, double d1, double d2, float f, float f1) { if(!FlansMod.DEBUG) return; GlStateManager.disableTexture2D(); GlStateManager.disableDepth(); GlStateManager.color(entity.getColorRed(), entity.getColorGreen(), entity.getColorBlue()); GlStateManager.pushMatrix(); GlStateManager.translate((float)d0, (float)d1, (float)d2); GL11.glPointSize(10F); GlStateManager.glBegin(GL11.GL_POINTS); GlStateManager.glVertex3f(0F, 0F, 0F); GlStateManager.glEnd(); GlStateManager.popMatrix(); GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); } @Override protected ResourceLocation getEntityTexture(EntityDebugDot entity) { return null; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderDebugDot(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/debug/RenderDebugVector.java ================================================ package com.flansmod.client.debug; import org.lwjgl.opengl.GL11; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.FlansMod; public class RenderDebugVector extends Render { public RenderDebugVector(RenderManager renderManager) { super(renderManager); } @Override public void doRender(EntityDebugVector entity, double d0, double d1, double d2, float f, float f1) { if(!FlansMod.DEBUG) return; GlStateManager.disableTexture2D(); GlStateManager.disableDepth(); GlStateManager.color(entity.getColorRed(), entity.getColorGreen(), entity.getColorBlue()); GlStateManager.pushMatrix(); GlStateManager.translate((float)d0, (float)d1, (float)d2); GlStateManager.glLineWidth(5F); GlStateManager.glBegin(GL11.GL_LINE_STRIP); GlStateManager.glVertex3f(0F, 0F, 0F); GlStateManager.glVertex3f(entity.getPointingX(), entity.getPointingY(), entity.getPointingZ()); GlStateManager.glEnd(); GlStateManager.popMatrix(); GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); } @Override protected ResourceLocation getEntityTexture(EntityDebugVector entity) { return null; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderDebugVector(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiArmourBox.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.teams.ArmourBoxType.ArmourBoxEntry; public class GuiArmourBox extends GuiScreen { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/armourBox.png"); private InventoryPlayer inventory; private Minecraft mc; private static RenderItem itemRenderer; private ArmourBoxType type; private int page; private int guiOriginX; private int guiOriginY; private int scroll; public GuiArmourBox(InventoryPlayer playerinventory, ArmourBoxType type) { inventory = playerinventory; mc = FMLClientHandler.instance().getClient(); itemRenderer = mc.getRenderItem(); this.type = type; page = 0; } @Override public void updateScreen() { super.updateScreen(); scroll++; } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int k = scaledresolution.getScaledWidth(); int l = scaledresolution.getScaledHeight(); FontRenderer fontrenderer = mc.fontRenderer; drawDefaultBackground(); GlStateManager.enableBlend(); mc.renderEngine.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); int m = guiOriginX = k / 2 - 88; int n = guiOriginY = l / 2 - 91; drawTexturedModalRect(m, n, 0, 0, 176, 182); //No idea why this works, but it makes the text bind its texture correctly //mc.renderEngine.bindTexture("/terrain.png"); //TODO : Investigate drawCenteredString(fontRenderer, type.name, k / 2, n + 5, 0xffffff); mc.renderEngine.bindTexture(texture); // Grey out buttons when they are unavaliable if(page == 0) drawTexturedModalRect(m + 77, n + 87, 176, 0, 10, 10); if(page >= type.pages.size() - 1) drawTexturedModalRect(m + 89, n + 87, 186, 0, 10, 10); RenderHelper.enableGUIStandardItemLighting(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableRescaleNormal(); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240F, 240F); // Fill the gun panels with guns drawRecipe(fontrenderer, m, n, page); // Draw the inventory slots (not real slots) for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { drawSlotInventory(inventory.getStackInSlot(col + (row + 1) * 9), m + 8 + col * 18, n + 100 + row * 18); } } for(int col = 0; col < 9; col++) { drawSlotInventory(inventory.getStackInSlot(col), m + 8 + col * 18, n + 158); } GlStateManager.disableBlend(); } /** * @param fontrenderer * @param m : x position to render in * @param n : y position to render in * @param q : armour page */ private void drawRecipe(FontRenderer fontrenderer, int m, int n, int q) { ArmourBoxEntry page = type.pages.get(q); if(page != null) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); //fontRenderer.drawString(type.guns[q].name, m + 9, n + 22, 0xffffffff); //Iterate over x for(int i = 0; i < 2; i++) { //Iterate over y for(int j = 0; j < 2; j++) { if(page.armours[i * 2 + j] != null) { drawSlotInventory(new ItemStack(page.armours[i * 2 + j].item), m + 9 + 83 * i, n + 44 + 22 * j); int numParts = page.requiredStacks[i * 2 + j].size(); //Find which 3 parts to render int startPart = 0; if(numParts >= 4) { startPart = (scroll / 40) % (numParts - 2); } for(int p = 0; p < (numParts < 3 ? numParts : 3); p++) { drawSlotInventory(page.requiredStacks[i * 2 + j].get(startPart + p), m + 30 + p * 19 + 83 * i, n + 44 + 22 * j); } } } } //Draw the armour name at the top RenderHelper.disableStandardItemLighting(); drawCenteredString(fontrenderer, page.name, m + 87, n + 25, 0xffffff); RenderHelper.enableGUIStandardItemLighting(); } } private void drawSlotInventory(ItemStack itemstack, int i, int j) { if(itemstack == null || itemstack.isEmpty()) return; RenderHelper.enableGUIStandardItemLighting(); itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); } @Override protected void mouseClicked(int i, int j, int k) { try { super.mouseClicked(i, j, k); } catch(IOException e) { } int m = i - guiOriginX; int n = j - guiOriginY; if(k == 0 || k == 1) { // Back button if(m > 77 && m < 87 && n > 87 && n < 97) { if(page > 0) page--; } // Forwards button if(m > 89 && m < 99 && n > 87 && n < 97) { if(page < type.pages.size() - 1) page++; } // Gun 1 //Iterate over x for(int x = 0; x < 2; x++) { //Iterate over y for(int y = 0; y < 2; y++) { if(type.pages.get(page).armours[x * 2 + y] != null && m > 7 + 83 * x && m < 27 + 83 * x && n > 42 + 22 * y && n < 62 + 22 * y) { type.block.buyArmour(type.pages.get(page).shortName, x * 2 + y, inventory); } } } } } @Override protected void keyTyped(char c, int i) { if(i == 1 || i == mc.gameSettings.keyBindInventory.getKeyCode()) { mc.player.closeScreen(); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableController.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.gameevent.InputEvent; import com.flansmod.api.IControllable; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.KeyInputHandler; import com.flansmod.common.FlansMod; public class GuiDriveableController extends GuiScreen { private IControllable plane; private boolean leftMouseHeld; private boolean rightMouseHeld; public GuiDriveableController(IControllable thePlane) { super(); plane = thePlane; } @Override public void initGui() { if(mc.gameSettings.thirdPersonView == 1) mc.setRenderViewEntity((plane.getCamera() == null ? mc.player : plane.getCamera())); } @Override public void onGuiClosed() { mc.mouseHelper.ungrabMouseCursor(); mc.setRenderViewEntity(mc.player); } @Override public void handleMouseInput() { EntityPlayer player = (EntityPlayer)plane.getControllingEntity(); if(player != mc.player) { mc.displayGuiScreen(null); return; } int dWheel = Mouse.getDWheel(); if(dWheel != 0) { player.inventory.changeCurrentItem(dWheel); } //Right mouse. Fires shells, drops bombs. Is not a holding thing if(Mouse.isButtonDown(1)) plane.pressKey(8, player, true); if(!leftMouseHeld && Mouse.isButtonDown(0)) //Left mouse, for MGs. Is a holding thing { leftMouseHeld = true; plane.updateKeyHeldState(9, true); } if(leftMouseHeld && !Mouse.isButtonDown(0)) { leftMouseHeld = false; plane.updateKeyHeldState(9, false); } if(!rightMouseHeld && Mouse.isButtonDown(1)) //Right mouse { rightMouseHeld = true; plane.updateKeyHeldState(8, true); } if(rightMouseHeld && !Mouse.isButtonDown(1)) { rightMouseHeld = false; plane.updateKeyHeldState(8, false); } MinecraftForge.EVENT_BUS.post(new InputEvent.MouseInputEvent()); } @Override protected void keyTyped(char c, int i) { if(i == 63) { mc.gameSettings.thirdPersonView = (mc.gameSettings.thirdPersonView + 1) % 3; if(mc.gameSettings.thirdPersonView == 1) mc.setRenderViewEntity((plane.getCamera() == null ? mc.player : plane.getCamera())); else mc.setRenderViewEntity(mc.player); } if(i == KeyInputHandler.debugKey.getKeyCode()) { FlansMod.DEBUG = !FlansMod.DEBUG; } if(i == KeyInputHandler.reloadModelsKey.getKeyCode()) { FlansModClient.reloadModels(false); } MinecraftForge.EVENT_BUS.post(new InputEvent.KeyInputEvent()); } @Override public void updateScreen() { if(mc.gameSettings.thirdPersonView == 1) mc.setRenderViewEntity((plane.getCamera() == null ? mc.player : plane.getCamera())); else mc.setRenderViewEntity(mc.player); } @Override public void handleInput() { EntityPlayer player = (EntityPlayer)plane.getControllingEntity(); if(player != mc.player) { mc.displayGuiScreen(null); return; } if(!Mouse.isGrabbed()) { mc.mouseHelper.grabMouseCursor(); } handleMouseInput(); for(; Keyboard.next(); ) { try { handleKeyboardInput(); } catch(IOException e) { } } int l = Mouse.getDX(); int m = Mouse.getDY(); plane.onMouseMoved(l, m); if(plane != null && !plane.isDead() && plane.getControllingEntity() != null && plane.getControllingEntity() instanceof EntityPlayer) { if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindForward.getKeyCode()))//KeyInputHandler.accelerateKey.getKeyCode())) { plane.pressKey(0, player, true); } if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindBack.getKeyCode()))//KeyInputHandler.decelerateKey.getKeyCode())) { plane.pressKey(1, player, true); } if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindLeft.getKeyCode()))//KeyInputHandler.leftKey.getKeyCode())) { plane.pressKey(2, player, true); } if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindRight.getKeyCode()))//KeyInputHandler.rightKey.getKeyCode())) { plane.pressKey(3, player, true); } if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindJump.getKeyCode()))//KeyInputHandler.upKey.getKeyCode())) { plane.pressKey(4, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.downKey.getKeyCode())) { plane.pressKey(5, player, true); } if(FlansMod.proxy.keyDown(mc.gameSettings.keyBindSneak.getKeyCode()))//KeyInputHandler.exitKey.getKeyCode())) { plane.pressKey(6, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.vehicleMenuKey.getKeyCode())) { plane.pressKey(7, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.bombKey.getKeyCode())) { plane.pressKey(8, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.gunKey.getKeyCode())) { plane.pressKey(9, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.controlSwitchKey.getKeyCode())) { plane.pressKey(10, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.leftRollKey.getKeyCode())) { plane.pressKey(11, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.rightRollKey.getKeyCode())) { plane.pressKey(12, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.gearKey.getKeyCode())) { plane.pressKey(13, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.doorKey.getKeyCode())) { plane.pressKey(14, player, true); } if(FlansMod.proxy.keyDown(KeyInputHandler.modeKey.getKeyCode())) { plane.pressKey(15, player, true); } } else { mc.displayGuiScreen(null); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableCrafting.java ================================================ package com.flansmod.client.gui; import java.awt.*; import java.io.IOException; import java.util.HashMap; import org.apache.commons.lang3.NotImplementedException; import io.vavr.collection.List; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.parts.EnumPartCategory; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.EnumType; public class GuiDriveableCrafting extends GuiScreen { /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/driveableCrafting.png"); private static final int CRAFT_BUTTON_ID = 0; private static final int BLUEPRINTS_UP_BUTTON_ID = 1; private static final int BLUEPRINTS_DOWN_BUTTON_ID = 2; private static final int RECIPE_UP_BUTTON_ID = 3; private static final int RECIPE_DOWN_BUTTON_ID = 4; /** * The inventory of the player using this crafting table */ private InventoryPlayer inventory; /** * The Minecraft instance */ private Minecraft mc; /** * Gui origin */ private int guiOriginX, guiOriginY; /** * Blueprint scroller, static to save position upon exiting crafting window */ private static int blueprintsScrollPos = 0; /** * Recipe scroller */ private int recipeScrollPos = 0; /** * The blueprint that is currently selected */ private static int selectedBlueprint = 0; /** * Spins the driveable model */ private float spinner = 0; /** * Whether or not the currently selected driveable can be crafted */ private boolean canCraft = false; public static final int BLUEPRINT_ROW_COUNT = 4; public static final int BLUEPRINT_COLUMN_COUNT = 8; public static final int BLUEPRINT_WIDTH = 18; public static final int BLUEPRINT_HEIGHT = 18; private int blueprintsOriginX; private int blueprintsOriginY; private int statsOriginX; private int statsOriginY; private int vehicleCraftingTextX; private int vehicleCraftingTextY; private int requiresTextX; private int requiresTextY; private int engineTextX; private int engineTextY; public static final int GUI_WIDTH = 176; public static final int GUI_HEIGHT = 198 + 36; public static final int WHITE = Color.white.getRGB(); private int recipeOriginX; private int recipeOriginY; private int engineOriginX; private int engineOriginY; private int modelCenterX; private int modelCenterY; private GuiButton craftButton; public static final int RECIPE_ROW_COUNT = 3; public static final int RECIPE_COLUMN_COUNT = 4; private ArrowButton blueprintsDownButton; private ArrowButton recipeDownButton; private ArrowButton recipeUpButton; private ArrowButton blueprintsUpButton; public GuiDriveableCrafting(InventoryPlayer playerInventory) { inventory = playerInventory; mc = FMLClientHandler.instance().getClient(); } @Override public void initGui() { super.initGui(); guiOriginX = width / 2 - GUI_WIDTH / 2; guiOriginY = height / 2 - GUI_HEIGHT / 2; blueprintsOriginX = guiOriginX + 8; blueprintsOriginY = guiOriginY + 18; statsOriginX = guiOriginX + 82; statsOriginY = guiOriginY + 64 + 36; vehicleCraftingTextX = guiOriginX + 6; vehicleCraftingTextY = guiOriginY + 6; requiresTextX = guiOriginX + 6; requiresTextY = guiOriginY + 125 + 36; engineTextX = guiOriginX + 114; engineTextY = guiOriginY + 141 + 36; recipeOriginX = guiOriginX + 8; recipeOriginY = guiOriginY + 138 + 36; engineOriginX = guiOriginX + 152; engineOriginY = guiOriginY + 138 + 36; modelCenterX = guiOriginX + 42; modelCenterY = guiOriginY + 89 + 36; buttonList.add(craftButton = new GuiButton( CRAFT_BUTTON_ID, guiOriginX + 110, guiOriginY + 162 + 36, 40, 20, "Craft")); buttonList.add(blueprintsUpButton = new ArrowButton( BLUEPRINTS_UP_BUTTON_ID, guiOriginX + 157, guiOriginY + 21, Direction.UP)); buttonList.add(blueprintsDownButton = new ArrowButton( BLUEPRINTS_DOWN_BUTTON_ID, guiOriginX + 157, guiOriginY + 39 + 36, Direction.DOWN)); buttonList.add(recipeUpButton = new ArrowButton( RECIPE_UP_BUTTON_ID, guiOriginX + 83, guiOriginY + 141 + 36, Direction.UP)); buttonList.add(recipeDownButton = new ArrowButton( RECIPE_DOWN_BUTTON_ID, guiOriginX + 83, guiOriginY + 177 + 36, Direction.DOWN)); updateButtons(); } @Override protected void actionPerformed(GuiButton button) { switch(button.id) { case CRAFT_BUTTON_ID: FlansMod.proxy.craftDriveable(inventory.player, DriveableType.types.get(selectedBlueprint)); break; case BLUEPRINTS_UP_BUTTON_ID: if(blueprintsScrollPos > 0) blueprintsScrollPos--; break; case BLUEPRINTS_DOWN_BUTTON_ID: if(blueprintsScrollPos * 8 + 16 < DriveableType.types.size()) blueprintsScrollPos++; break; case RECIPE_UP_BUTTON_ID: if(recipeScrollPos > 0) recipeScrollPos--; break; case RECIPE_DOWN_BUTTON_ID: DriveableType selectedType = DriveableType.types.get(selectedBlueprint); int totalCells = RECIPE_ROW_COUNT * RECIPE_COLUMN_COUNT; if(recipeScrollPos * RECIPE_COLUMN_COUNT + totalCells < selectedType.driveableRecipe.size()) recipeScrollPos++; break; } updateButtons(); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { drawDefaultBackground(); // GUI background mc.renderEngine.bindTexture(texture); drawTexturedModalRect(guiOriginX, guiOriginY, 0, 0, GUI_WIDTH, GUI_HEIGHT); drawString(fontRenderer, "Vehicle Crafting", vehicleCraftingTextX, vehicleCraftingTextY, WHITE); // Blueprints selector List itemsToRender = getBlueprintItemsToRender(); // Preview DriveableType selectedType = DriveableType.types.get(selectedBlueprint); drawPreview(selectedType); // Stats drawStats(selectedType); // Engine requirements drawString(fontRenderer, "Engine", engineTextX, engineTextY, WHITE); drawString(fontRenderer, selectedType.numEngines() + "x", engineTextX - 14, engineTextY, WHITE); canCraft = true; // Recipe items itemsToRender = itemsToRender.pushAll(getRecipeItemsToRender(selectedType)); // Collect up all the engines into neat and tidy stacks so we can find if any of them are big enough // and which of those stacks are best ItemStack bestEngineStack = getBestEngineStackForType(selectedType); // Draw engine slot itemsToRender = itemsToRender.pushAll(getEngineItemToRender(bestEngineStack)); craftButton.enabled = canCraft; GlStateManager.disableLighting(); super.drawScreen(mouseX, mouseY, partialTicks); itemsToRender.forEach(item -> drawSlotInventory(item.itemStack, item.x, item.y, mouseX, mouseY)); } private List getEngineItemToRender(ItemStack engineStack) { List itemsToRender = List.empty(); mc.renderEngine.bindTexture(texture); if(engineStack.isEmpty()) { drawTexturedModalRect(engineOriginX, engineOriginY, 195, 11, 16, 16); canCraft = false; } else { itemsToRender = itemsToRender.push(new ItemToRender(engineStack, engineOriginX, engineOriginY)); } return itemsToRender; } private ItemStack getBestEngineStackForType(DriveableType selectedType) { HashMap engines = getPlayersEnginesForType(selectedType); //Find the stack of engines that is fastest but which also has enough for this driveable float bestEngineSpeed = -1F; ItemStack bestEngineStack = ItemStack.EMPTY.copy(); for(PartType part : engines.keySet()) { //If this engine outperforms the currently selected best one and there are enough of them, swap if(part.engineSpeed > bestEngineSpeed && engines.get(part).getCount() >= selectedType.numEngines()) { bestEngineSpeed = part.engineSpeed; bestEngineStack = engines.get(part); } } return bestEngineStack; } private HashMap getPlayersEnginesForType(DriveableType selectedType) { HashMap engines = new HashMap<>(); //Find some suitable engines for(ItemStack itemStack : inventory.mainInventory) { if(itemStack.getItem() instanceof ItemPart) { PartType partType = ((ItemPart)itemStack.getItem()).type; //Check its an engine that we can use if(partType.category == EnumPartCategory.ENGINE && partType.worksWith.contains(EnumType.getFromObject(selectedType))) { //If we already have engines of this type, add these ones to the stack if(engines.containsKey(partType)) { engines.get(partType).setCount(engines.get(partType).getCount() + itemStack.getCount()); } //Else, make this the first stack else engines.put(partType, itemStack); } } } return engines; } private List getRecipeItemsToRender(DriveableType selectedType) { List itemsToRender = List.empty(); drawString(fontRenderer, "Requires", requiresTextX, requiresTextY, WHITE); for(int row = 0; row < RECIPE_ROW_COUNT; row++) { for(int column = RECIPE_COLUMN_COUNT - 1; column >= 0; column--) { int pageStartIndex = recipeScrollPos * RECIPE_COLUMN_COUNT; int rowStartInPageIndex = row * RECIPE_COLUMN_COUNT; int recipeItemNumber = pageStartIndex + rowStartInPageIndex + column; if(recipeItemNumber < selectedType.driveableRecipe.size()) { ItemStack recipeStack = selectedType.driveableRecipe.get(recipeItemNumber); int totalAmountFound = 0; for(ItemStack itemStack : inventory.mainInventory) { if(itemStack.getItem() == recipeStack.getItem() && itemStack.getItemDamage() == recipeStack.getItemDamage()) { totalAmountFound += itemStack.getCount(); if(totalAmountFound == recipeStack.getCount()) break; } } //If we didn't find enough, give the stack a red outline if(totalAmountFound < recipeStack.getCount()) { mc.renderEngine.bindTexture(texture); drawTexturedModalRect( recipeOriginX + column * BLUEPRINT_WIDTH, recipeOriginY + row * BLUEPRINT_HEIGHT, 195, 11, 16, 16); canCraft = false; } //Draw the actual item we want itemsToRender = itemsToRender.push(new ItemToRender( recipeStack, recipeOriginX + column * BLUEPRINT_WIDTH, recipeOriginY + row * BLUEPRINT_HEIGHT)); } } } return itemsToRender; } private void drawStats(DriveableType selectedType) { GlStateManager.disableLighting(); String recipeName = selectedType.name; if(recipeName.length() > 16) recipeName = recipeName.substring(0, 15) + "..."; // Driveable stats drawString(fontRenderer, recipeName, statsOriginX, statsOriginY, WHITE); drawString( fontRenderer, "Cargo Slots : " + selectedType.numCargoSlots, statsOriginX, statsOriginY + 10, WHITE); drawString( fontRenderer, "Bomb Slots : " + selectedType.numBombSlots, statsOriginX, statsOriginY + 20, WHITE); drawString( fontRenderer, "Passengers : " + selectedType.numPassengers, statsOriginX, statsOriginY + 30, WHITE); drawString(fontRenderer, "Guns : " + (selectedType.ammoSlots()), statsOriginX, statsOriginY + 40, WHITE); } private void drawPreview(DriveableType selectedType) { //Increment the spinner to spin the driveable. Wheeee! spinner++; //Render rotating driveable model GlStateManager.pushMatrix(); if(selectedType.model != null) { GlStateManager.translate(modelCenterX, modelCenterY, 100); GlStateManager.disableLighting(); //Do lights GlStateManager.pushMatrix(); { GlStateManager.rotate(180F, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(0F, 0.0F, 1.0F, 0.0F); RenderHelper.enableStandardItemLighting(); } GlStateManager.popMatrix(); GlStateManager.enableRescaleNormal(); if(selectedType instanceof MechaType) GlStateManager.translate(0, 15, 0); GlStateManager.scale( -50F * selectedType.modelScale / selectedType.cameraDistance, 50F * selectedType.modelScale / selectedType.cameraDistance, 50F * selectedType.modelScale / selectedType.cameraDistance); GlStateManager.rotate(180F, 0F, 0F, 1F); GlStateManager.rotate(30F, 1F, 0F, 0F); GlStateManager.rotate(spinner / 5F, 0F, 1F, 0F); mc.renderEngine.bindTexture(FlansModResourceHandler.getTexture(selectedType)); selectedType.model.render(selectedType); } GlStateManager.popMatrix(); } private List getBlueprintItemsToRender() { List itemsToRender = List.empty(); for(int row = BLUEPRINT_ROW_COUNT - 1; row >= 0; row--) { for(int column = 0; column < BLUEPRINT_COLUMN_COUNT; column++) { int pageStartIndex = blueprintsScrollPos * BLUEPRINT_COLUMN_COUNT; int rowStartInPageIndex = row * BLUEPRINT_COLUMN_COUNT; int blueprintNumber = pageStartIndex + rowStartInPageIndex + column; // Draw outline for selected blueprint if(blueprintNumber == selectedBlueprint) { mc.renderEngine.bindTexture(texture); drawTexturedModalRect( blueprintsOriginX + column * BLUEPRINT_WIDTH, blueprintsOriginY + row * BLUEPRINT_HEIGHT, 213, 11, BLUEPRINT_WIDTH - 2, BLUEPRINT_HEIGHT - 2); } // Draw blueprint if(blueprintNumber < DriveableType.types.size()) { DriveableType type = DriveableType.types.get(blueprintNumber); itemsToRender = itemsToRender.push(new ItemToRender( new ItemStack(type.item), blueprintsOriginX + column * BLUEPRINT_WIDTH, blueprintsOriginY + row * BLUEPRINT_HEIGHT)); } } } return itemsToRender; } /** * Item stack rendering method */ private void drawSlotInventory(ItemStack itemstack, int x, int y, int mouseX, int mouseY) { if(itemstack == null) return; itemRender.renderItemIntoGUI(itemstack, x, y); itemRender.renderItemOverlayIntoGUI(fontRenderer, itemstack, x, y, null); drawTooltip(itemstack.getDisplayName(), x, y, mouseX, mouseY, 16, 16); } private void drawTooltip(String text, int x, int y, int mouseX, int mouseY, int iconWidth, int iconHeight) { if(mouseX >= x && mouseY >= y && mouseX < x + iconWidth && mouseY < y + iconHeight) { drawHoveringText(text, mouseX, mouseY); } } @Override protected void keyTyped(char c, int i) { if(i == 1 || i == mc.gameSettings.keyBindInventory.getKeyCode()) { mc.player.closeScreen(); } } @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { super.mouseClicked(mouseX, mouseY, mouseButton); if(mouseButton == 0 || mouseButton == 1) { //Driveable buttons for(int row = 0; row < BLUEPRINT_ROW_COUNT; row++) { for(int column = 0; column < BLUEPRINT_COLUMN_COUNT; column++) { if(mouseX >= blueprintsOriginX + column * BLUEPRINT_WIDTH && mouseX < blueprintsOriginX + column * BLUEPRINT_WIDTH + BLUEPRINT_WIDTH && mouseY >= blueprintsOriginY + row * BLUEPRINT_HEIGHT && mouseY < blueprintsOriginY + row * BLUEPRINT_HEIGHT + BLUEPRINT_HEIGHT) { int pageStartIndex = blueprintsScrollPos * BLUEPRINT_COLUMN_COUNT; int rowStartInPageIndex = row * BLUEPRINT_COLUMN_COUNT; int result = pageStartIndex + rowStartInPageIndex + column; if(result < DriveableType.types.size()) { recipeScrollPos = 0; selectedBlueprint = result; return; } } } } } } @Override public boolean doesGuiPauseGame() { return false; } private void updateButtons() { // Blueprint buttons blueprintsUpButton.enabled = blueprintsScrollPos > 0; int totalBlueprintsCells = BLUEPRINT_COLUMN_COUNT * BLUEPRINT_ROW_COUNT; blueprintsDownButton.enabled = blueprintsScrollPos * BLUEPRINT_COLUMN_COUNT + totalBlueprintsCells < DriveableType.types.size() - 1; // Recipe buttons recipeUpButton.enabled = recipeScrollPos > 0; int totalRecipeItems = RECIPE_COLUMN_COUNT * RECIPE_ROW_COUNT; DriveableType selectedType = DriveableType.types.get(selectedBlueprint); recipeDownButton.enabled = recipeScrollPos * RECIPE_COLUMN_COUNT + totalRecipeItems < selectedType.driveableRecipe.size() - 1; } private static class ArrowButton extends GuiButton { public static final int WIDTH = 10; public static final int HEIGHT = 10; public final int enabledTextureX; public final int enabledTextureY = 0; public final int disabledTextureX; public final int disabledTextureY = 0; public final Direction direction; public ArrowButton(int buttonId, int x, int y, Direction direction) { super(buttonId, x, y, WIDTH, HEIGHT, ""); this.direction = direction; switch(direction) { case UP: enabledTextureX = 216; disabledTextureX = 196; break; case DOWN: enabledTextureX = 226; disabledTextureX = 206; break; default: throw new NotImplementedException("Texture location not set for direction"); } } @Override public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) { if(visible) { mc.renderEngine.bindTexture(texture); if(enabled) { drawTexturedModalRect(x, y, enabledTextureX, enabledTextureY, WIDTH, HEIGHT); } else { drawTexturedModalRect(x, y, disabledTextureX, disabledTextureY, WIDTH, HEIGHT); } } } } private static class ItemToRender { public ItemStack itemStack; public int x; public int y; public ItemToRender(ItemStack itemStack, int x, int y) { this.itemStack = itemStack; this.x = x; this.y = y; } } private enum Direction {UP, DOWN} } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableFuel.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.common.driveables.ContainerDriveableMenu; import com.flansmod.common.driveables.EntityDriveable; public class GuiDriveableFuel extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/planeFuel.png"); public World world; public InventoryPlayer inventory; public EntityDriveable plane; private int anim = 0; private long lastTime; public GuiDriveableFuel(InventoryPlayer inventoryplayer, World world1, EntityDriveable entPlane) { super(new ContainerDriveableMenu(inventoryplayer, world1, true, entPlane)); plane = entPlane; ySize = 161; world = world1; inventory = inventoryplayer; } @Override protected void drawGuiContainerForegroundLayer(int i, int j) { fontRenderer.drawString(plane.getDriveableType().name + " - Fuel", 6, 6, 0x404040); fontRenderer.drawString("Inventory", 8, (ySize - 96) + 2, 0x404040); } @Override protected void drawGuiContainerBackgroundLayer(float f, int i1, int j1) { long newTime = mc.world.getWorldInfo().getWorldTime(); if(newTime > lastTime) { lastTime = newTime; if(newTime % 5 == 0) anim++; } GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); mc.renderEngine.bindTexture(texture); int j = (width - xSize) / 2; int k = (height - ySize) / 2; drawTexturedModalRect(j, k, 0, 0, xSize, ySize); int fuelTankSize = plane.getDriveableType().fuelTankSize; float fuelInTank = plane.driveableData.fuelInTank; if(plane.fuelling) drawTexturedModalRect(j + 15, k + 44, 176 + 15 * (anim % 4), 0, 15, 16); if(fuelInTank < fuelTankSize / 8 && (anim % 4) > 1) drawTexturedModalRect(j + 16, k + 25, 176, 16, 6, 6); if(fuelInTank > 0) drawTexturedModalRect(j + 26, k + 21, 0, 161, (int)((129 * fuelInTank) / fuelTankSize), 15); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int m = i - (width - xSize) / 2; int n = j - (height - ySize) / 2; if(m > 161 && m < 171 && n > 5 && n < 15) { mc.displayGuiScreen(new GuiDriveableMenu(inventory, world, plane)); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableInventory.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.ContainerDriveableInventory; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.network.PacketDriveableGUI; public class GuiDriveableInventory extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/planeInventory.png"); public ContainerDriveableInventory container; public InventoryPlayer inventory; public World world; public int scroll; public int numItems; public int maxScroll; public EntityDriveable driveable; public int screen; //0 = Guns, 1 = Bombs, 2 = Cargo public GuiDriveableInventory(InventoryPlayer inventoryplayer, World world1, EntityDriveable entPlane, int i) { super(new ContainerDriveableInventory(inventoryplayer, world1, entPlane, i)); driveable = entPlane; inventory = inventoryplayer; world = world1; container = (ContainerDriveableInventory)inventorySlots; ySize = 180; screen = i; maxScroll = container.maxScroll; numItems = container.numItems; } @Override protected void drawGuiContainerForegroundLayer(int x, int y) { String title = " - Guns"; if(screen == 1) title = " - " + driveable.getBombInventoryName(); if(screen == 2) title = " - Cargo"; if(screen == 3) title = " - " + driveable.getMissileInventoryName(); fontRenderer.drawString(driveable.getDriveableType().name + title, 6, 6, 0x404040); fontRenderer.drawString("Inventory", 8, (ySize - 96) + 2, 0x404040); RenderHelper.enableGUIStandardItemLighting(); GlStateManager.color(1.0F, 1.0F, 1.0F); if(screen == 0) { int slotsDone = 0; for(int i = 0; i < driveable.getDriveableType().seats.length; i++) { if(slotsDone >= 3 + scroll) continue; if(driveable.getDriveableType().seats[i].gunType != null) { if(slotsDone >= scroll) { fontRenderer.drawString(driveable.getDriveableType().seats[i].gunName, 53, 29 + 19 * (slotsDone - scroll), 0x000000); drawStack(new ItemStack(driveable.getDriveableType().seats[i].gunType.getItem()), 10, 25 + 19 * (slotsDone - scroll)); } slotsDone++; } } for(int i = 0; i < driveable.getDriveableType().pilotGuns.size(); i++) { if(slotsDone >= 3 + scroll) continue; if(driveable.getDriveableType().pilotGuns.get(i).type != null) { if(slotsDone >= scroll) { fontRenderer.drawString("Driver's gun " + (i + 1), 53, 29 + 19 * (slotsDone - scroll), 0x000000); drawStack(new ItemStack(driveable.getDriveableType().pilotGuns.get(i).type.getItem()), 10, 25 + 19 * (slotsDone - scroll)); } slotsDone++; } } } GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableRescaleNormal(); RenderHelper.disableStandardItemLighting(); GlStateManager.disableDepth(); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } private void drawStack(ItemStack itemstack, int x, int y) { itemRender.renderItemIntoGUI(itemstack, x, y); itemRender.renderItemOverlayIntoGUI(fontRenderer, itemstack, x, y, null); } private static String getGunSlotName(int i) { switch(i) { case 0: return "Left Nose Gun"; case 1: return "Right Nose Gun"; case 2: return "Left Wing Gun"; case 3: return "Right Wing Gun"; case 4: return "Tail Gun"; case 5: return "Left Bay Gun"; case 6: return "Right Bay Gun"; case 7: return "Dorsal Gun"; } return "Not a Gun"; } @Override protected void drawGuiContainerBackgroundLayer(float f, int i1, int j1) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); mc.renderEngine.bindTexture(texture); int j = (width - xSize) / 2; int k = (height - ySize) / 2; drawTexturedModalRect(j, k, 0, 0, xSize, ySize); switch(screen) { case 0: { for(int n = 0; n < (numItems > 3 ? 3 : numItems); n++) { drawTexturedModalRect(j + 9, k + 24 + 19 * n, 176, 0, 37, 18); } break; } case 1: case 2: case 3: { int m = ((numItems + 7) / 8); for(int row = 0; row < (m > 3 ? 3 : m); row++) { drawTexturedModalRect(j + 9, k + 24 + 19 * row, 7, 97, 18 * ((row + scroll + 1) * 8 <= numItems ? 8 : numItems % 8), 18); } break; } } if(scroll == 0) drawTexturedModalRect(j + 161, k + 41, 176, 18, 10, 10); if(scroll == maxScroll) drawTexturedModalRect(j + 161, k + 53, 176, 28, 10, 10); } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int m = i - (width - xSize) / 2; int n = j - (height - ySize) / 2; if(scroll > 0 && m > 161 && m < 171 && n > 41 && n < 51) { scroll--; container.updateScroll(scroll); } if(scroll < maxScroll && m > 161 && m < 171 && n > 53 && n < 63) { scroll++; container.updateScroll(scroll); } if(m > 161 && m < 171 && n > 5 && n < 15) { if(driveable instanceof EntityMecha) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(4)); (inventory.player).openGui(FlansMod.INSTANCE, 10, world, driveable.chunkCoordX, driveable.chunkCoordY, driveable.chunkCoordZ); } else mc.displayGuiScreen(new GuiDriveableMenu(inventory, world, driveable)); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableMenu.java ================================================ package com.flansmod.client.gui; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.ContainerDriveableMenu; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.network.PacketDriveableGUI; public class GuiDriveableMenu extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/planeMenu.png"); public World world; public InventoryPlayer inventory; public EntityDriveable entity; public GuiDriveableMenu(InventoryPlayer inventoryplayer, World world1, EntityDriveable entPlane) { super(new ContainerDriveableMenu(inventoryplayer, world1)); entity = entPlane; ySize = 180; world = world1; inventory = inventoryplayer; } @Override public void initGui() { super.initGui(); DriveableType type = entity.getDriveableType(); //Cargo button GuiButton cargoButton = new GuiButton(0, width / 2 - 60, height / 2 - 71, 58, 20, "Cargo"); cargoButton.enabled = type.numCargoSlots > 0; buttonList.add(cargoButton); //Gun button GuiButton gunsButton = new GuiButton(1, width / 2 + 2, height / 2 - 71, 58, 20, "Guns"); gunsButton.enabled = type.ammoSlots() > 0; buttonList.add(gunsButton); //Fuel button GuiButton fuelButton = new GuiButton(2, width / 2 - 60, height / 2 - 49, 58, 20, "Fuel"); fuelButton.enabled = type.fuelTankSize > 0; buttonList.add(fuelButton); //Missile / Shell Button GuiButton missileButton = new GuiButton(3, width / 2 + 2, height / 2 - 49, 58, 20, entity.getMissileInventoryName()); missileButton.enabled = type.numMissileSlots > 0; buttonList.add(missileButton); //Mine / Bomb Button GuiButton bombButton = new GuiButton(5, width / 2 + 2, height / 2 - 27, 58, 20, entity.getBombInventoryName()); bombButton.enabled = type.numBombSlots > 0; buttonList.add(bombButton); //Repair button buttonList.add(new GuiButton(4, width / 2 - 60, height / 2 - 27, 58, 20, "Repair")); } @Override protected void actionPerformed(GuiButton button) { //Replace with a packet requesting the GUI from the server if(button.id == 0) //Cargo { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(3)); //inventory.player.openGui(FlansMod.INSTANCE, 9, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } if(button.id == 1) //Guns { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(0)); //inventory.player.openGui(FlansMod.INSTANCE, 6, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } if(button.id == 2) //Fuel { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(2)); //inventory.player.openGui(FlansMod.INSTANCE, 8, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } if(button.id == 3) //Missiles { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(5)); //inventory.player.openGui(FlansMod.INSTANCE, 12, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } if(button.id == 4) //Repair { //No server side required. No interactive slots in this one inventory.player.openGui(FlansMod.INSTANCE, 1, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } if(button.id == 5) //Bombs { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(1)); //inventory.player.openGui(FlansMod.INSTANCE, 7, world, entity.chunkCoordX, entity.chunkCoordY, entity.chunkCoordZ); } } @Override protected void drawGuiContainerForegroundLayer(int i, int j) { fontRenderer.drawString(entity.getDriveableType().name, 6, 6, 0x404040); fontRenderer.drawString("Inventory", 8, (ySize - 96) + 2, 0x404040); } @Override protected void drawGuiContainerBackgroundLayer(float f, int i1, int j1) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); mc.renderEngine.bindTexture(texture); int j = (width - xSize) / 2; int k = (height - ySize) / 2; drawTexturedModalRect(j, k, 0, 0, xSize, ySize); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiDriveableRepair.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import java.util.ArrayList; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.network.PacketDriveableGUI; public class GuiDriveableRepair extends GuiScreen { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/repair.png"); /** * The player using this GUI */ private EntityPlayer driver; /** * The driveable (s)he is driving */ private EntityDriveable driving; /** * The list of parts that are actually damageable */ private ArrayList partsToDraw = new ArrayList<>(); /** * Item renderer */ private static RenderItem itemRenderer; /** * Gui origin */ private int guiOriginX, guiOriginY; public GuiDriveableRepair(EntityPlayer player) { super(); driver = player; driving = ((EntitySeat)player.getRidingEntity()).driveable; for(DriveablePart part : driving.getDriveableData().parts.values()) { //Check to see if the part is actually damageable if(part.maxHealth > 0) { //Add it to the list of parts to draw partsToDraw.add(part); } } } @Override public void initGui() { super.initGui(); for(int i = 0; i < partsToDraw.size(); i++) { buttonList.add(new GuiButton(i, 0, 0, 55, 20, "Repair")); } itemRenderer = mc.getRenderItem(); } @Override protected void actionPerformed(GuiButton button) { FlansMod.proxy.repairDriveable(driver, driving, partsToDraw.get(button.id)); } private void updateButtons() { int y = 43; for(int i = 0; i < partsToDraw.size(); i++) { DriveablePart part = partsToDraw.get(i); GuiButton button = buttonList.get(i); button.visible = part.health <= 0; button.x = guiOriginX + 9; button.y = guiOriginY + y; y += part.health <= 0 ? 40 : 20; } } @Override public void drawScreen(int i, int j, float f) { int guiWidth = 202; //Work out the guiHeight by adding what is necessary for each part int guiHeight = 31; for(DriveablePart part : partsToDraw) { //Add to the GUI height depending on whether we need a repair button or not guiHeight += part.health <= 0 ? 40 : 20; } //Update the buttons updateButtons(); //Standard GUI render stuff ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); //Bind the background texture mc.renderEngine.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); //Calculate the gui origin guiOriginX = w / 2 - guiWidth / 2; guiOriginY = h / 2 - guiHeight / 2; //Render the header drawTexturedModalRect(guiOriginX, guiOriginY, 0, 0, 202, 23); //Render the footer drawTexturedModalRect(guiOriginX, guiOriginY + guiHeight - 8, 0, 65, 202, 8); //Render the title drawString(fontRenderer, driving.getDriveableType().name + " - Repair", guiOriginX + 7, guiOriginY + 7, 0xffffff); //Render each part //Where to start rendering from. Updated with each part int y = 23; for(DriveablePart part : partsToDraw) { boolean broken = part.health <= 0; //Render the background for this section mc.renderEngine.bindTexture(texture); drawTexturedModalRect(guiOriginX, guiOriginY + y, 0, 24, 202, broken ? 40 : 20); //Render the damage bar float percentHealth = (float)part.health / (float)part.maxHealth; GlStateManager.color(1 - percentHealth, percentHealth, 0F); drawTexturedModalRect(guiOriginX + 121, guiOriginY + y + 2, 0, 73, (int)(70 * percentHealth), 16); //Write the part name and percent health drawString(fontRenderer, part.type.getName(), guiOriginX + 10, guiOriginY + y + 6, 0xffffff); drawCenteredString(fontRenderer, (int)(percentHealth * 100F) + "%", guiOriginX + 158, guiOriginY + y + 6, 0xffffff); //If the part is damaged, draw the parts required to fix it if(broken) { //Create a temporary copy of the player inventory in order to work out whether the player has each of the itemstacks required InventoryPlayer temporaryInventory = new InventoryPlayer(null); temporaryInventory.copyInventory(driver.inventory); ArrayList stacksNeeded = driving.getDriveableType().getItemsRequired(part, driving.getDriveableData().engine); //Draw the stacks that should be in each slot for(int n = 0; n < 7; n++) { //If there are more than 7 stacks, loop over them int stackNum = n + (FlansMod.ticker / 60) % Math.max(1, stacksNeeded.size() - 6); //If this is a valid stack if(stackNum < stacksNeeded.size()) { //Get the item stack we need ItemStack stackNeeded = stacksNeeded.get(stackNum); //The total amount of items found that match this recipe stack int totalAmountFound = 0; //Iterate over the temporary inventory for(int m = 0; m < temporaryInventory.getSizeInventory(); m++) { //Get the stack in each slot ItemStack stackInSlot = temporaryInventory.getStackInSlot(m).copy(); //If the stack is what we want if(stackInSlot.getItem() == stackNeeded.getItem() && stackInSlot.getItemDamage() == stackNeeded.getItemDamage()) { //Work out the amount to take from the stack int amountFound = Math.min(stackInSlot.getCount(), stackNeeded.getCount() - totalAmountFound); //Take it stackInSlot.setCount(stackInSlot.getCount() - amountFound); //Check for empty stacks if(stackInSlot.getCount() <= 0) stackInSlot = ItemStack.EMPTY.copy(); //Put the modified stack back in the inventory temporaryInventory.setInventorySlotContents(m, stackInSlot); //Increase the amount found counter totalAmountFound += amountFound; //If we have enough, stop looking if(totalAmountFound == stackNeeded.getCount()) break; } } //If we did not find enough in the inventory if(totalAmountFound < stackNeeded.getCount()) { mc.renderEngine.bindTexture(texture); drawTexturedModalRect(guiOriginX + 67 + 18 * n, guiOriginY + y + 22, 202, 0, 16, 16); } drawSlotInventory(stacksNeeded.get(stackNum), guiOriginX + 67 + 18 * n, guiOriginY + y + 22); } } } //Increase the render y value for the next part y += broken ? 40 : 20; } super.drawScreen(i, j, f); } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int m = i - guiOriginX; int n = j - guiOriginY; if(m > 185 && m < 195 && n > 5 && n < 15) if(driving instanceof EntityMecha) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(4)); (driver).openGui(FlansMod.INSTANCE, 10, driver.world, driving.chunkCoordX, driving.chunkCoordY, driving.chunkCoordZ); } else mc.displayGuiScreen(new GuiDriveableMenu(driver.inventory, driver.world, driving)); } /** * Item stack renderering method */ private void drawSlotInventory(ItemStack itemstack, int i, int j) { if(itemstack == null || itemstack.isEmpty()) return; itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiGunBox.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.boxes.ContainerGunBox; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.guns.boxes.GunBoxType.GunBoxEntry; import com.flansmod.common.guns.boxes.GunBoxType.GunBoxEntryTopLevel; import com.flansmod.common.guns.boxes.GunBoxType.GunBoxPage; import com.flansmod.common.network.PacketBuyWeapon; import com.flansmod.common.types.InfoType; public class GuiGunBox extends GuiContainer { private static final int numCategories = 4; /** * Texture location */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/weaponBoxNew.png"); /** * Texture sizes */ private final int textureX = 512, textureY = 256; private InventoryPlayer inventory; private static RenderItem itemRenderer; private GunBoxType type; private int pageScroller; private GunBoxPage currentPage; private GunBoxEntryTopLevel currentEntry; private GunBoxEntry currentSubEntry; private int guiOriginX; private int guiOriginY; private int scroll; private GuiButton craftLeft, craftRight, categoryLeft, categoryRight; private GuiButton[] categories = new GuiButton[numCategories]; public GuiGunBox(InventoryPlayer inventory, GunBoxType type) { super(new ContainerGunBox(inventory)); this.inventory = inventory; this.type = type; pageScroller = 0; currentPage = type.pages.get(0); xSize = ySize = 256; } @Override public void updateScreen() { super.updateScreen(); scroll++; if(craftLeft != null && craftRight != null) { craftLeft.visible = currentEntry != null; craftRight.visible = currentSubEntry != null; if(currentEntry != null) { craftLeft.enabled = currentEntry.canCraft(inventory, false); } if(currentSubEntry != null) { craftRight.enabled = currentSubEntry.canCraft(inventory, false); } } } @Override public void initGui() { super.initGui(); itemRenderer = mc.getRenderItem(); craftLeft = new GuiButton(0, width / 2 - 119, height / 2 + 15, 87, 20, "Craft"); craftLeft.visible = false; buttonList.add(craftLeft); craftRight = new GuiButton(1, width / 2 + 33, height / 2 + 15, 87, 20, "Craft"); craftRight.visible = false; buttonList.add(craftRight); categoryLeft = new GuiButton(2, width / 2 - 119, height / 2 - 122, 20, 20, "<"); categoryLeft.enabled = false; buttonList.add(categoryLeft); categoryRight = new GuiButton(3, width / 2 + 99, height / 2 - 122, 20, 20, ">"); categoryRight.enabled = type.pages.size() > (pageScroller + 1) * numCategories; buttonList.add(categoryRight); for(int i = 0; i < numCategories; i++) { if(pageScroller * numCategories + i < type.pages.size()) { categories[i] = new GuiButton(4 + i, width / 2 - numCategories * 30 + i * 60, height / 2 - 100, 60, 20, type.pages.get(pageScroller * numCategories + i).name); buttonList.add(categories[i]); } else { categories[i] = new GuiButton(4 + i, width / 2 - numCategories * 30 + i * 60, height / 2 - 100, 60, 20, "NONE"); categories[i].visible = false; buttonList.add(categories[i]); } } } @Override protected void actionPerformed(GuiButton button) { if(categories == null) { return; } switch(button.id) { case 0: //Left FlansMod.getPacketHandler().sendToServer(new PacketBuyWeapon(type, currentEntry.type)); break; case 1: //Right FlansMod.getPacketHandler().sendToServer(new PacketBuyWeapon(type, currentSubEntry.type)); break; case 2: //Left if(pageScroller > 0) pageScroller--; break; case 3: //Right if(type.pages.size() > (pageScroller + 1) * numCategories) pageScroller++; break; default: currentPage = type.pages.get(pageScroller * numCategories + button.id - 4); currentEntry = currentPage.entries.size() == 0 ? null : currentPage.entries.get(0); currentSubEntry = currentEntry == null ? null : (currentEntry.childEntries.size() == 0 ? null : currentEntry.childEntries.get(0)); } categoryLeft.enabled = pageScroller > 0; categoryRight.enabled = type.pages.size() > (pageScroller + 1) * numCategories; for(int i = 0; i < numCategories; i++) { if(pageScroller * numCategories + i < type.pages.size()) { categories[i].visible = true; categories[i].displayString = type.pages.get(pageScroller * numCategories + i).name; } else categories[i].visible = false; } } @Override protected void drawGuiContainerBackgroundLayer(float f, int i1, int j1) { GlStateManager.color(1F, 1F, 1F, 1F); mc.renderEngine.bindTexture(texture); int originX = guiOriginX = (width - xSize) / 2; int originY = guiOriginY = (height - ySize) / 2; drawModalRectWithCustomSizedTexture(originX, originY, 0, 0, xSize, ySize, textureX, textureY); if(currentPage != null) { if(currentEntry != null) { int currentEntryIndex = currentPage.entries.indexOf(currentEntry); //Render sub entry selection boxes drawModalRectWithCustomSizedTexture(originX + 130, originY + 54, 290, 4, 24, 112, textureX, textureY); drawModalRectWithCustomSizedTexture(originX + 95, originY + 57 + currentEntryIndex * 22, 318, 28, 38, 18, textureX, textureY); //Loop twice for bg texture and item for(int i = 0; i < 5; i++) { if(i >= currentEntry.childEntries.size()) break; GunBoxEntry subEntry = currentEntry.childEntries.get(i); drawModalRectWithCustomSizedTexture(originX + 133, originY + 57 + i * 22, 319, 8, 18, 18, textureX, textureY); } if(currentSubEntry != null) { int currentSubEntryIndex = currentEntry.childEntries.indexOf(currentSubEntry); // Render right panel thing drawModalRectWithCustomSizedTexture(originX + 132, originY + 55 + currentSubEntryIndex * 22, 327, 48, 29, 22, textureX, textureY); //Render right panel bg renderPanelBackground(currentSubEntry, originX + 161, originY + 57); } //Render left panel for bg renderPanelBackground(currentEntry, originX + 8, originY + 57); //Render left panel detail renderPanelForeground(currentEntry, originX + 8, originY + 57); if(currentSubEntry != null) { //Render right panel detail renderPanelForeground(currentSubEntry, originX + 161, originY + 57); } for(int i = 0; i < 5; i++) { if(i >= currentEntry.childEntries.size()) break; GunBoxEntry subEntry = currentEntry.childEntries.get(i); renderInfoType(subEntry.type, originX + 134, originY + 58 + i * 22); } } //Render options for(int i = 0; i < 5; i++) { if(i >= currentPage.entries.size()) break; GunBoxEntryTopLevel entry = currentPage.entries.get(i); renderInfoType(entry.type, originX + 106, originY + 58 + i * 22); } } int stringWidth = mc.fontRenderer.getStringWidth(type.name); mc.fontRenderer.drawString(type.name, originX + xSize / 2 - stringWidth / 2, originY + 8, 0x00000000); mc.fontRenderer.drawString(type.name, originX + xSize / 2 - stringWidth / 2 + 1, originY + 7, 0xffffffff); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } private void renderInfoType(InfoType type, int x, int y) { if(type == null) { //FlansMod.log.warn("Null type when rendering!"); return; } drawSlotInventory(new ItemStack(type.item), x, y); } private void renderPanelBackground(GunBoxEntry entry, int x, int y) { int numParts = entry.requiredParts.size(); int numPartsOnLine1 = Math.min(numParts, 4); int numPartsOnLine2 = numParts > 4 ? Math.min(numParts - 4, 4) : 0; for(int i = 0; i < numPartsOnLine1; i++) { if(entry.haveEnoughOf(inventory, entry.requiredParts.get(i))) drawModalRectWithCustomSizedTexture(x + 5 + 20 * i, y + 64, 294, 142, 18, 18, textureX, textureY); else drawModalRectWithCustomSizedTexture(x + 5 + 20 * i, y + 64, 276, 142, 18, 18, textureX, textureY); } //if(numPartsOnLine1 > 0) // drawModalRectWithCustomSizedTexture(x + 5, y + 44, 276, 122, 18 + 20 * (numPartsOnLine1 - 1), 18, textureX, textureY); //if(numPartsOnLine2 > 0) // drawModalRectWithCustomSizedTexture(x + 5, y + 64, 276, 122, 18 + 20 * (numPartsOnLine2 - 1), 18, textureX, textureY); } private void renderPanelForeground(GunBoxEntry entry, int x, int y) { if(entry == null || entry.type == null) { return; } FontRenderer fr = mc.fontRenderer; String bufferLine = ""; String bufferLine2 = ""; String bufferArray[] = entry.type.name.split(" "); for(String aBufferArray : bufferArray) { if((bufferLine.length() + aBufferArray.length()) <= 16) bufferLine += aBufferArray + " "; else bufferLine2 += aBufferArray + " "; } fr.drawString(bufferLine, x + 5, y + 5, 0x00000000); fr.drawString(bufferLine2, x + 5, y + 15, 0x00000000); if(entry.type instanceof GunType) { GunType gun = (GunType)entry.type; fr.drawString("Damage: ", x + 5, y + 25, 0x00000000); String tempString = "" + gun.damage; fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 25, 0x00000000); fr.drawString("Spread: ", x + 5, y + 35, 0x00000000); tempString = "" + gun.bulletSpread; fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 35, 0x00000000); if(gun.shootDelay > 0) { fr.drawString("RoF: ", x + 5, y + 45, 0x00000000); tempString = String.format("%.0f RPM", 60f * 20f / gun.shootDelay); fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 45, 0x00000000); } } else if(entry.type instanceof ShootableType) { ShootableType gun = (ShootableType)entry.type; fr.drawString("No. Rounds: ", x + 5, y + 25, 0x00000000); String tempString = "" + gun.roundsPerItem; fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 25, 0x00000000); if(gun.numBullets > 1) { fr.drawString("Pellets: ", x + 5, y + 35, 0x00000000); tempString = "" + gun.numBullets; fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 35, 0x00000000); } else if(gun.fireRadius > 0f) { fr.drawString("Creates Fire", x + 5, y + 35, 0x00000000); } else if(gun.explosionRadius > 0f) { fr.drawString("Explosion: ", x + 5, y + 35, 0x00000000); tempString = "" + gun.explosionRadius; fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 35, 0x00000000); } if(gun.damageVsDriveable > 1.0f) { fr.drawString("Anti-Tank: ", x + 5, y + 45, 0x00000000); tempString = String.format("x%.0f", gun.damageVsDriveable); fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 45, 0x00000000); } else if(gun.damageVsLiving > 1.0f) { fr.drawString("Anti-Person: ", x + 5, y + 45, 0x00000000); tempString = String.format("x%.0f", gun.damageVsLiving); fr.drawString(tempString, x + 85 - fr.getStringWidth(tempString), y + 45, 0x00000000); } } fr.drawString("Cost", x + 5, y + 55, 0x00000000); int numParts = entry.requiredParts.size(); int numPartsOnLine1 = Math.min(numParts, 4); int numPartsOnLine2 = numParts > 4 ? Math.min(numParts - 4, 4) : 0; for(int i = 0; i < numPartsOnLine1; i++) { drawSlotInventory(entry.requiredParts.get(i), x + 6 + 20 * i, y + 65); } //for(int i = 0; i < numPartsOnLine2; i++) //{ // drawSlotInventory(entry.requiredParts.get(i + 4), x + 6 + 20 * i, y + 65); //} } private void drawSlotInventory(ItemStack itemstack, int i, int j) { if(itemstack == null || itemstack.isEmpty()) return; RenderHelper.enableGUIStandardItemLighting(); itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int m = i - guiOriginX; int n = j - guiOriginY; if(k == 0 || k == 1) { if(currentPage != null) { for(int e = 0; e < 5; e++) { if(e < currentPage.entries.size() && 105 < m && m < 123 && 57 + e * 22 < n && n < 76 + e * 22) { currentEntry = currentPage.entries.get(e); currentSubEntry = currentEntry.childEntries.size() > 0 ? currentEntry.childEntries.get(0) : null; } } } if(currentEntry != null) { for(int e = 0; e < 5; e++) { if(e < currentEntry.childEntries.size() && 133 < m && m < 151 && 57 + e * 22 < n && n < 76 + e * 22) { currentSubEntry = currentEntry.childEntries.get(e); } } } } } @Override protected void keyTyped(char c, int i) { if(i == 1 || i == mc.gameSettings.keyBindInventory.getKeyCode()) { mc.player.closeScreen(); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiGunModTable.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import java.util.Random; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.client.ClientProxy; import com.flansmod.client.model.CustomItemRenderType; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.ContainerGunModTable; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.network.PacketGunPaint; public class GuiGunModTable extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/gunTable.png"); private static final Random rand = new Random(); private Paintjob hoveringOver = null; private int mouseX, mouseY; private InventoryPlayer inventory; public GuiGunModTable(InventoryPlayer inv, World w) { super(new ContainerGunModTable(inv, w)); inventory = inv; ySize = 256; } @Override protected void drawGuiContainerForegroundLayer(int x, int y) { fontRenderer.drawString("Inventory", 8, (ySize - 94) + 2, 0x404040); fontRenderer.drawString("Gun Modification Table", 8, 6, 0x404040); ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof ItemGun) { ItemStack tempStack = gunStack.copy(); if(hoveringOver != null) tempStack.setItemDamage(hoveringOver.ID); GunType gunType = ((ItemGun)gunStack.getItem()).GetType(); if(gunType.model != null) { GlStateManager.pushMatrix(); GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.disableLighting(); GlStateManager.pushMatrix(); GlStateManager.rotate(180F, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(0F, 0.0F, 1.0F, 0.0F); RenderHelper.enableStandardItemLighting(); GlStateManager.popMatrix(); GlStateManager.enableRescaleNormal(); GlStateManager.translate(80, 48, 100); GlStateManager.rotate(160, 1F, 0F, 0F); GlStateManager.rotate(20, 0F, 1F, 0F); GlStateManager.scale(-50F, 50F, 50F); //ClientProxy.gunRenderer.renderGun(gunStack, gunType, 1F / 16F, gunType.model, GunAnimations.defaults, 0F); ClientProxy.gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, tempStack); GlStateManager.popMatrix(); } } } @Override protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); mc.renderEngine.bindTexture(texture); int xOrigin = (width - xSize) / 2; int yOrigin = (height - ySize) / 2; drawTexturedModalRect(xOrigin, yOrigin, 0, 0, xSize, ySize); for(int z = 1; z < 13; z++) inventorySlots.getSlot(z).yPos = -1000; ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)gunStack.getItem()).GetType(); if(gunType.allowBarrelAttachments) { drawTexturedModalRect(xOrigin + 51, yOrigin + 107, 176, 122, 22, 22); inventorySlots.getSlot(1).yPos = 110; } if(gunType.allowScopeAttachments) { drawTexturedModalRect(xOrigin + 77, yOrigin + 81, 202, 96, 22, 22); inventorySlots.getSlot(2).yPos = 84; } if(gunType.allowStockAttachments) { drawTexturedModalRect(xOrigin + 103, yOrigin + 107, 228, 122, 22, 22); inventorySlots.getSlot(3).yPos = 110; } if(gunType.allowGripAttachments) { drawTexturedModalRect(xOrigin + 77, yOrigin + 133, 202, 148, 22, 22); inventorySlots.getSlot(4).yPos = 136; } for(int x = 0; x < 2; x++) { for(int y = 0; y < 4; y++) { if(x + y * 2 < gunType.numGenericAttachmentSlots) inventorySlots.getSlot(5 + x + y * 2).yPos = 83 + 18 * y; } } //Render generic slot backgrounds for(int x = 0; x < 2; x++) { for(int y = 0; y < 4; y++) { if(x + y * 2 < gunType.numGenericAttachmentSlots) drawTexturedModalRect(xOrigin + 9 + 18 * x, yOrigin + 82 + 18 * y, 178, 54, 18, 18); } } int numPaintjobs = gunType.paintjobs.size(); int numRows = numPaintjobs / 2 + 1; for(int y = 0; y < numRows; y++) { for(int x = 0; x < 2; x++) { //If this row has only one paintjob, don't try and render the second one if(2 * y + x >= numPaintjobs) continue; drawTexturedModalRect(xOrigin + 131 + 18 * x, yOrigin + 82 + 18 * y, 178, 54, 18, 18); } } for(int y = 0; y < numRows; y++) { for(int x = 0; x < 2; x++) { //If this row has only one paintjob, don't try and render the second one if(2 * y + x >= numPaintjobs) continue; Paintjob paintjob = gunType.paintjobs.get(2 * y + x); ItemStack stack = gunStack.copy(); //stack.getTagCompound().setString("Paint", paintjob.iconName); stack.setItemDamage(paintjob.ID); itemRender.renderItemIntoGUI(stack, xOrigin + 132 + x * 18, yOrigin + 83 + y * 18); } } } //Draw hover box for paintjob if(hoveringOver != null) { int numDyes = hoveringOver.dyesNeeded.length; //Only draw box if there are dyes needed if(numDyes != 0 && !inventory.player.capabilities.isCreativeMode) { //Calculate which dyes we have in our inventory boolean[] haveDyes = new boolean[numDyes]; for(int n = 0; n < numDyes; n++) { int amountNeeded = hoveringOver.dyesNeeded[n].getCount(); for(int s = 0; s < inventory.getSizeInventory(); s++) { ItemStack stack = inventory.getStackInSlot(s); if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == hoveringOver.dyesNeeded[n].getItemDamage()) { amountNeeded -= stack.getCount(); } } if(amountNeeded <= 0) haveDyes[n] = true; } GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.disableLighting(); mc.renderEngine.bindTexture(texture); int originX = mouseX + 6; int originY = mouseY - 20; //If we have only one, use the double ended slot if(numDyes == 1) { drawTexturedModalRect(originX, originY, (haveDyes[0] ? 201 : 178), 218, 22, 22); } else { //First slot drawTexturedModalRect(originX, originY, 178, (haveDyes[0] ? 195 : 172), 20, 22); //Middle slots for(int s = 1; s < numDyes - 1; s++) { drawTexturedModalRect(originX + 2 + 18 * s, originY, 199, (haveDyes[s] ? 195 : 172), 18, 22); } //Last slot drawTexturedModalRect(originX + 2 + 18 * (numDyes - 1), originY, 218, (haveDyes[numDyes - 1] ? 195 : 172), 20, 22); } for(int s = 0; s < numDyes; s++) { itemRender.renderItemIntoGUI(hoveringOver.dyesNeeded[s], originX + 3 + s * 18, originY + 3); itemRender.renderItemOverlayIntoGUI(this.fontRenderer, hoveringOver.dyesNeeded[s], originX + 3 + s * 18, originY + 3, null); } } } } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } @Override public void handleMouseInput() throws IOException { super.handleMouseInput(); mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; int mouseXInGUI = mouseX - guiLeft; int mouseYInGUI = mouseY - guiTop; hoveringOver = null; ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)gunStack.getItem()).GetType(); int numPaintjobs = gunType.paintjobs.size(); int numRows = numPaintjobs / 2 + 1; for(int j = 0; j < numRows; j++) { for(int i = 0; i < 2; i++) { if(2 * j + i >= numPaintjobs) continue; Paintjob paintjob = gunType.paintjobs.get(2 * j + i); ItemStack stack = gunStack.copy(); stack.getTagCompound().setString("Paint", paintjob.iconName); int slotX = 131 + i * 18; int slotY = 82 + j * 18; if(mouseXInGUI >= slotX && mouseXInGUI < slotX + 18 && mouseYInGUI >= slotY && mouseYInGUI < slotY + 18) hoveringOver = paintjob; } } } } @Override protected void mouseClicked(int x, int y, int button) throws IOException { super.mouseClicked(x, y, button); if(button != 0) return; if(hoveringOver == null) return; FlansMod.getPacketHandler().sendToServer(new PacketGunPaint(hoveringOver.ID)); ((ContainerGunModTable)inventorySlots).clickPaintjob(hoveringOver.ID); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiMechaInventory.java ================================================ package com.flansmod.client.gui; import java.io.IOException; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.model.RenderMecha; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.mechas.ContainerMechaInventory; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.MechaType; public class GuiMechaInventory extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/mechaInventory.png"); private static final RenderMecha mechaRenderer; static { mechaRenderer = new RenderMecha(Minecraft.getMinecraft().getRenderManager()); } public ContainerMechaInventory container; public InventoryPlayer inventory; public World world; public int scroll; public int numItems; public int maxScroll; public EntityMecha mecha; private int anim = 0; private long lastTime; public GuiMechaInventory(InventoryPlayer inventoryplayer, World world1, EntityMecha entMecha) { super(new ContainerMechaInventory(inventoryplayer, world1, entMecha)); mecha = entMecha; inventory = inventoryplayer; world = world1; container = (ContainerMechaInventory)inventorySlots; ySize = 180; xSize = 350; maxScroll = container.maxScroll; numItems = container.numItems; } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } @Override protected void drawGuiContainerForegroundLayer(int x, int y) { fontRenderer.drawString(mecha.getMechaType().name, 9, 9, 0x404040); fontRenderer.drawString("Inventory", 181, (ySize - 96) + 2, 0x404040); } @Override protected void drawGuiContainerBackgroundLayer(float f, int i1, int j1) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); mc.renderEngine.bindTexture(texture); int j = (width - xSize) / 2; int k = (height - ySize) / 2; drawTexturedModalRect(j, k, 0, 0, xSize, ySize); int numRows = ((numItems + 7) / 8); for(int row = 0; row < (numRows > 3 ? 3 : numRows); row++) { drawTexturedModalRect(j + 185, k + 24 + 19 * row, 181, 97, 18 * ((row + scroll + 1) * 8 <= numItems ? 8 : numItems % 8), 18); } if(scroll == 0) drawTexturedModalRect(j + 336, k + 41, 350, 0, 10, 10); if(scroll == maxScroll) drawTexturedModalRect(j + 336, k + 53, 350, 10, 10, 10); long newTime = mc.world.getWorldInfo().getWorldTime(); if(newTime > lastTime) { lastTime = newTime; if(newTime % 5 == 0) anim++; } int fuelTankSize = mecha.getMechaType().fuelTankSize; float fuelInTank = mecha.driveableData.fuelInTank; if(fuelInTank < fuelTankSize / 8 && (anim % 4) > 1) drawTexturedModalRect(width / 2 - 14, height / 2 - 59, 360, 0, 6, 6); if(fuelInTank > 0) drawTexturedModalRect(width / 2 - 18, height / 2 + 45 - (int)((94 * fuelInTank) / fuelTankSize), 350, 20, 15, (int)((94 * fuelInTank) / fuelTankSize)); MechaType type = mecha.getMechaType(); //Render rotating mecha model GlStateManager.pushMatrix(); GlStateManager.enableDepth(); GlStateManager.enableLighting(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.translate(j + 92, k + 105, 100); GlStateManager.scale(-50F / type.cameraDistance, 50F / type.cameraDistance, 50F / type.cameraDistance); GlStateManager.rotate(180F, 0F, 0F, 1F); GlStateManager.rotate(30F, 1F, 0F, 0F); GlStateManager.rotate(FlansMod.ticker, 0F, 1F, 0F); mc.renderEngine.bindTexture(FlansModResourceHandler.getTexture(type)); mechaRenderer.doRender(mecha, 0, 0, 0, 0F, 0F); //type.model.render(type); GlStateManager.disableLighting(); GlStateManager.disableDepth(); GlStateManager.popMatrix(); } @Override public void drawTexturedModalRect(int par1, int par2, int par3, int par4, int par5, int par6) { float f = 1F / 512F; float f1 = 1F / 256F; WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV((double)(par1), (double)(par2 + par6), (double)this.zLevel, (double)((float)(par3) * f), (double)((float)(par4 + par6) * f1)); worldrenderer.addVertexWithUV((double)(par1 + par5), (double)(par2 + par6), (double)this.zLevel, (double)((float)(par3 + par5) * f), (double)((float)(par4 + par6) * f1)); worldrenderer.addVertexWithUV((double)(par1 + par5), (double)(par2), (double)this.zLevel, (double)((float)(par3 + par5) * f), (double)((float)(par4) * f1)); worldrenderer.addVertexWithUV((double)(par1), (double)(par2), (double)this.zLevel, (double)((float)(par3) * f), (double)((float)(par4) * f1)); worldrenderer.draw(); } @Override public void initGui() { super.initGui(); buttonList.add(new GuiButton(0, width / 2 - 166, height / 2 + 63, 93, 20, "Passenger Guns")); buttonList.add(new GuiButton(1, width / 2 - 68, height / 2 + 63, 68, 20, "Repair")); } @Override protected void actionPerformed(GuiButton button) { if(button.id == 0) { inventory.player.openGui(FlansMod.INSTANCE, 6, world, mecha.chunkCoordX, mecha.chunkCoordY, mecha.chunkCoordZ); } if(button.id == 1) { inventory.player.openGui(FlansMod.INSTANCE, 1, world, mecha.chunkCoordX, mecha.chunkCoordY, mecha.chunkCoordZ); } } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int m = i - (width - xSize) / 2; int n = j - (height - ySize) / 2; if(scroll > 0 && m > 336 && m < 346 && n > 41 && n < 51) { scroll--; container.updateScroll(scroll); } if(scroll < maxScroll && m > 336 & m < 346 && n > 53 && n < 63) { scroll++; container.updateScroll(scroll); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/GuiPaintjobTable.java ================================================ package com.flansmod.client.gui; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Random; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.texture.DynamicTexture; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import com.flansmod.client.ClientProxy; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.model.CustomItemRenderType; import com.flansmod.client.model.ModelAttachment; import com.flansmod.client.model.ModelDriveable; import com.flansmod.client.model.RenderGun; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.network.PacketGunPaint; import com.flansmod.common.paintjob.ContainerPaintjobTable; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.paintjob.TileEntityPaintjobTable; import com.flansmod.common.types.EnumType; import com.flansmod.common.vector.Vector3f; public class GuiPaintjobTable extends GuiContainer { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/paintjobTable.png"); private static final Random rand = new Random(); private static final int paletteSizeX = 18; private static final int paletteSizeY = 4; private static final float componentBarLength = 68.0f; private Paintjob hoveringOver = null; private int mouseX, mouseY; private InventoryPlayer inventory; private boolean inCustomMode; private float customModeTransitionTimer = 0.0f; private float transitionSpeed = 0.9f; private int prevMainPageX; private RotatedAxes modelAxes = new RotatedAxes(); private RotatedAxes prevModelAxes = new RotatedAxes(); private static int[][] paletteColours = new int[paletteSizeX][paletteSizeY]; private static int[] baseColours = new int[]{0x000000, 0xffffff, 0xff0000, 0xff5500, 0xffaa00, 0xffff00, 0xaaff00, 0x55ff00, 0x00ff00, 0x00ff55, 0x00ffaa, 0x00ffff, 0x00aaff, 0x0055ff, 0x0000ff, 0x5500ff, 0xaa00ff, 0xff00ff}; private static int currentColour; private static int flatTextureWindowX = 300, flatTextureWindowY = 100; private static boolean movingFlatTextureWindow = false; //private static final int BYTES_PER_PIXEL = 4; //private static int textureID = -1; //private static BufferedImage currentTexture; private static DynamicTexture dynamicTexture; private static int dynamicTextureX, dynamicTextureY; static { ResetPalette(); } private static void ResetPalette() { for(int x = 0; x < paletteSizeX; x++) { for(int y = 0; y < paletteSizeY; y++) { int red = (baseColours[x] >> 16) & 0xff; int green = (baseColours[x] >> 8) & 0xff; int blue = (baseColours[x] >> 0) & 0xff; if(x == 0) { red = green = blue = 0xff * y / 7; } else if(x == 1) { red = green = blue = 0xff * (y + 4) / 7; } else { if(y == 3) { red /= 2; green /= 2; blue /= 2; } if(y == 1) { red = 0xff - (0xff - red) / 2; green = 0xff - (0xff - green) / 2; blue = 0xff - (0xff - blue) / 2; } if(y == 0) { red = 0xff - (0xff - red) / 4; green = 0xff - (0xff - green) / 4; blue = 0xff - (0xff - blue) / 4; } } paletteColours[x][y] = (red << 16) + (green << 8) + blue; } } } public GuiPaintjobTable(InventoryPlayer inv, World w, TileEntityPaintjobTable te) { super(new ContainerPaintjobTable(inv, w, te)); inventory = inv; xSize = 224; ySize = 264; } @Override public void updateScreen() { super.updateScreen(); prevModelAxes = modelAxes.clone(); if(inCustomMode) { customModeTransitionTimer = 1.0f - ((1.0f - customModeTransitionTimer) * transitionSpeed); } else { customModeTransitionTimer *= transitionSpeed; modelAxes.rotateLocalYaw(2.5f); } int xPos = GetMainPageX(); int dPos = xPos - prevMainPageX; for(int i = 0; i < 4 * 9 + 2; i++) { inventorySlots.getSlot(i).xPos += dPos; } if(movingFlatTextureWindow) { flatTextureWindowX = Mouse.getEventX() * this.width / this.mc.displayWidth - guiLeft; flatTextureWindowY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1 - guiTop; } prevMainPageX = xPos; } private int GetMainPageX() { return (int)(-500.0f * customModeTransitionTimer); } private int GetMainPageY() { return 0; } private int GetCustomPageX() { return (int)(500.0f * (1.0f - customModeTransitionTimer)); } private int GetCustomPageY() { return 0; } private int GetFlatTextureWindowX() { return GetCustomPageX() + flatTextureWindowX; } private int GetFlatTextureWindowY() { return GetCustomPageY() + flatTextureWindowY; } private Vector3f GetRenderOrigin() { return new Vector3f(100.0f, 64.0f, 100.0f); } @Override protected void drawGuiContainerForegroundLayer(int x, int y) { // Render main screen if(customModeTransitionTimer <= 0.999f) { //int xOrigin = ((width - xSize) / 2) + GetMainPageX(); //int yOrigin = ((height - ySize) / 2) + GetMainPageY(); fontRenderer.drawString("Inventory", GetMainPageX() + 8, GetMainPageY() + (ySize - 94) + 2, 0x404040); fontRenderer.drawString("Paintjob Table", GetMainPageX() + 8, GetMainPageY() + 6, 0x404040); } // Render custom screen if(customModeTransitionTimer >= 0.001f) { int xOrigin = ((width - xSize) / 2) + GetCustomPageX() - 32; int yOrigin = ((height - ySize) / 2) + GetCustomPageY(); fontRenderer.drawString("Confirm", xOrigin - 7, yOrigin + 169, 0x000000); fontRenderer.drawString("Cancel", xOrigin - 6, yOrigin + 186, 0x000000); fontRenderer.drawString("Inventory", xOrigin - 12, yOrigin + 203, 0x000000); } Vector3f renderOrigin = GetRenderOrigin(); ItemStack paintableStack = inventorySlots.getSlot(0).getStack(); if(paintableStack != null && paintableStack.getItem() instanceof IPaintableItem) { ItemStack tempStack = paintableStack.copy(); if(hoveringOver != null) tempStack.setItemDamage(hoveringOver.ID); PaintableType paintableType = ((IPaintableItem)paintableStack.getItem()).GetPaintableType(); EnumType eType = EnumType.getFromObject(paintableType); if(paintableType.GetModel() != null) { GlStateManager.pushMatrix(); GlStateManager.color(1F, 1F, 1F, 1F); //GlStateManager.loadIdentity(); // Setup lighting GlStateManager.disableLighting(); GlStateManager.pushMatrix(); GlStateManager.rotate(180F, 1.0F, 0.0F, 0.0F); RenderHelper.enableStandardItemLighting(); GlStateManager.popMatrix(); GlStateManager.enableRescaleNormal(); //GlStateManager.translate(10f, 10f, -10f); //GlStateManager.scale(100f, 100f, 100f); GlStateManager.translate(renderOrigin.x, renderOrigin.y, renderOrigin.z); GlStateManager.rotate(180, 1F, 0F, 0F); //GlStateManager.rotate(20, 0F, 1F, 0F); float scale = paintableType.GetRecommendedScale(); GlStateManager.scale(-scale, scale, scale); float dYaw = (modelAxes.getYaw() - prevModelAxes.getYaw()); while(dYaw > 180.0f) dYaw -= 360.0f; while(dYaw < -180.0f) dYaw += 360.0f; //GlStateManager.rotate(prevModelAxes.getYaw() + dYaw * RenderGun.smoothing, 0.0F, 1.0F, 0.0F); Paintjob paintjob = paintableType.paintjobs.get(tempStack.getItemDamage()); if(inCustomMode) { bindWorkingTexture(); } switch(eType) { case gun: { if(inCustomMode) RenderGun.bindTextures = false; ClientProxy.gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, tempStack); RenderGun.bindTextures = true; break; } case attachment: { if(!inCustomMode) mc.renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(paintjob)); ((ModelAttachment)paintableType.GetModel()).renderAttachment(0.0625f); break; } case plane: case vehicle: case mecha: { if(!inCustomMode) mc.renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(paintjob)); ((ModelDriveable)paintableType.GetModel()).render((DriveableType)paintableType); break; } default: break; } GlStateManager.popMatrix(); } } } @Override protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableDepth(); mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; // Render main screen if(customModeTransitionTimer <= 0.999f) { int xOrigin = ((width - xSize) / 2) + GetMainPageX(); int yOrigin = ((height - ySize) / 2) + GetMainPageY(); // Gun render box drawModalRectWithCustomSizedTexture(xOrigin, yOrigin, 0, 0, xSize, 114, textureX, textureY); // Inventory box drawModalRectWithCustomSizedTexture(xOrigin, yOrigin + 122, 0, 114, xSize, 142, textureX, textureY); ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof IPaintableItem) { PaintableType gunType = ((IPaintableItem)gunStack.getItem()).GetPaintableType(); int numPaintjobs = gunType.paintjobs.size(); int numRows = numPaintjobs / 9 + 1; for(int y = 0; y < numRows; y++) { for(int x = 0; x < 9; x++) { // Only render up to the number of paintjobs in the row if(9 * y + x >= numPaintjobs) continue; Paintjob paintjob = gunType.paintjobs.get(9 * y + x); ItemStack stack = gunStack.copy(); stack.setItemDamage(paintjob.ID); itemRender.renderItemIntoGUI(stack, xOrigin + 8 + x * 18, yOrigin + 130 + y * 18); } } } //Draw hover box for paintjob if(hoveringOver != null) { int numDyes = hoveringOver.dyesNeeded.length; //Only draw box if there are dyes needed if(numDyes != 0 && !inventory.player.capabilities.isCreativeMode) { //Calculate which dyes we have in our inventory boolean[] haveDyes = new boolean[numDyes]; for(int n = 0; n < numDyes; n++) { int amountNeeded = hoveringOver.dyesNeeded[n].getCount(); for(int s = 0; s < inventory.getSizeInventory(); s++) { ItemStack stack = inventory.getStackInSlot(s); if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == hoveringOver.dyesNeeded[n].getItemDamage()) { amountNeeded -= stack.getCount(); } } if(amountNeeded <= 0) haveDyes[n] = true; } GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.disableLighting(); mc.renderEngine.bindTexture(texture); int originX = mouseX + 6; int originY = mouseY - 20; //If we have only one, use the double ended slot if(numDyes == 1) { drawModalRectWithCustomSizedTexture(originX, originY, (haveDyes[0] ? 379 : 356), 0, 22, 22, textureX, textureY); } else { //First slot drawModalRectWithCustomSizedTexture(originX, originY, 256, (haveDyes[0] ? 23 : 0), 20, 22, textureX, textureY); //Middle slots for(int s = 1; s < numDyes - 1; s++) { drawModalRectWithCustomSizedTexture(originX + 2 + 18 * s, originY, 277, (haveDyes[s] ? 23 : 0), 18, 22, textureX, textureY); } //Last slot drawModalRectWithCustomSizedTexture(originX + 2 + 18 * (numDyes - 1), originY, 296, (haveDyes[numDyes - 1] ? 23 : 0), 20, 22, textureX, textureY); } for(int s = 0; s < numDyes; s++) { itemRender.renderItemIntoGUI(hoveringOver.dyesNeeded[s], originX + 3 + s * 18, originY + 3); itemRender.renderItemOverlayIntoGUI(this.fontRenderer, hoveringOver.dyesNeeded[s], originX + 3 + s * 18, originY + 3, null); } } } } // Render custom paintjob screen if(customModeTransitionTimer >= 0.001f) { mc.renderEngine.bindTexture(texture); int xOrigin = ((width - xSize) / 2) + GetCustomPageX() - 32; int yOrigin = ((height - ySize) / 2) + GetCustomPageY(); // Palette drawModalRectWithCustomSizedTexture(xOrigin, yOrigin + 200, 224, 206, 288, 50, textureX, textureY); GlStateManager.disableTexture2D(); for(int x = 0; x < paletteSizeX; x++) { for(int y = 0; y < paletteSizeY; y++) { int colour = paletteColours[x][y]; float scale = 1.0f / 256.0f; GlStateManager.color(scale * ((colour >> 16) & 0xff), scale * ((colour >> 8) & 0xff), scale * ((colour >> 0) & 0xff)); drawModalRectWithCustomSizedTexture(xOrigin + 8 + 9 * x, yOrigin + 200 + 8 + 9 * y, 0, 0, 7, 7, textureX, textureY); } } float scale = 1.0f / 256.0f; float red = scale * ((currentColour >> 16) & 0xff); float green = scale * ((currentColour >> 8) & 0xff); float blue = scale * ((currentColour >> 0) & 0xff); GlStateManager.color(red, green, blue); drawModalRectWithCustomSizedTexture(xOrigin + 172, yOrigin + 208, 0, 0, 34, 34, textureX, textureY); // Slider bars for(int n = 0; n < componentBarLength; n++) { GlStateManager.color((float)n / componentBarLength, green, blue); drawModalRectWithCustomSizedTexture(xOrigin + 212 + n, yOrigin + 208, 0, 0, 1, 10, textureX, textureY); } for(int n = 0; n < componentBarLength; n++) { GlStateManager.color(red, (float)n / componentBarLength, blue); drawModalRectWithCustomSizedTexture(xOrigin + 212 + n, yOrigin + 220, 0, 0, 1, 10, textureX, textureY); } for(int n = 0; n < componentBarLength; n++) { GlStateManager.color(red, green, (float)n / componentBarLength); drawModalRectWithCustomSizedTexture(xOrigin + 212 + n, yOrigin + 232, 0, 0, 1, 10, textureX, textureY); } GlStateManager.enableTexture2D(); GlStateManager.color(1.0f, 1.0f, 1.0f); // Sliders drawModalRectWithCustomSizedTexture(xOrigin + 212 + (int)(red * componentBarLength), yOrigin + 207, 317, 21, 3, 12, textureX, textureY); drawModalRectWithCustomSizedTexture(xOrigin + 212 + (int)(green * componentBarLength), yOrigin + 219, 317, 21, 3, 12, textureX, textureY); drawModalRectWithCustomSizedTexture(xOrigin + 212 + (int)(blue * componentBarLength), yOrigin + 231, 317, 21, 3, 12, textureX, textureY); for(int n = 0; n < 3; n++) { drawModalRectWithCustomSizedTexture(xOrigin + 290, yOrigin + 200 + 17 * n, 401, 0, 78, 16, textureX, textureY); } int xFlatOrigin = GetFlatTextureWindowX(); int yFlatOrigin = GetFlatTextureWindowY(); if(dynamicTextureX == dynamicTextureY || true)// Default to this case. Just lose some texture { drawModalRectWithCustomSizedTexture(xFlatOrigin, yFlatOrigin, 242, 54, 64 + 7, 152, textureX, textureY); drawModalRectWithCustomSizedTexture(xFlatOrigin + 64 + 7, yFlatOrigin, 242 + 270 - 64 - 7, 54, 64 + 7, 152, textureX, textureY); bindWorkingTexture(); drawModalRectWithCustomSizedTexture(xFlatOrigin + 7, yFlatOrigin + 17, 0, 0, 128, 128, dynamicTextureX, dynamicTextureY); } //else if(dynamicTextureX == 2 * dynamicTextureY) //{ // drawModalRectWithCustomSizedTexture(xFlatOrigin, yFlatOrigin, 242, 54, 270, 152, textureX, textureY); // // bindWorkingTexture(); // // drawModalRectWithCustomSizedTexture(xFlatOrigin + 7, yFlatOrigin + 17, 0, 0, 256, 128, dynamicTextureX, dynamicTextureY); //} } GlStateManager.enableDepth(); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } public static void copyImageToTexture() { dynamicTexture.updateDynamicTexture(); } public void bindWorkingTexture() { mc.getTextureManager().bindTexture(mc.getTextureManager().getDynamicTextureLocation("customPaintjob", dynamicTexture)); } private void SetCustomMode(boolean active) { if(active) { if(dynamicTexture == null) { copyTextureFromGunToCustomTexture(); } } else { } inCustomMode = active; } private void copyTextureFromGunToCustomTexture() { ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof IPaintableItem) { PaintableType paintableType = ((IPaintableItem)gunStack.getItem()).GetPaintableType(); Paintjob paintjob = paintableType.getPaintjob(gunStack.getItemDamage()); try { String imageLocation = "Flan/" + paintableType.contentPack + "/assets/flansmod/skins/" + paintjob.textureName + ".png"; BufferedImage bufferedImage = ImageIO.read(new File(imageLocation)); dynamicTexture = new DynamicTexture(bufferedImage); dynamicTextureX = bufferedImage.getWidth(); dynamicTextureY = bufferedImage.getHeight(); } catch(IOException e) { FlansMod.log.throwing(e); } copyImageToTexture(); } } @Override public void handleInput() throws IOException { super.handleInput(); if(inCustomMode) { mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; int mouseXInGUI = mouseX - guiLeft; int mouseYInGUI = mouseY - guiTop; int flatTexOriginX = GetFlatTextureWindowX(); int flatTexOriginY = GetFlatTextureWindowY(); if(Mouse.isButtonDown(0)) { int pixelX = mouseXInGUI + 64 - (flatTexOriginX + 7) - 4; int pixelY = mouseYInGUI - (flatTexOriginY + 17) + 5; if(pixelX >= 0 && pixelX < 128 && pixelY >= 0 && pixelY < 128) { for(int i = -2; i < 2; i++) { for(int j = -2; j < 2; j++) { if((i == -2 || i == 2) && (j == -2 || j == 2)) { continue; } int px = Math.min(Math.max(0, pixelX + i), dynamicTextureX - 1); int py = Math.min(Math.max(0, pixelY + j), dynamicTextureY - 1); dynamicTexture.getTextureData()[px + py * dynamicTextureX] = 0xff000000 + currentColour; copyImageToTexture(); } } } } if(mouseXInGUI >= flatTexOriginX - 64 + 7 && mouseXInGUI <= flatTexOriginX + 64 + 14 && mouseYInGUI >= flatTexOriginY - 4 && mouseYInGUI <= flatTexOriginY + 6) { movingFlatTextureWindow = Mouse.isButtonDown(0); } } } @Override public void handleMouseInput() throws IOException { super.handleMouseInput(); if(Mouse.getEventButton() == 2 && Mouse.getEventButtonState()) { SetCustomMode(!inCustomMode); } mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; int mouseXInGUI = mouseX - guiLeft; int mouseYInGUI = mouseY - guiTop; hoveringOver = null; if(inCustomMode) { int xOrigin = GetCustomPageX() - 32; int yOrigin = GetCustomPageY(); for(int x = 0; x < paletteSizeX; x++) { for(int y = 0; y < paletteSizeY; y++) { if(mouseXInGUI >= xOrigin + 8 + 9 * x && mouseXInGUI < xOrigin + 15 + 9 * x && mouseYInGUI >= yOrigin + 208 + 9 * y && mouseYInGUI < yOrigin + 215 + 9 * y) { switch(Mouse.getEventButton()) { case 0: // Left click. Pick colour { currentColour = paletteColours[x][y]; break; } case 1: // Right click. Set colour from custom { paletteColours[x][y] = currentColour; break; } } } } } if(Mouse.getEventButton() == 0 && Mouse.getEventButtonState()) { if(mouseXInGUI >= xOrigin + 212 && mouseXInGUI < xOrigin + 212 + componentBarLength && mouseYInGUI >= yOrigin + 208 && mouseYInGUI < yOrigin + 218) { int red = (int)(((mouseXInGUI - (xOrigin + 212)) * 0xff) / componentBarLength); currentColour &= 0x00ffff; // Clear red component currentColour |= (red << 16); } if(mouseXInGUI >= xOrigin + 212 && mouseXInGUI < xOrigin + 212 + componentBarLength && mouseYInGUI >= yOrigin + 220 && mouseYInGUI < yOrigin + 230) { int green = (int)(((mouseXInGUI - (xOrigin + 212)) * 0xff) / componentBarLength); currentColour &= 0xff00ff; // Clear green component currentColour |= (green << 8); } if(mouseXInGUI >= xOrigin + 212 && mouseXInGUI < xOrigin + 212 + componentBarLength && mouseYInGUI >= yOrigin + 232 && mouseYInGUI < yOrigin + 242) { int blue = (int)(((mouseXInGUI - (xOrigin + 212)) * 0xff) / componentBarLength); currentColour &= 0xffff00; // Clear blue component currentColour |= (blue << 0); } } } else { ItemStack gunStack = inventorySlots.getSlot(0).getStack(); if(gunStack != null && gunStack.getItem() instanceof IPaintableItem) { PaintableType paintableType = ((IPaintableItem)gunStack.getItem()).GetPaintableType(); int numPaintjobs = paintableType.paintjobs.size(); int numRows = numPaintjobs / 9 + 1; for(int j = 0; j < numRows; j++) { for(int i = 0; i < 9; i++) { if(9 * j + i >= numPaintjobs) continue; Paintjob paintjob = paintableType.paintjobs.get(9 * j + i); ItemStack stack = gunStack.copy(); stack.getTagCompound().setString("Paint", paintjob.iconName); int slotX = 7 + i * 18; int slotY = 129 + j * 18; if(mouseXInGUI >= slotX && mouseXInGUI < slotX + 18 && mouseYInGUI >= slotY && mouseYInGUI < slotY + 18) hoveringOver = paintjob; } } } } } @Override protected void mouseClicked(int x, int y, int button) throws IOException { super.mouseClicked(x, y, button); if(button != 0) return; if(hoveringOver == null) return; FlansMod.getPacketHandler().sendToServer(new PacketGunPaint(hoveringOver.ID)); ((ContainerPaintjobTable)inventorySlots).clickPaintjob(hoveringOver.ID); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/config/ModGuiConfig.java ================================================ package com.flansmod.client.gui.config; import net.minecraft.client.gui.GuiScreen; import net.minecraftforge.common.config.ConfigElement; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.fml.client.config.GuiConfig; import com.flansmod.common.FlansMod; public class ModGuiConfig extends GuiConfig { public ModGuiConfig(GuiScreen parent) { super(parent, new ConfigElement(FlansMod.configFile.getCategory(Configuration.CATEGORY_GENERAL)).getChildElements(), FlansMod.MODID, false, false, GuiConfig.getAbridgedConfigPath(FlansMod.configFile.toString())); } } ================================================ FILE: src/main/java/com/flansmod/client/gui/config/ModGuiFactory.java ================================================ package com.flansmod.client.gui.config; import java.util.Set; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraftforge.fml.client.IModGuiFactory; public class ModGuiFactory implements IModGuiFactory { @Override public void initialize(Minecraft minecraftInstance) { } @Override public Set runtimeGuiCategories() { return null; } @Override public boolean hasConfigGui() { return false; } @Override public GuiScreen createConfigGui(GuiScreen parentScreen) { return null; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/EnumLoadoutSlot.java ================================================ package com.flansmod.client.gui.teams; public enum EnumLoadoutSlot { primary("Primary", true), secondary("Secondary", true), special("Special", false), melee("Melee", false), armour("Armour", false); EnumLoadoutSlot(String s, boolean b) { name = s; isWeapon = b; } public boolean isWeapon; public String name; } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiBaseEditor.java ================================================ package com.flansmod.client.gui.teams; import java.io.IOException; import java.util.Arrays; import org.lwjgl.input.Keyboard; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; import com.flansmod.common.FlansMod; import com.flansmod.common.network.PacketBaseEdit; public class GuiBaseEditor extends GuiScreen { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/baseEdit.png"); private int guiOriginX; private int guiOriginY; private GuiTextField nameEntryField; private GuiButton[] teamButtons; private GuiButton[] mapButtons; private GuiButton leftButton; private GuiButton rightButton; private int mapsPage; /** * The packet received from the server containing all the base information. Modify this and send it back */ public PacketBaseEdit packet; public GuiBaseEditor(PacketBaseEdit packet) { this.packet = packet; } public void initGui() { super.initGui(); this.buttonList.clear(); //Setup the text entry field Keyboard.enableRepeatEvents(true); nameEntryField = new GuiTextField(0, this.fontRenderer, width / 2 - 128 + 70, height / 2 - 94 + 24, 179, fontRenderer.FONT_HEIGHT); nameEntryField.setMaxStringLength(60); nameEntryField.setEnableBackgroundDrawing(true); nameEntryField.setVisible(true); nameEntryField.setFocused(true); nameEntryField.setTextColor(16777215); nameEntryField.setText(packet.baseName); //Add buttons teamButtons = new GuiButton[4]; teamButtons[0] = new GuiButton(0, width / 2 - 128 + 6, height / 2 - 94 + 38, 58, 20, "No Team"); teamButtons[1] = new GuiButton(1, width / 2 - 128 + 68, height / 2 - 94 + 38, 58, 20, "Spectator"); teamButtons[2] = new GuiButton(2, width / 2 - 128 + 130, height / 2 - 94 + 38, 58, 20, "Team 1"); teamButtons[3] = new GuiButton(3, width / 2 - 128 + 192, height / 2 - 94 + 38, 58, 20, "Team 2"); buttonList.addAll(Arrays.asList(teamButtons).subList(0, 4)); mapButtons = new GuiButton[5]; for(int i = 0; i < 5; i++) { mapButtons[i] = new GuiButton(4 + i, width / 2 - 128 + 28, height / 2 - 94 + 75 + 22 * i, 200, 20, "Map " + (i + 1)); buttonList.add(mapButtons[i]); } leftButton = new GuiButton(9, width / 2 - 128 + 6, height / 2 - 94 + 119, 20, 20, "<"); rightButton = new GuiButton(10, width / 2 + 128 - 26, height / 2 - 94 + 119, 20, 20, ">"); buttonList.add(leftButton); buttonList.add(rightButton); } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int k = scaledresolution.getScaledWidth(); int l = scaledresolution.getScaledHeight(); FontRenderer fontrenderer = mc.fontRenderer; drawDefaultBackground(); GlStateManager.enableBlend(); mc.renderEngine.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); int m = guiOriginX = k / 2 - 128; int n = guiOriginY = l / 2 - 94; drawTexturedModalRect(m, n, 0, 0, 256, 189); drawString(fontRenderer, "Base Settings", guiOriginX + 6, guiOriginY + 6, 0xffffff); drawString(fontRenderer, "Base Name : ", guiOriginX + 6, guiOriginY + 24, 0xffffff); drawString(fontRenderer, "Map", guiOriginX + 6, guiOriginY + 64, 0xffffff); nameEntryField.drawTextBox(); super.drawScreen(i, j, f); } @Override protected void actionPerformed(GuiButton button) { switch(button.id) { case 0: case 1: case 2: case 3: packet.teamID = button.id; break; case 4: case 5: case 6: case 7: case 8: packet.mapID = mapsPage * 5 + button.id - 4; break; case 9: mapsPage--; break; case 10: mapsPage++; break; } } @Override public void updateScreen() { for(int i = 0; i < 4; i++) { teamButtons[i].enabled = packet.teamID != i; } for(int i = 0; i < 5; i++) { mapButtons[i].visible = packet.maps.length > i + mapsPage * 5; if(mapButtons[i].visible) { mapButtons[i].displayString = packet.maps[i + mapsPage * 5]; mapButtons[i].enabled = i + mapsPage * 5 != packet.mapID; } } rightButton.visible = packet.maps.length > (mapsPage + 1) * 5; leftButton.visible = mapsPage > 0; nameEntryField.updateCursorCounter(); } @Override protected void mouseClicked(int i, int j, int k) { try { super.mouseClicked(i, j, k); } catch(IOException e) { } nameEntryField.mouseClicked(i, j, k); } @Override protected void keyTyped(char c, int i) { try { super.keyTyped(c, i); } catch(IOException e) { } nameEntryField.textboxKeyTyped(c, i); } @Override public void onGuiClosed() { super.onGuiClosed(); packet.baseName = nameEntryField.getText(); Keyboard.enableRepeatEvents(false); FlansMod.getPacketHandler().sendToServer(packet); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiChooseLoadout.java ================================================ package com.flansmod.client.gui.teams; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.TeamsManagerRanked; public class GuiChooseLoadout extends GuiTeamsBase { /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/LandingPage.png"); public GuiChooseLoadout() { super(); } @Override public void initGui() { super.initGui(); ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); guiOriginX = w / 2 - 128; guiOriginY = h / 2 - 99; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in choose loadout page!"); return; } for(int i = 0; i < 5; i++) { if(data.currentLevel >= pool.slotUnlockLevels[i]) { buttonList.add( new GuiButton(i, width / 2 - 128 + 12 + 49 * i, height / 2 - 99 + 117, 36, 20, "Select")); } } buttonList.add(new GuiButton(5, width / 2 - 128 + 7, height / 2 - 99 + 144, 88, 20, "<< Change Team")); } @Override protected void actionPerformed(GuiButton button) { if(button.id >= 0 && button.id < 5) { TeamsManagerRanked.ChooseLoadout(button.id); FMLClientHandler.instance().getClient().displayGuiScreen(null); } if(button.id == 5) { //Go back to team select ClientTeamsData.OpenTeamSelectPage(); } } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); guiOriginX = w / 2 - 128; guiOriginY = h / 2 - 99; //Bind the background texture mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in choose loadout page!"); return; } //Draw the background drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY, 0, 0, 256, 143, textureX, textureY); drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY + 143, 256, 180, 256, 76, textureX, textureY); // Draw text drawCenteredString(fontRenderer, "Choose a loadout", guiOriginX + 128, guiOriginY + 12, 0xffffff); // Draw loadout panels for(int n = 0; n < 5; n++) { DrawLoadoutPanel(pool, data, guiOriginX + 7 + 49 * n, guiOriginY + 28, n); } super.drawScreen(i, j, f); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiEditLoadout.java ================================================ package com.flansmod.client.gui.teams; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.EnumAttachmentType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.LoadoutPool.LoadoutEntry; import com.flansmod.common.teams.LoadoutPool.LoadoutEntryInfoType; import com.flansmod.common.teams.LoadoutPool.LoadoutEntryPaintjob; import com.flansmod.common.teams.PlayerLoadout; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.TeamsManagerRanked; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class GuiEditLoadout extends GuiTeamsBase { /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/LoadoutEditor.png"); private static final int WIDTH = 326, HEIGHT = 198; protected int selectedLoadout = 0; protected EnumLoadoutSlot selectedSlot = EnumLoadoutSlot.primary; protected int selectedCategory = 0; protected int scroller = 0; private PlayerLoadout previousLoadout = null; protected ArrayList availableComponents = new ArrayList<>(); private static final String[] WEAPON_COMPONENT_NAMES = new String[] {"Weapon", "Paint", "Scope", "Barrel", "Stock", "Grip", "Extra"}; private static final String[] NON_WEAPON_COMPONENT_NAMES = new String[] {"Item", "Paint"}; public GuiEditLoadout(int i) { super(); selectedLoadout = i; previousLoadout = ClientTeamsData.theRankData.loadouts[selectedLoadout].copy(); RecalculateAvailableEntries(); } @Override public void initGui() { super.initGui(); ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; buttonList.add(new GuiButton(0, width / 2 - WIDTH / 2 + 10, height / 2 - HEIGHT / 2 + 143, 82, 20, "Confirm")); buttonList.add(new GuiButton(1, width / 2 - WIDTH / 2 + 10, height / 2 - HEIGHT / 2 + 165, 82, 20, "Cancel")); } @Override protected void actionPerformed(GuiButton button) { if(button.id == 0) // Confirm { // Send data to server TeamsManagerRanked.ConfirmLoadoutChanges(); ClientTeamsData.OpenLandingPage(); } else if(button.id == 1) // Cancel { ClientTeamsData.theRankData.loadouts[selectedLoadout] = previousLoadout.copy(); ClientTeamsData.OpenLandingPage(); } } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; //Bind the background texture mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in landing page!"); return; } //Draw the background drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY, 0, 0, WIDTH, HEIGHT, textureX, textureY); // Draw title text drawCenteredString(fontRenderer, "Edit Loadout " + (selectedLoadout + 1), guiOriginX + WIDTH / 2, guiOriginY + 4, 0xffffff); // Draw loadout slots panel { mc.renderEngine.bindTexture(texture); drawModalRectWithCustomSizedTexture(guiOriginX + 70, guiOriginY + 32 + 22 * selectedSlot.ordinal(), 70, 203, 36, 22, textureX, textureY); drawCenteredString(fontRenderer, "Loadout", guiOriginX + 51, guiOriginY + 18, 0xffffff); for(int n = 0; n < EnumLoadoutSlot.values().length; n++) { drawCenteredString(fontRenderer, EnumLoadoutSlot.values()[n].name, guiOriginX + 39, guiOriginY + 38 + 22 * n, 0xffffff); ItemStack stack = data.loadouts[selectedLoadout].slots[n]; drawSlotInventory(stack, guiOriginX + 73, guiOriginY + 35 + 22 * n); } } // Draw slot panel { mc.renderEngine.bindTexture(texture); drawModalRectWithCustomSizedTexture(guiOriginX + 169, guiOriginY + 32 + 22 * selectedCategory, 70, 203, 36, 22, textureX, textureY); drawCenteredString(fontRenderer, selectedSlot.name, guiOriginX + 150, guiOriginY + 18, 0xffffff); if(selectedSlot.isWeapon) { for(int n = 0; n < WEAPON_COMPONENT_NAMES.length; n++) { ItemStack stack = data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()]; InfoType type = (stack != null && stack.getItem() instanceof IFlanItem) ? ((IFlanItem)stack.getItem()).getInfoType() : null; int numUnlocks = type != null ? data.GetNumUnlocksForType(type) : 0; if(n == 1 && type != null && numUnlocks > 0) { drawCenteredString(fontRenderer, WEAPON_COMPONENT_NAMES[n] + " (" + numUnlocks + ")", guiOriginX + 138, guiOriginY + 38 + 22 * n, 0xffffff); } else drawCenteredString(fontRenderer, WEAPON_COMPONENT_NAMES[n], guiOriginX + 138, guiOriginY + 38 + 22 * n, 0xffffff); switch(n) { case 0: // Main item { ItemStack copy = ItemStack.EMPTY.copy(); if(stack != null) { copy = stack.copy(); copy.setItemDamage(0); } drawSlotInventory(copy, guiOriginX + 172, guiOriginY + 35 + 22 * n); break; } case 1: // Paint { drawSlotInventory(stack, guiOriginX + 172, guiOriginY + 35 + 22 * n); break; } default: { if(stack != null && !stack.isEmpty() && stack.getTagCompound() != null) { NBTTagCompound attachmentTags = stack.getTagCompound().getCompoundTag("attachments"); if(attachmentTags != null) { ItemStack attachmentStack = ItemStack.EMPTY.copy(); switch(n) { case 2: attachmentStack = new ItemStack(attachmentTags.getCompoundTag("scope")); break; case 3: attachmentStack = new ItemStack(attachmentTags.getCompoundTag("barrel")); break; case 4: attachmentStack = new ItemStack(attachmentTags.getCompoundTag("stock")); break; case 5: attachmentStack = new ItemStack(attachmentTags.getCompoundTag("grip")); break; case 6: attachmentStack = new ItemStack(attachmentTags.getCompoundTag("generic_0")); break; } drawSlotInventory(attachmentStack, guiOriginX + 172, guiOriginY + 35 + 22 * n); } } break; } } } } else { for(int n = 0; n < NON_WEAPON_COMPONENT_NAMES.length; n++) { drawCenteredString(fontRenderer, NON_WEAPON_COMPONENT_NAMES[n], guiOriginX + 138, guiOriginY + 38 + 22 * n, 0xffffff); ItemStack stack = data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()]; switch(n) { case 0: // Main item { ItemStack copy = ItemStack.EMPTY.copy(); if(stack != null) { copy = stack.copy(); copy.setItemDamage(0); } drawSlotInventory(copy, guiOriginX + 172, guiOriginY + 35 + 22 * n); break; } case 1: // Paint { drawSlotInventory(stack, guiOriginX + 172, guiOriginY + 35 + 22 * n); break; } default: { break; } } } } } // Draw stats panel { String name = ""; ItemStack stack = data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()]; if(stack != null && !stack.isEmpty()) { name = stack.getDisplayName(); } drawCenteredString(fontRenderer, name, guiOriginX + 262, guiOriginY + 18, 0xffffff); DrawGun(stack, guiOriginX + 254, guiOriginY + 48, 40f); drawCenteredString(fontRenderer, "Damage", guiOriginX + 234, guiOriginY + 60, 0xffffff); drawCenteredString(fontRenderer, "Accuracy", guiOriginX + 234, guiOriginY + 70, 0xffffff); drawCenteredString(fontRenderer, "Ammo", guiOriginX + 234, guiOriginY + 80, 0xffffff); if(stack != null && stack.getItem() instanceof ItemGun) { GunType type = ((ItemGun)stack.getItem()).GetType(); LoadoutEntryInfoType entry = pool.GetLoadoutEntryForInfoType(selectedSlot.ordinal(), type); ShootableType mainAmmo = null; int numClips = 1; for(ItemStack extra : entry.extraItems) { if(extra != null && extra.getItem() instanceof ItemShootable) { mainAmmo = ((ItemShootable)extra.getItem()).type; numClips = extra.getCount(); break; } } if(mainAmmo != null) { drawCenteredString(fontRenderer, String.format("%.0f", type.damage * mainAmmo.damageVsLiving * mainAmmo.numBullets), guiOriginX + 290, guiOriginY + 60, 0xffffff); drawCenteredString(fontRenderer, String.format("%.0f", (50.0f - type.bulletSpread) * 2.0f), guiOriginX + 290, guiOriginY + 70, 0xffffff); drawCenteredString(fontRenderer, String.format("%d", mainAmmo.roundsPerItem * numClips), guiOriginX + 290, guiOriginY + 80, 0xffffff); } } } // Draw selector panel { drawCenteredString(fontRenderer, "Choose " + WEAPON_COMPONENT_NAMES[selectedCategory].toLowerCase(), guiOriginX + 262, guiOriginY + 95, 0xffffff); for(int row = 0; row < 4; row++) { for(int col = 0; col < 6; col++) { int index = scroller * 24 + row * 6 + col; if(index >= availableComponents.size()) { continue; } LoadoutEntry entry = availableComponents.get(index); if(entry instanceof LoadoutEntryInfoType) { drawSlotInventory(new ItemStack(((LoadoutEntryInfoType)entry).type.getItem()), guiOriginX + 209 + col * 18, guiOriginY + 107 + row * 18); } else if(entry instanceof LoadoutEntryPaintjob) { Paintjob paintjob = ((LoadoutEntryPaintjob)entry).paintjob; DrawRarityBackground(paintjob.rarity, guiOriginX + 209 + col * 18, guiOriginY + 107 + row * 18); drawSlotInventory(new ItemStack(paintjob.parent.getItem(), 1, paintjob.ID), guiOriginX + 209 + col * 18, guiOriginY + 107 + row * 18); } if(!entry.available) { mc.renderEngine.bindTexture(texture); GlStateManager.pushMatrix(); GlStateManager.translate(0.0f, 0.0f, 101.0f); drawModalRectWithCustomSizedTexture(guiOriginX + 209 + col * 18, guiOriginY + 107 + row * 18, 332, 161, 16, 16, textureX, textureY); if(entry.unlockLevel > 0) { drawCenteredString(fontRenderer, "" + entry.unlockLevel, guiOriginX + 218 + col * 18, guiOriginY + 112 + row * 18, 0xffffff); } GlStateManager.popMatrix(); } } } } // Resets some GL modes to prevent screen going grey sometimes. Quick and easy hack. Thanks, stick. drawSlotInventory(new ItemStack(Items.STICK), -50, -50); super.drawScreen(i, j, f); } private boolean IsInSquare(int clickX, int clickY, int x, int y, int w, int h) { return x <= clickX && clickX < x + w && y <= clickY && clickY < y + h; } @Override protected void mouseClicked(int i, int j, int k) throws IOException { super.mouseClicked(i, j, k); int x = i - guiOriginX; int y = j - guiOriginY; if(k == 0 || k == 1) { // Loadout slots panel for(int n = 0; n < EnumLoadoutSlot.values().length; n++) { if(IsInSquare(x, y, 70, 32 + 22 * n, 22, 22)) { selectedSlot = EnumLoadoutSlot.values()[n]; //if(!selectedSlot.isWeapon && selectedCategory > 2) selectedCategory = 0; RecalculateAvailableEntries(); } } // Slot panel if(selectedSlot.isWeapon) { for(int n = 0; n < WEAPON_COMPONENT_NAMES.length; n++) { if(IsInSquare(x, y, 169, 32 + 22 * n, 22, 22)) { selectedCategory = n; RecalculateAvailableEntries(); } } } else { for(int n = 0; n < NON_WEAPON_COMPONENT_NAMES.length; n++) { if(IsInSquare(x, y, 169, 32 + 22 * n, 22, 22)) { selectedCategory = n; RecalculateAvailableEntries(); } } } // Selector panel for(int row = 0; row < 4; row++) { for(int col = 0; col < 6; col++) { int index = scroller * 24 + row * 6 + col; if(index >= availableComponents.size()) continue; if(!availableComponents.get(index).available) continue; if(IsInSquare(x, y, 209 + col * 18, 107 + row * 18, 18, 18)) { LoadoutEntry entry = availableComponents.get(index); SelectItem(entry); } } } if(IsInSquare(x, y, 257, 179, 10, 10)) { SelectItem(null); } } } public void SelectItem(LoadoutEntry entry) { PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; switch(selectedCategory) { case 0: // Main item { if(entry instanceof LoadoutEntryInfoType) { data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()] = new ItemStack(((LoadoutEntryInfoType)entry).type.getItem()); } else if(entry != null) { FlansMod.log.warn("Loadout entry doesn't match for slot"); } break; } case 1: // Paint { if(entry instanceof LoadoutEntryPaintjob) { if(data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()] != null) { data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()].setItemDamage(((LoadoutEntryPaintjob)entry).paintjob.ID); } else FlansMod.log.warn("Applying paintjob to null item!"); } else if(entry != null) { FlansMod.log.warn("Loadout entry doesn't match slot"); } } default: // Attachments { if(entry instanceof LoadoutEntryInfoType || entry == null) { ItemStack stack = data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()]; if(stack != null && !stack.isEmpty()) { if(stack.getTagCompound() == null) { stack.setTagCompound(new NBTTagCompound()); } NBTTagCompound attachmentTags = stack.getTagCompound().getCompoundTag("attachments"); if(attachmentTags == null) { attachmentTags = new NBTTagCompound(); } NBTTagCompound ourTags = new NBTTagCompound(); if(entry != null) { ItemStack attachmentStack = new ItemStack(((LoadoutEntryInfoType)entry).type.getItem()); attachmentStack.writeToNBT(ourTags); } switch(selectedCategory) { case 2: attachmentTags.setTag("scope", ourTags); break; case 3: attachmentTags.setTag("barrel", ourTags); break; case 4: attachmentTags.setTag("stock", ourTags); break; case 5: attachmentTags.setTag("grip", ourTags); break; case 6: attachmentTags.setTag("generic_0", ourTags); break; } stack.getTagCompound().setTag("attachments", attachmentTags); } else FlansMod.log.warn("Applying attachment to null item!"); } else FlansMod.log.warn("Loadout entry doesn't match for slot"); } } } public class LoadoutComparator implements Comparator { @Override public int compare(LoadoutEntry a, LoadoutEntry b) { if(a.unlockLevel < b.unlockLevel) return -1; if(a.unlockLevel > b.unlockLevel) return 1; if(a instanceof LoadoutEntryPaintjob && b instanceof LoadoutEntryPaintjob) { if(((LoadoutEntryPaintjob)a).paintjob.rarity.ordinal() < ((LoadoutEntryPaintjob)b).paintjob.rarity.ordinal()) return -1; if(((LoadoutEntryPaintjob)a).paintjob.rarity.ordinal() > ((LoadoutEntryPaintjob)b).paintjob.rarity.ordinal()) return 1; } return 0; } } public void RecalculateAvailableEntries() { availableComponents.clear(); PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; ArrayList unlockedEntries = new ArrayList<>(); ArrayList lockedEntries = new ArrayList<>(); if(selectedCategory == 1) // Paint { ItemStack stack = data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()]; if(stack != null && stack.getItem() instanceof IPaintableItem) { PaintableType type = ((IPaintableItem)stack.getItem()).GetPaintableType(); for(int i = 0; i < type.paintjobs.size(); i++) { LoadoutEntryPaintjob entry = new LoadoutEntryPaintjob(); entry.unlockLevel = 0; entry.paintjob = type.paintjobs.get(i); if(i == 0) { entry.available = true; } else { entry.available = TeamsManagerRanked.LocalPlayerOwnsUnlock(entry.paintjob.hashCode()); } if(entry.available) unlockedEntries.add(entry); else lockedEntries.add(entry); } } } else { for(LoadoutEntryInfoType entry : pool.unlocks[selectedSlot.ordinal()]) { switch(selectedCategory) { case 0: // Main item { if(entry.type instanceof AttachmentType) continue; break; } case 1: break; // Paint. Shouldn't even get here default: // Attachments. Check sub-type { // Check it is an attachment if(!(entry.type instanceof AttachmentType)) continue; // Check that the gun allows it GunType gunType = ((ItemGun)data.loadouts[selectedLoadout].slots[selectedSlot.ordinal()].getItem()).GetType(); if(!gunType.allowAllAttachments && !gunType.allowedAttachments.contains(entry.type)) continue; // And check that it is right for the slot EnumAttachmentType attachType = ((AttachmentType)entry.type).type; switch(selectedCategory) { case 2: if(attachType != EnumAttachmentType.sights) continue; else break; case 3: if(attachType != EnumAttachmentType.barrel) continue; else break; case 4: if(attachType != EnumAttachmentType.stock) continue; else break; case 5: if(attachType != EnumAttachmentType.grip) continue; else break; case 6: if(attachType != EnumAttachmentType.generic) continue; else break; } break; } } LoadoutEntryInfoType copy = new LoadoutEntryInfoType(); copy.type = entry.type; copy.unlockLevel = entry.unlockLevel; copy.available = data.currentLevel >= copy.unlockLevel; if(copy.available) unlockedEntries.add(copy); else lockedEntries.add(copy); } } unlockedEntries.sort(new LoadoutComparator()); lockedEntries.sort(new LoadoutComparator()); availableComponents.addAll(unlockedEntries); availableComponents.addAll(lockedEntries); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiLandingPage.java ================================================ package com.flansmod.client.gui.teams; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.RewardBox; public class GuiLandingPage extends GuiTeamsBase { /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/LandingPage.png"); private static final int WIDTH = 256, HEIGHT = 215; public GuiLandingPage() { super(); } @Override public void initGui() { super.initGui(); ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in landing page!"); mc.displayGuiScreen(null); return; } for(int i = 0; i < 5; i++) { if(data.currentLevel >= pool.slotUnlockLevels[i]) { buttonList.add( new GuiButton(i, width / 2 - WIDTH / 2 + 12 + 49 * i, height / 2 - HEIGHT / 2 + 117, 36, 20, "Edit")); } } buttonList.add(new GuiButton(5, width / 2 - WIDTH / 2 + 202, height / 2 - HEIGHT / 2 + 162, 47, 20, "Play >>")); for(int i = 0; i < 3; i++) { int numBoxes = data.GetNumOfUnopenedBoxes(pool.rewardBoxes[i]); GuiButton button = new GuiButton(6 + i, width / 2 - WIDTH / 2 + 9 + 65 * i, height / 2 - HEIGHT / 2 + 187, 59, 20, "Open"); button.enabled = numBoxes > 0; buttonList.add(button); } } @Override protected void actionPerformed(GuiButton button) { if(button.id >= 0 && button.id < 5) { ClientTeamsData.OpenEditLoadoutPage(button.id); } if(button.id == 5) { //Play - go to team select ClientTeamsData.OpenTeamSelectPage(); } if(button.id >= 6 && button.id < 6 + 3) { ClientTeamsData.OpenRewardBox(button.id - 6); } } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; //Bind the background texture mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in landing page!"); mc.displayGuiScreen(null); return; } //Draw the background drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY, 0, 0, WIDTH, HEIGHT, textureX, textureY); int XPForNextLevel = pool.GetXPForLevel(data.currentLevel + 1); float XPProgress = 0.0f; if(XPForNextLevel > 0) { XPProgress = (float)data.currentXP / (float)XPForNextLevel; } else { XPProgress = 1.0f; } drawModalRectWithCustomSizedTexture(guiOriginX + 106, guiOriginY + 146, 259, 164, (int)(92.0f * XPProgress), 16, textureX, textureY); // Draw text drawCenteredString(fontRenderer, ClientTeamsData.motd, guiOriginX + 128, guiOriginY + 12, 0xffffff); drawString(fontRenderer, mc.player.getName(), guiOriginX + 30, guiOriginY + 150, 0xffffff); drawCenteredString(fontRenderer, "Rank " + data.currentLevel, guiOriginX + 154, guiOriginY + 150, 0xffffff); // Draw rank icon DrawRankIcon(data.currentLevel, 0, 9, 146, false); // Draw loadout panels for(int n = 0; n < 5; n++) { DrawLoadoutPanel(pool, data, guiOriginX + 7 + 49 * n, guiOriginY + 28, n); } // Draw reward box panels for(int n = 0; n < 3; n++) { DrawRewardBoxPanel(pool, data, guiOriginX + 7 + 65 * n, guiOriginY + 166, n); } super.drawScreen(i, j, f); } private void DrawRewardBoxPanel(LoadoutPool pool, PlayerRankData data, int x, int y, int index) { RewardBox box = pool.rewardBoxes[index]; drawSlotInventory(new ItemStack(box.getItem()), x + 3, y + 3); drawCenteredString(fontRenderer, "x " + data.GetNumOfUnopenedBoxes(box), x + 33, y + 7, 0xffffff); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiMissionResults.java ================================================ package com.flansmod.client.gui.teams; import java.util.ArrayList; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.client.FlansModClient; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.GunType; import com.flansmod.common.network.PacketTeamInfo; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.LoadoutPool.LoadoutEntryInfoType; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.RewardBox; public class GuiMissionResults extends GuiTeamsBase { /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/MissionResults.png"); private static final int WIDTH = 256, HEIGHT = 256; private enum EnumResultsState { IDLE, SHOW_LINE_1_XP, SHOW_LINE_2_VICTORY_BONUS, SHOW_LINE_3, SHOW_LINE_4, SHOW_LINE_5_TOTAL, INCREASE_XP_BAR, LEVEL_UP, REVEAL_UNLOCK1, REVEAL_UNLOCK2, REVEAL_UNLOCK3, REVEAL_UNLOCK4, DONE } private static final int[] stateTimes = new int[]{ 0, 4, 4, 4, 4, 4, 20, 20, 5, 5, 5, 25, 0 }; private static class MissionResultsUnlock { public boolean isWeapon = true; public LoadoutEntryInfoType loadoutEntry = null; public RewardBox rewardBox = null; } private int timeInState = 0; // Temp rank data private int displayRank, displayXP, earnedXP; private int targetRank, targetXP; private int lastXP; private boolean hasLevelledUp = false, hasDoneFinalLevelUp = false; private EnumResultsState state = EnumResultsState.IDLE; private MissionResultsUnlock[] unlocks = new MissionResultsUnlock[4]; public GuiMissionResults() { super(); PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in mission results!"); return; } state = EnumResultsState.SHOW_LINE_1_XP; displayRank = data.currentLevel; lastXP = displayXP = data.currentXP; earnedXP = data.pendingXP; targetXP = data.currentXP + data.pendingXP; targetRank = data.currentLevel; int XPForNextLevel = pool.GetXPForLevel(targetRank + 1); while(XPForNextLevel > 0 && targetXP >= XPForNextLevel) { targetXP -= XPForNextLevel; targetRank++; XPForNextLevel = pool.GetXPForLevel(targetRank + 1); } hasLevelledUp = false; } @Override public void initGui() { super.initGui(); ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; buttonList.add(new GuiButton(0, width / 2 - WIDTH / 2 + 214, height / 2 - HEIGHT / 2 + 6, 36, 20, "Done")); } @Override protected void actionPerformed(GuiButton button) { if(button.id == 0) // Confirm { // Send data to server FMLClientHandler.instance().getClient().displayGuiScreen(new GuiTeamScores()); } } @Override public void updateScreen() { PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in mission results!"); return; } timeInState++; switch(state) { case IDLE: { break; } case SHOW_LINE_1_XP: case SHOW_LINE_2_VICTORY_BONUS: case SHOW_LINE_3: case SHOW_LINE_4: case SHOW_LINE_5_TOTAL: { if(timeInState > stateTimes[state.ordinal()]) { EnterState(EnumResultsState.values()[(state.ordinal() + 1)]); } break; } case INCREASE_XP_BAR: { int currentTarget = targetXP; if(targetRank > displayRank) { currentTarget = pool.GetXPForLevel(displayRank + 1); } displayXP = MathHelper.floor(lastXP + ((float)(currentTarget - lastXP) * (float)(timeInState - 1) / (float)stateTimes[state.ordinal()])); if(timeInState > stateTimes[state.ordinal()]) { if(targetRank > displayRank) { EnterState(EnumResultsState.LEVEL_UP); } else { EnterState(EnumResultsState.DONE); } } break; } case LEVEL_UP: case REVEAL_UNLOCK1: case REVEAL_UNLOCK2: case REVEAL_UNLOCK3: { if(timeInState > stateTimes[state.ordinal()]) { EnterState(EnumResultsState.values()[(state.ordinal() + 1)]); } break; } case REVEAL_UNLOCK4: { if(timeInState > stateTimes[state.ordinal()]) { EnterState(EnumResultsState.INCREASE_XP_BAR); } break; } case DONE: break; default: break; } } private void EnterState(EnumResultsState newState) { PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in mission results!"); return; } // Do exit checks? state = newState; timeInState = 0; switch(state) { case INCREASE_XP_BAR: { lastXP = displayXP; break; } case LEVEL_UP: { displayRank++; displayXP = 0; hasLevelledUp = true; for(int i = 0; i < 4; i++) { unlocks[i] = null; } int index = 0; for(ArrayList list : pool.unlocks) { for(LoadoutEntryInfoType entry : list) { if(index >= 4) continue; boolean conflict = false; for(int i = 0; i < index; i++) { if(unlocks[i].isWeapon && unlocks[i].loadoutEntry != null && unlocks[i].loadoutEntry.type.shortName.equals(entry.type.shortName)) conflict = true; } if(conflict) continue; if(entry.unlockLevel == displayRank) { unlocks[index] = new MissionResultsUnlock(); unlocks[index].isWeapon = true; unlocks[index].loadoutEntry = entry; index++; } } } for(RewardBox box : pool.rewardsPerLevel[displayRank - 1]) { unlocks[index] = new MissionResultsUnlock(); unlocks[index].isWeapon = false; unlocks[index].rewardBox = box; index++; } break; } case REVEAL_UNLOCK4: { if(displayRank == targetRank) { hasDoneFinalLevelUp = true; } break; } default: break; } } @Override public void drawScreen(int i, int j, float f) { PacketTeamInfo teamInfo = FlansModClient.teamInfo; if(teamInfo == null || teamInfo.gametype == null || teamInfo.gametype.equals("") || teamInfo.teamData == null || teamInfo.teamData.length < 1 || !teamInfo.roundOver()) { mc.displayGuiScreen(null); return; } ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; //Bind the background texture mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in mission results!"); return; } //Draw the background drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY, 0, 0, WIDTH, HEIGHT, textureX, textureY); int XPForNextLevel = pool.GetXPForLevel(displayRank + 1); float XPProgress = 0.0f; if(XPForNextLevel > 0) { XPProgress = (float)displayXP / (float)XPForNextLevel; } else { XPProgress = 1.0f; } XPProgress = MathHelper.clamp(XPProgress, 0.0f, 1.0f); drawModalRectWithCustomSizedTexture(guiOriginX + 7, guiOriginY + 109, 259, 109, (int)(242 * XPProgress), 10, textureX, textureY); if(state.ordinal() >= EnumResultsState.LEVEL_UP.ordinal() && state.ordinal() <= EnumResultsState.REVEAL_UNLOCK4.ordinal()) { drawModalRectWithCustomSizedTexture(guiOriginX + 5, guiOriginY + 120, 266, 120, 246, 38, textureX, textureY); } if(XPForNextLevel > 0) { drawCenteredString(fontRenderer, displayXP + " / " + XPForNextLevel, guiOriginX + 128, guiOriginY + 110, 0xffffff); } else { drawCenteredString(fontRenderer, "" + displayXP, guiOriginX + 128, guiOriginY + 110, 0xffffff); } // Draw text drawString(fontRenderer, (ClientTeamsData.timeLeftInStage / 20) + "", guiOriginX + 12, guiOriginY + 12, 0xffffff); drawCenteredString(fontRenderer, "ROUND OVER", guiOriginX + 128, guiOriginY + 12, 0xffffff); if(state.ordinal() >= EnumResultsState.LEVEL_UP.ordinal() && state.ordinal() <= EnumResultsState.REVEAL_UNLOCK4.ordinal()) { drawCenteredString(fontRenderer, "RANK INCREASED", guiOriginX + 128, guiOriginY + 135, 0xffffff); } else { drawString(fontRenderer, "Rank " + displayRank, guiOriginX + 44, guiOriginY + 135, 0xffffff); drawString(fontRenderer, "Next Rank", guiOriginX + 163, guiOriginY + 135, 0xffffff); } if(state.ordinal() >= EnumResultsState.SHOW_LINE_1_XP.ordinal()) { drawString(fontRenderer, "XP Earned: ", guiOriginX + 11, guiOriginY + 31, 0xffffff); drawString(fontRenderer, "" + earnedXP, guiOriginX + 244 - fontRenderer.getStringWidth("" + earnedXP), guiOriginY + 31, 0xffffff); } if(state.ordinal() >= EnumResultsState.SHOW_LINE_2_VICTORY_BONUS.ordinal()) drawString(fontRenderer, "", guiOriginX + 11, guiOriginY + 41, 0xffffff); if(state.ordinal() >= EnumResultsState.SHOW_LINE_3.ordinal()) drawString(fontRenderer, "", guiOriginX + 11, guiOriginY + 51, 0xffffff); if(state.ordinal() >= EnumResultsState.SHOW_LINE_4.ordinal()) drawString(fontRenderer, "", guiOriginX + 11, guiOriginY + 61, 0xffffff); if(state.ordinal() >= EnumResultsState.SHOW_LINE_5_TOTAL.ordinal()) { drawString(fontRenderer, "Total: ", guiOriginX + 11, guiOriginY + 91, 0xffffff); drawString(fontRenderer, "" + earnedXP, guiOriginX + 244 - fontRenderer.getStringWidth("" + earnedXP), guiOriginY + 91, 0xffffff); } // Draw rank icon DrawRankIcon(displayRank, 0, 8, 123, true); if(displayRank < pool.maxLevel) { DrawRankIcon(displayRank + 1, 0, 216, 123, true); } boolean hasDoneFinalLevel = hasDoneFinalLevelUp; if(state.ordinal() >= EnumResultsState.REVEAL_UNLOCK1.ordinal() || hasDoneFinalLevel) DrawUnlock(unlocks[0], guiOriginX + 8, guiOriginY + 160); if(state.ordinal() >= EnumResultsState.REVEAL_UNLOCK2.ordinal() || hasDoneFinalLevel) DrawUnlock(unlocks[1], guiOriginX + 131, guiOriginY + 160); if(state.ordinal() >= EnumResultsState.REVEAL_UNLOCK3.ordinal() || hasDoneFinalLevel) DrawUnlock(unlocks[2], guiOriginX + 8, guiOriginY + 207); if(state.ordinal() >= EnumResultsState.REVEAL_UNLOCK4.ordinal() || hasDoneFinalLevel) DrawUnlock(unlocks[3], guiOriginX + 131, guiOriginY + 207); super.drawScreen(i, j, f); } private void DrawUnlock(MissionResultsUnlock entry, int i, int j) { if(entry == null) return; if(entry.isWeapon) { drawCenteredString(fontRenderer, "New item unlocked", i + 58, j + 2, 0xffffff); drawCenteredString(fontRenderer, entry.loadoutEntry.type.name, i + 58, j + 31, 0xffffff); if(entry.loadoutEntry.type instanceof GunType) { DrawGun(new ItemStack(entry.loadoutEntry.type.getItem()), i + 50, j + 24, 25.0f); } else { drawSlotInventory(new ItemStack(entry.loadoutEntry.type.getItem()), i + 49, j + 12); } } else { drawCenteredString(fontRenderer, "Reward obtained", i + 58, j + 2, 0xffffff); drawCenteredString(fontRenderer, entry.rewardBox.name, i + 58, j + 31, 0xffffff); drawSlotInventory(new ItemStack(entry.rewardBox.getItem()), i + 49, j + 12); } } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiOpenRewardBox.java ================================================ package com.flansmod.client.gui.teams; import java.util.ArrayList; import java.util.Random; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.ModuloHelper; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.RewardBox; public class GuiOpenRewardBox extends GuiTeamsBase { private enum EnumPageState { SPINNING, READY_TO_SLOW_DOWN, SLOWING_DOWN, STOPPED, } /** * The background image */ private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/OpenCrates.png"); private static final int WIDTH = 196, HEIGHT = 200; private static final int WAITING_FOR_SERVER = -1; private static int spinTime = 30, slowdownTime = 130; private static long timeOfLastSound = 0; private static Random gunScrambler = new Random(); private float spinSpeed = 0.555555555f; private ArrayList options = new ArrayList<>(); private int target = WAITING_FOR_SERVER; private EnumPageState state = EnumPageState.SPINNING; private int timeLeftInState = spinTime; private float spinner = 0.0f; private GuiButton doneButton; public void SetTarget(Paintjob paint) { for(int i = 0; i < options.size(); i++) { if(options.get(i) == paint) { target = i; return; } } FlansMod.Assert(false, "Could not find paintjob we just unlocked!"); } @Override public void initGui() { super.initGui(); ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; doneButton = new GuiButton(0, width / 2 - 20, guiOriginY + 170, 40, 20, "Done"); doneButton.enabled = false; buttonList.add(doneButton); } @Override protected void actionPerformed(GuiButton button) { if(button.id == 0) { ClientTeamsData.OpenLandingPage(); } } public GuiOpenRewardBox(RewardBox rewardBox) { super(); state = EnumPageState.SPINNING; timeLeftInState = spinTime; target = WAITING_FOR_SERVER; ArrayList temp = new ArrayList<>(rewardBox.paintjobs); int size = rewardBox.paintjobs.size(); for(int i = 0; i < size; i++) { int random = gunScrambler.nextInt(size - i); options.add(temp.get(random)); temp.remove(random); } spinSpeed = InitialVelocity(); } @Override public void updateScreen() { super.updateScreen(); timeLeftInState--; switch(state) { case SPINNING: { SimulateSpinner(); // Make sure we have our target from the server before trying to spin down on to it if(timeLeftInState <= 0 && target != WAITING_FOR_SERVER) { SwitchToState(EnumPageState.READY_TO_SLOW_DOWN); timeLeftInState = slowdownTime; } break; } case READY_TO_SLOW_DOWN: { SimulateSpinner(); float difference = MathHelper.abs(spinner - target); if(difference < 1.0f) { // We're here (ish). Fix the position and then spin round one last time, slowing down as we go. spinner = target; timeLeftInState = slowdownTime; SwitchToState(EnumPageState.SLOWING_DOWN); } break; } case SLOWING_DOWN: { spinSpeed += Acceleration(); if(spinSpeed <= -Acceleration()) { spinSpeed = 0.0f; FMLClientHandler.instance().getClient().getSoundHandler().playSound( new PositionedSoundRecord(FlansModResourceHandler.getSoundEvent("UnlockNotch"), SoundCategory.NEUTRAL, 1.0F, 2.0f, (float)mc.player.posX, (float)mc.player.posY, (float)mc.player.posZ)); SwitchToState(EnumPageState.STOPPED); } int timeInState = slowdownTime - timeLeftInState; int preIndex = MathHelper.floor(spinner) % options.size(); spinner = target + timeInState * InitialVelocity() + 0.5f * Acceleration() * timeInState * timeInState; int postIndex = MathHelper.floor(spinner) % options.size(); break; } case STOPPED: { spinner = target; doneButton.enabled = true; break; } default: break; } } private void SimulateSpinner() { int preIndex = MathHelper.floor(spinner) % options.size(); spinner += spinSpeed; int postIndex = MathHelper.floor(spinner) % options.size(); if(spinner > options.size()) { spinner -= options.size(); } } private float InitialVelocity() { return (2.0f / (float)slowdownTime) * options.size(); } private float Acceleration() { return -(InitialVelocity() * InitialVelocity()) / (2 * options.size()); } private void SwitchToState(EnumPageState newState) { state = newState; } @Override public void drawScreen(int i, int j, float f) { int preIndex = MathHelper.floor(spinner) % options.size(); int postIndex = MathHelper.floor(spinner + spinSpeed * f) % options.size(); if(preIndex != postIndex && Minecraft.getSystemTime() - timeOfLastSound >= 80) { FMLClientHandler.instance().getClient().getSoundHandler().playSound( new PositionedSoundRecord(FlansModResourceHandler.getSoundEvent("UnlockNotch"), SoundCategory.NEUTRAL, 0.5F, 1.0f, (float)mc.player.posX, (float)mc.player.posY, (float)mc.player.posZ)); timeOfLastSound = Minecraft.getSystemTime(); } ScaledResolution scaledresolution = new ScaledResolution(mc); int w = scaledresolution.getScaledWidth(); int h = scaledresolution.getScaledHeight(); drawDefaultBackground(); GlStateManager.enableBlend(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); guiOriginX = w / 2 - WIDTH / 2; guiOriginY = h / 2 - HEIGHT / 2; //Bind the background texture mc.renderEngine.bindTexture(texture); int textureX = 512; int textureY = 256; PlayerRankData data = ClientTeamsData.theRankData; LoadoutPool pool = ClientTeamsData.currentPool; if(data == null || pool == null) { FlansMod.log.warn("Problem in landing page!"); return; } //Draw the background drawModalRectWithCustomSizedTexture(guiOriginX, guiOriginY, 0, 0, WIDTH, HEIGHT, textureX, textureY); int pixelOffset = ModuloHelper.modulo(MathHelper.floor(spinner * 18.0f), 18) - 18; drawModalRectWithCustomSizedTexture(guiOriginX + 9, guiOriginY + 101, 239 + pixelOffset + 10, 101, 180, 18, textureX, textureY); // Draw text drawCenteredString(fontRenderer, "Reward Box", guiOriginX + 98, guiOriginY + 12, 0xffffff); for(int n = 0; n < 10; n++) { int index = MathHelper.floor(spinner) - 4 + n; Paintjob paintjob = options.get(ModuloHelper.modulo(index, options.size())); ItemStack stack = new ItemStack(paintjob.parent.getItem(), 1, paintjob.ID); drawSlotInventory(stack, guiOriginX + 18 - 18 - pixelOffset + 18 * n, guiOriginY + 102); } for(int n = 0; n < 10; n++) { int index = MathHelper.floor(spinner) - 4 + n; Paintjob paintjob = options.get(ModuloHelper.modulo(index, options.size())); DrawRarityBackground(paintjob.rarity, guiOriginX + 18 - 18 - pixelOffset + 18 * n, guiOriginY + 102); } mc.renderEngine.bindTexture(texture); GlStateManager.disableDepth(); drawModalRectWithCustomSizedTexture(guiOriginX + 0, guiOriginY + 93, 0, 93, 196, 34, textureX, textureY); GlStateManager.enableDepth(); int currentIndex = MathHelper.floor(spinner) % options.size(); ItemStack gunStack = new ItemStack(options.get(currentIndex).parent.item, 1, options.get(currentIndex).ID); DrawGun(gunStack, guiOriginX + 98, guiOriginY + 65, 60.0f); if(state == EnumPageState.STOPPED) { drawCenteredString(fontRenderer, "New paintjob unlocked!", guiOriginX + 98, guiOriginY + 130, 0xffffff); drawCenteredString(fontRenderer, options.get(target).parent.name, guiOriginX + 98, guiOriginY + 142, 0xffffff); drawCenteredString(fontRenderer, "\"" + options.get(target).iconName + "\"", guiOriginX + 98, guiOriginY + 154, 0xffffff); } super.drawScreen(i, j, f); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiTeamScores.java ================================================ package com.flansmod.client.gui.teams; import org.lwjgl.opengl.GL11; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; import com.flansmod.client.FlansModClient; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.network.PacketTeamInfo; import com.flansmod.common.teams.Team; public class GuiTeamScores extends GuiTeamsBase { public static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/teamsScores.png"); public static final ResourceLocation texture2 = new ResourceLocation("flansmod", "gui/teamsScores2.png"); @Override public void drawScreen(int i, int j, float f) { super.drawScreen(i, j, f); PacketTeamInfo teamInfo = FlansModClient.teamInfo; if(teamInfo == null || teamInfo.gametype == null || teamInfo.gametype.equals("") || teamInfo.teamData == null || teamInfo.teamData.length < 1) { mc.displayGuiScreen(null); return; } if(teamInfo.sortedByTeam) { renderTwoTeamGUI(teamInfo); } else renderDMGUI(teamInfo); } public void renderTwoTeamGUI(PacketTeamInfo teamInfo) { ScaledResolution scaledresolution = new ScaledResolution(mc); int k = scaledresolution.getScaledWidth(); int l = scaledresolution.getScaledHeight(); FontRenderer fontrenderer = mc.fontRenderer; drawDefaultBackground(); GlStateManager.enableBlend(); mc.renderEngine.bindTexture(texture2); int guiHeight = 68 + 9 * teamInfo.numLines; GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); int m = k / 2 - 156; int n = l / 2 - guiHeight / 2; //Like draw texturedModalRect, but with custom image size //func_146110_a(m, n, 100, 0, 312, 180, 512, 256); drawModalRectWithCustomSizedTexture(m, n, 100, 0, 312, 65, 512, 256); for(int p = 0; p < teamInfo.numLines; p++) drawModalRectWithCustomSizedTexture(m, n + 65 + 16 * p, 100, 65, 312, 16, 512, 256); drawModalRectWithCustomSizedTexture(m, n + 65 + (teamInfo.numLines) * 16, 100, 170, 312, 10, 512, 256); if(teamInfo.showZombieScore) { drawModalRectWithCustomSizedTexture(m + 103, n + 51, 412, 0, 29, 11, 512, 256); drawModalRectWithCustomSizedTexture(m + 254, n + 51, 412, 0, 29, 11, 512, 256); } //No idea why this works, but it makes the text bind its texture correctly //mc.renderEngine.bindTexture("/terrain.png"); //TODO : Investiagate this drawString(fontRenderer, teamInfo.map, m + 6, n + 6, 0xffffff); drawString(fontRenderer, teamInfo.gametype, m + 312 - 6 - fontRenderer.getStringWidth(teamInfo.gametype), n + 6, 0xffffff); if(teamInfo.roundOver()) { Team winners = teamInfo.getWinner(); //Time limit was hit if(winners == null) { drawString(fontRenderer, "Time Ran Out!", m + 10, n + 20, 0xffffff); } else { drawString(fontRenderer, winners.name + " Won!", m + 10, n + 20, 0xffffff); } drawString(fontRenderer, Math.max(ClientTeamsData.timeLeftInStage / 20, 0) + "", m + 312 - 22, n + 20, 0xffffff); } else { int secondsLeft = teamInfo.timeLeft / 20; int minutesLeft = secondsLeft / 60; secondsLeft = secondsLeft % 60; drawString(fontRenderer, "Time Left : " + minutesLeft + ":" + (secondsLeft < 10 ? "0" + secondsLeft : secondsLeft), m + 10, n + 20, 0xffffff); drawString(fontRenderer, "Score Limit : " + teamInfo.scoreLimit, m + 302 - fontRenderer.getStringWidth("Score Limit : " + teamInfo.scoreLimit), n + 20, 0xffffff); } for(int i = 0; i < 2; i++) { fontRenderer.drawString("\u00a7" + teamInfo.teamData[i].team.textColour + teamInfo.teamData[i].team.name, m + 10 + 151 * i, n + 39, 0xffffff); fontRenderer.drawString("\u00a7" + teamInfo.teamData[i].team.textColour + teamInfo.teamData[i].score, m + 133 + 151 * i, n + 39, 0xffffff); for(int j = 0; j < teamInfo.teamData[i].numPlayers; j++) { if(teamInfo.teamData[i].playerData[j] == null) continue; GlStateManager.color(1.0f, 1.0f, 1.0f); DrawRankIcon(teamInfo.teamData[i].playerData[j].level, 0, m + 10 + 151 * i, n + 65 + 16 * j, false); drawString(fontRenderer, teamInfo.teamData[i].playerData[j].username, m + 30 + 151 * i, n + 68 + 16 * j, 0xffffff); drawCenteredString(fontRenderer, "" + teamInfo.teamData[i].playerData[j].score, m + 111 + 151 * i, n + 68 + 16 * j, 0xffffff); drawCenteredString(fontRenderer, "" + (teamInfo.showZombieScore ? teamInfo.teamData[i].playerData[j].zombieScore : teamInfo.teamData[i].playerData[j].kills), m + 127 + 151 * i, n + 68 + 16 * j, 0xffffff); drawCenteredString(fontRenderer, "" + teamInfo.teamData[i].playerData[j].deaths, m + 143 + 151 * i, n + 68 + 16 * j, 0xffffff); } } /* drawString(fontRenderer, "Name", m + 8, n + 14, 0xffffff); drawString(fontRenderer, "Score", m + 100, n + 14, 0xffffff); drawString(fontRenderer, "Kills", m + 150, n + 14, 0xffffff); drawString(fontRenderer, "Deaths", m + 200, n + 14, 0xffffff); int line = 0; if(teamInfo.sortedByTeam) { for(int p = 0; p < teamInfo.numTeams; p++) { if(teamInfo.teamData[p] == null || teamInfo.teamData[p].team == null) continue; drawString(fontRenderer, "\u00a7" + teamInfo.teamData[p].team.textColour + teamInfo.teamData[p].team.name, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].score, m + 100, n + 25 + 9 * line, 0xffffff); line++; for(int q = 0; q < teamInfo.teamData[p].numPlayers; q++) { drawString(fontRenderer, teamInfo.teamData[p].playerData[q].username, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].score, m + 100, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].kills, m + 150, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].deaths, m + 200, n + 25 + 9 * line, 0xffffff); line++; } } } else { for(int q = 0; q < teamInfo.teamData[0].numPlayers; q++) { drawString(fontRenderer, teamInfo.teamData[0].playerData[q].username, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].score, m + 100, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].kills, m + 150, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].deaths, m + 200, n + 25 + 9 * line, 0xffffff); line++; } } */ GlStateManager.disableBlend(); } public void renderDMGUI(PacketTeamInfo teamInfo) { long newTime = mc.world.getWorldInfo().getWorldTime(); ScaledResolution scaledresolution = new ScaledResolution(mc); int k = scaledresolution.getScaledWidth(); int l = scaledresolution.getScaledHeight(); FontRenderer fontrenderer = mc.fontRenderer; drawDefaultBackground(); GlStateManager.enableBlend(); mc.renderEngine.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); int guiHeight = 34 + 9 * teamInfo.numLines; int m = k / 2 - 128; int n = l / 2 - guiHeight / 2; drawTexturedModalRect(m, n, 0, 45, 256, 24); for(int p = 0; p < teamInfo.numLines; p++) drawTexturedModalRect(m, n + 24 + 9 * p, 0, 71, 256, 9); drawTexturedModalRect(m, l / 2 + guiHeight / 2 - 10, 0, 87, 256, 10); //No idea why this works, but it makes the text bind its texture correctly //mc.renderEngine.bindTexture("/terrain.png"); //TODO : Investiagate this drawCenteredString(fontRenderer, teamInfo.gametype, k / 2, n + 4, 0xffffff); drawString(fontRenderer, "Name", m + 8, n + 14, 0xffffff); drawString(fontRenderer, "Score", m + 100, n + 14, 0xffffff); drawString(fontRenderer, "Kills", m + 150, n + 14, 0xffffff); drawString(fontRenderer, "Deaths", m + 200, n + 14, 0xffffff); int line = 0; if(teamInfo.sortedByTeam) { for(int p = 0; p < teamInfo.numTeams; p++) { if(teamInfo.teamData[p] == null || teamInfo.teamData[p].team == null) continue; drawString(fontRenderer, "\u00a7" + teamInfo.teamData[p].team.textColour + teamInfo.teamData[p].team.name, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].score, m + 100, n + 25 + 9 * line, 0xffffff); line++; for(int q = 0; q < teamInfo.teamData[p].numPlayers; q++) { drawString(fontRenderer, teamInfo.teamData[p].playerData[q].username, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].score, m + 100, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].kills, m + 150, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[p].playerData[q].deaths, m + 200, n + 25 + 9 * line, 0xffffff); line++; } } } else { for(int q = 0; q < teamInfo.teamData[0].numPlayers; q++) { drawString(fontRenderer, teamInfo.teamData[0].playerData[q].username, m + 8, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].score, m + 100, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].kills, m + 150, n + 25 + 9 * line, 0xffffff); drawString(fontRenderer, "" + teamInfo.teamData[0].playerData[q].deaths, m + 200, n + 25 + 9 * line, 0xffffff); line++; } } GlStateManager.disableBlend(); } @Override public boolean doesGuiPauseGame() { return false; } @Override protected boolean AllowEscape() { return true; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiTeamSelect.java ================================================ package com.flansmod.client.gui.teams; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderItem; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.network.PacketTeamSelect; import com.flansmod.common.teams.PlayerClass; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; public class GuiTeamSelect extends GuiScreen { private static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/teams.png"); private static RenderItem itemRenderer; private boolean classMenu; //This is static so that players may switch teams whenever they wish. //This is updated because the server forces players to pick teams when the teams change public static Team[] teamChoices; private PlayerClass[] classChoices; private int guiHeight; //For changing team when you want to, as opposed to when the server forces you to. public GuiTeamSelect() { if(teamChoices == null) { FMLClientHandler.instance().getClient().displayGuiScreen(null); return; } classMenu = false; guiHeight = 29 + 24 * teamChoices.length; } public GuiTeamSelect(Team[] teams) { classMenu = false; teamChoices = teams; guiHeight = 29 + 24 * teams.length; } public GuiTeamSelect(PlayerClass[] classes) { classMenu = true; classChoices = classes; guiHeight = 29 + 24 * classes.length; } @Override public void initGui() { super.initGui(); if(classMenu) { for(int i = 0; i < classChoices.length; i++) { if(classChoices[i] != null) buttonList.add(new GuiButton(i, width / 2 - 128 + 9, height / 2 - guiHeight / 2 + 24 + 24 * i, 73, 20, classChoices[i].name)); } } else { if(teamChoices == null) { FMLClientHandler.instance().getClient().displayGuiScreen(null); return; } for(int i = 0; i < teamChoices.length; i++) { if(teamChoices[i] != null) buttonList.add(new GuiButton(i, width / 2 - 128 + 10, height / 2 - guiHeight / 2 + 24 + 24 * i, 236, 20, "\u00a7" + teamChoices[i].textColour + teamChoices[i].name)); else buttonList.add(new GuiButton(i, width / 2 - 128 + 10, height / 2 - guiHeight / 2 + 24 + 24 * i, 236, 20, "No Team / Builder")); } } itemRenderer = mc.getRenderItem(); } @Override public void drawScreen(int i, int j, float f) { //TODO : Draw the inventory BG and slots for the class menu GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); drawDefaultBackground(); mc.renderEngine.bindTexture(texture); drawTexturedModalRect(width / 2 - 128, height / 2 - guiHeight / 2, 0, 0, 256, 22); drawTexturedModalRect(width / 2 - 128, height / 2 + guiHeight / 2 - 6, 0, 73, 256, 7); if(classMenu) { for(int n = 0; n < classChoices.length; n++) { drawTexturedModalRect(width / 2 - 128, height / 2 - guiHeight / 2 + 22 + 24 * n, 0, 23, 256, 24); } } else { for(int n = 0; n < teamChoices.length; n++) { drawTexturedModalRect(width / 2 - 128, height / 2 - guiHeight / 2 + 22 + 24 * n, 0, 48, 256, 24); } } fontRenderer.drawStringWithShadow(classMenu ? "Choose a Class" : "Choose a Team", width / 2 - 120, height / 2 - guiHeight / 2 + 8, 0xffffff); super.drawScreen(i, j, f); if(classMenu) { for(int n = 0; n < classChoices.length; n++) { for(int m = 0; m < classChoices[n].startingItems.size(); m++) { drawSlotInventory(classChoices[n].startingItems.get(m), width / 2 - 128 + 85 + 18 * m, height / 2 - guiHeight / 2 + 26 + 24 * n); } } } } @Override protected void actionPerformed(GuiButton button) { if(classMenu) { FlansMod.getPacketHandler().sendToServer(new PacketTeamSelect(classChoices[button.id].shortName, true)); Minecraft.getMinecraft().displayGuiScreen(null); } else { TeamsManager.getInstance().SelectTeam(teamChoices[button.id]); } } private void drawSlotInventory(ItemStack itemstack, int i, int j) { itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); } @Override public boolean doesGuiPauseGame() { return false; } @Override protected void keyTyped(char c, int i) { if(i == 1 || i == mc.gameSettings.keyBindInventory.getKeyCode()) { mc.player.closeScreen(); if(classMenu) { if(classChoices != null && classChoices.length > 0) FlansMod.getPacketHandler().sendToServer(new PacketTeamSelect(classChoices[0].shortName, true)); } else FlansMod.getPacketHandler().sendToServer(new PacketTeamSelect(Team.spectators.shortName, false)); } } @Override public void onGuiClosed() { } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiTeamsBase.java ================================================ package com.flansmod.client.gui.teams; import java.io.IOException; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import com.flansmod.client.ClientProxy; import com.flansmod.client.model.CustomItemRenderType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerLoadout; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.types.EnumPaintjobRarity; public class GuiTeamsBase extends GuiScreen { /** * Item renderer */ protected static RenderItem itemRenderer; /** * Gui origin */ protected int guiOriginX, guiOriginY; protected Minecraft mc; protected EntityPlayer player; public GuiTeamsBase() { super(); mc = Minecraft.getMinecraft(); player = mc.player; itemRenderer = mc.getRenderItem(); } @Override public void initGui() { super.initGui(); } @Override public void drawScreen(int i, int j, float f) { super.drawScreen(i, j, f); } private static final ResourceLocation loudoutBoxes = new ResourceLocation("flansmod", "gui/LandingPage.png"); private static final ResourceLocation ranks = new ResourceLocation("flansmod", "gui/Ranks.png"); private static final ResourceLocation loadoutEditor = new ResourceLocation("flansmod", "gui/LoadoutEditor.png"); protected void DrawLoadoutPanel(LoadoutPool pool, PlayerRankData data, int i, int j, int n) { mc.renderEngine.bindTexture(loudoutBoxes); int textureX = 512; int textureY = 256; if(data.currentLevel >= pool.slotUnlockLevels[n]) { drawModalRectWithCustomSizedTexture(i, j, 7 + 49 * n, 28, 46, 111, textureX, textureY); PlayerLoadout loadout = data.loadouts[n]; if(loadout != null) { DrawGun(loadout.slots[0], i + 20, j + 28, 16f); DrawGun(loadout.slots[1], i + 20, j + 46, 16f); drawSlotInventory(loadout.slots[0], i + 6, j + 54); drawSlotInventory(loadout.slots[1], i + 24, j + 54); drawSlotInventory(loadout.slots[2], i + 6, j + 72); drawSlotInventory(loadout.slots[3], i + 24, j + 72); } } else { drawModalRectWithCustomSizedTexture(i, j, 259, 28, 46, 111, textureX, textureY); drawCenteredString(fontRenderer, "Unlocks", i + 23, j + 23, 0xffffff); drawCenteredString(fontRenderer, "at " + pool.slotUnlockLevels[n], i + 23, j + 40, 0xffffff); } drawCenteredString(fontRenderer, "Slot " + (n + 1), i + 23, j + 5, 0xffffff); } protected void DrawRarityBackground(EnumPaintjobRarity rarity, int i, int j) { mc.renderEngine.bindTexture(loadoutEditor); int textureX = 512; int textureY = 256; if(rarity != EnumPaintjobRarity.UNKNOWN) { int x = 0, y = 71; switch(rarity) { case COMMON: x = 331; break; case UNCOMMON: x = 349; break; case RARE: x = 367; break; case LEGENDARY: { x = 385; break; } default: break; } if(x > 0) { drawModalRectWithCustomSizedTexture(i, j, x, y, 16, 16, textureX, textureY); } } } protected void DrawGun(ItemStack stack, int x, int y, float scale) { if(stack != null && stack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)stack.getItem()).GetType(); if(gunType.model != null) { GlStateManager.pushMatrix(); GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.translate(x, y, 100); GlStateManager.disableLighting(); GlStateManager.pushMatrix(); GlStateManager.rotate(180F, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(1F, 0.0F, 1.0F, 0.0F); RenderHelper.enableStandardItemLighting(); GlStateManager.popMatrix(); GlStateManager.enableRescaleNormal(); GlStateManager.rotate(160, 1F, 0F, 0F); GlStateManager.rotate(10, 0F, 1F, 0F); GlStateManager.scale(-scale, scale, scale); ClientProxy.gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, stack); RenderHelper.disableStandardItemLighting(); GlStateManager.popMatrix(); } } } protected void DrawRankIcon(int rank, int prestige, int x, int y, boolean doubleSize) { mc.renderEngine.bindTexture(ranks); if(doubleSize) { drawModalRectWithCustomSizedTexture(guiOriginX + x, guiOriginY + y, rank * 32, prestige * 32, 32, 32, 1024, 512); } else drawModalRectWithCustomSizedTexture(guiOriginX + x, guiOriginY + y, rank * 16, prestige * 16, 16, 16, 512, 256); } /** * Item stack renderering method */ protected void drawSlotInventory(ItemStack itemstack, int i, int j) { if(itemstack == null || itemstack.isEmpty()) return; itemRenderer.renderItemIntoGUI(itemstack, i, j); itemRenderer.renderItemOverlayIntoGUI(fontRenderer, itemstack, i, j, null); } @Override public boolean doesGuiPauseGame() { return false; } @Override protected void keyTyped(char typedChar, int keyCode) throws IOException { if(AllowEscape()) { super.keyTyped(typedChar, keyCode); } } protected boolean AllowEscape() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/gui/teams/GuiVoting.java ================================================ package com.flansmod.client.gui.teams; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ResourceLocation; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.network.PacketVoteCast; public class GuiVoting extends GuiScreen { public static final ResourceLocation texture = new ResourceLocation("flansmod", "gui/vote.png"); public static int myVote = 0; private int guiHeight; public GuiVoting() { myVote = 0; } @Override public void initGui() { super.initGui(); this.buttonList.clear(); guiHeight = 29 + ClientTeamsData.roundFinishedData.votingOptions.length * 24; //Add buttons for(int i = 0; i < ClientTeamsData.roundFinishedData.votingOptions.length; i++) { buttonList.add(new GuiButton(i, width / 2 + 128 - 50, height / 2 - guiHeight / 2 + 24 + 24 * i, 40, 20, "Vote")); } } @Override protected void actionPerformed(GuiButton button) { myVote = button.id + 1; FlansMod.getPacketHandler().sendToServer(new PacketVoteCast(myVote)); } @Override public void drawScreen(int i, int j, float f) { ScaledResolution scaledresolution = new ScaledResolution(mc); int k = scaledresolution.getScaledWidth(); int l = scaledresolution.getScaledHeight(); FontRenderer fontrenderer = mc.fontRenderer; drawDefaultBackground(); GlStateManager.enableBlend(); mc.renderEngine.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); int m = k / 2 - 128; int n = l / 2 - guiHeight / 2; drawTexturedModalRect(m, n, 0, 0, 256, 22); for(int p = 0; p < ClientTeamsData.roundFinishedData.votingOptions.length; p++) drawTexturedModalRect(m, n + 22 + 24 * p, 0, 23, 256, 24); drawTexturedModalRect(m, l / 2 + guiHeight / 2 - 6, 0, 73, 256, 7); drawString(fontRenderer, "Vote for the Next Round", m + 8, n + 8, 0xffffff); drawString(fontRenderer, (ClientTeamsData.timeLeftTotal / 20) + "", m + 256 - 20, n + 8, 0xffffff); for(int p = 0; p < ClientTeamsData.roundFinishedData.votingOptions.length; p++) { drawString(fontRenderer, ClientTeamsData.roundFinishedData.votingOptions[p].mapName, m + 10, n + 25 + 24 * p, 0xffffff); drawString(fontRenderer, ClientTeamsData.roundFinishedData.votingOptions[p].gametype + " : \u00a7" + ClientTeamsData.roundFinishedData.votingOptions[p].teamNames[0] + ", \u00a7" + ClientTeamsData.roundFinishedData.votingOptions[p].teamNames[1], m + 10, n + 35 + 24 * p, 0xffffff); drawCenteredString(fontRenderer, (myVote == p + 1 ? "\u00a72" : "") + ClientTeamsData.roundFinishedData.votingOptions[p].numVotes, m + 196, n + 31 + 24 * p, 0xffffff); } super.drawScreen(i, j, f); } @Override public boolean doesGuiPauseGame() { return false; } } ================================================ FILE: src/main/java/com/flansmod/client/handlers/ClientEventHandler.java ================================================ package com.flansmod.client.handlers; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.client.event.EntityViewRenderEvent.CameraSetup; import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderItemInFrameEvent; import net.minecraftforge.client.event.RenderLivingEvent; import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.event.RenderSpecificHandEvent; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.ClientRenderHooks; import com.flansmod.client.FlansModClient; import com.flansmod.client.model.InstantBulletRenderer; import com.flansmod.client.model.RenderFlag; import com.flansmod.client.model.RenderGun; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.ItemGun; /** * All handled events for the client should go through here and be passed on, this makes it easier to see which events * are being handled by the mod */ @SideOnly(Side.CLIENT) public class ClientEventHandler { private KeyInputHandler keyInputHandler = new KeyInputHandler(); private MouseInputHandler mouseInputHandler = new MouseInputHandler(); private ClientRenderHooks renderHooks = new ClientRenderHooks(); @SubscribeEvent public void renderTick(TickEvent.RenderTickEvent event) { switch(event.phase) { case START: { RenderGun.smoothing = event.renderTickTime; FlansModClient.updateCameraZoom(event.renderTickTime); renderHooks.setPartialTick(event.renderTickTime); renderHooks.updatePlayerView(); break; } case END: { break; } } } @SubscribeEvent @SideOnly(Side.CLIENT) public void clientTick(TickEvent.ClientTickEvent event) { switch(event.phase) { case START: { //Handle all packets received since last tick FlansMod.getPacketHandler().handleClientPackets(); FlansModClient.updateFlashlights(Minecraft.getMinecraft()); break; } case END: { InstantBulletRenderer.UpdateAllTrails(); renderHooks.update(); RenderFlag.angle += 2F; FlansModClient.tick(); keyInputHandler.checkTickKeys(); break; } } } @SubscribeEvent public void chatMessage(ClientChatReceivedEvent event) { if(event.getMessage().getUnformattedText().equals("#flansmod")) { event.setCanceled(true); } } @SideOnly(Side.CLIENT) @SubscribeEvent public void checkMouseInput(MouseEvent event) { mouseInputHandler.checkMouseInput(event); EntityPlayer player = Minecraft.getMinecraft().player; if(player.getHeldItemMainhand().getItem() instanceof ItemGun) { if(((ItemGun)player.getHeldItemMainhand().getItem()).GetType().oneHanded && Minecraft.getMinecraft().gameSettings.keyBindSneak.isKeyDown() && Math.abs(event.getDwheel()) > 0) event.setCanceled(true); } } @SideOnly(Side.CLIENT) @SubscribeEvent public void onKeyInput(InputEvent.KeyInputEvent event) { keyInputHandler.checkEventKeys(); } @SubscribeEvent public void renderWorld(RenderWorldLastEvent event) { InstantBulletRenderer.RenderAllTrails(event.getPartialTicks()); } // ---------------------------------------- // Lots of events for the ClientRenderHooks // ---------------------------------------- @SubscribeEvent public void renderItemFrame(RenderItemInFrameEvent event) { renderHooks.renderItemFrame(event); } @SubscribeEvent public void renderHeldItem(RenderSpecificHandEvent event) { renderHooks.renderHeldItem(event); } @SubscribeEvent public void renderThirdPersonWeapons(RenderLivingEvent.Pre event) { renderHooks.renderThirdPersonWeapons(event); } @SubscribeEvent public void renderPlayer(RenderPlayerEvent.Pre event) { renderHooks.renderPlayer(event); } @SubscribeEvent public void cameraSetup(CameraSetup event) { renderHooks.cameraSetup(event); } @SubscribeEvent public void ModifyHUD(RenderGameOverlayEvent event) { renderHooks.modifyHUD(event); } } ================================================ FILE: src/main/java/com/flansmod/client/handlers/FlansModResourceHandler.java ================================================ package com.flansmod.client.handlers; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.HashMap; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.types.InfoType; public class FlansModResourceHandler { private static HashMap iconMap = new HashMap<>(); private static HashMap textureMap = new HashMap<>(); private static HashMap trailTextureMap = new HashMap<>(); private static HashMap paintjobMap = new HashMap<>(); private static HashMap paintjobIconMap = new HashMap<>(); private static HashMap scopeMap = new HashMap<>(); private static HashMap soundMap = new HashMap<>(); private static HashMap blockMap = new HashMap<>(); public static ResourceLocation flag = new ResourceLocation("flansmod", "textures/items/flagpole.png"); public static ResourceLocation[] opStick = new ResourceLocation[]{new ResourceLocation("flansmod", "textures/items/opStick_ownership.png"), new ResourceLocation("flansmod", "textures/items/opStick_connecting.png"), new ResourceLocation("flansmod", "textures/items/opStick_mapping.png"), new ResourceLocation("flansmod", "textures/items/opStick_destruction.png")}; public static ResourceLocation getIcon(InfoType infoType) { if(iconMap.containsKey(infoType)) { return iconMap.get(infoType); } ResourceLocation resLoc = new ResourceLocation("flansmod", "textures/items/" + infoType.iconPath + ".png"); iconMap.put(infoType, resLoc); return resLoc; } public static ResourceLocation getTexture(InfoType infoType) { if(textureMap.containsKey(infoType)) { return textureMap.get(infoType); } ResourceLocation resLoc = new ResourceLocation("flansmod", "skins/" + infoType.texture + ".png"); if(infoType.texture != null) { textureMap.put(infoType, resLoc); return resLoc; } else return null; } public static ResourceLocation getDeployableTexture(GunType gunType) { if(textureMap.containsKey(gunType)) { return textureMap.get(gunType); } ResourceLocation resLoc = new ResourceLocation("flansmod", "skins/" + gunType.deployableTexture + ".png"); textureMap.put(gunType, resLoc); return resLoc; } public static ResourceLocation getScope(String scopeTexture) { if(scopeMap.containsKey(scopeTexture)) { return scopeMap.get(scopeTexture); } ResourceLocation resLoc = new ResourceLocation("flansmod", "gui/" + scopeTexture + ".png"); scopeMap.put(scopeTexture, resLoc); return resLoc; } public static SoundEvent getSoundEvent(String sound) { if(soundMap.containsKey(sound)) { return soundMap.get(sound); } ResourceLocation resLoc = new ResourceLocation("flansmod", sound); SoundEvent event = new SoundEvent(resLoc); event.setRegistryName(sound); soundMap.put(sound, event); return event; } public static ResourceLocation getPaintjobTexture(Paintjob paintjob) { if(paintjobMap.containsKey(paintjob)) { return paintjobMap.get(paintjob); } ResourceLocation resLoc = new ResourceLocation("flansmod", "skins/" + paintjob.textureName + ".png"); paintjobMap.put(paintjob, resLoc); return resLoc; } public static ResourceLocation getBlockTexture(String texturePath) { if(blockMap.containsKey(texturePath)) { return blockMap.get(texturePath); } ResourceLocation resLoc = new ResourceLocation("flansmod", "blocks/" + texturePath); blockMap.put(texturePath, resLoc); return resLoc; } public static ResourceLocation getIcon(PaintableType paintableType, Paintjob paintjob) { if(paintjobIconMap.containsKey(paintjob)) { return paintjobIconMap.get(paintjob); } ResourceLocation resLoc = new ResourceLocation("flansmod", "textures/items/" + paintjob.iconName + ".png"); paintjobIconMap.put(paintjob, resLoc); return resLoc; } public static ResourceLocation getTrailTexture(String trailTexture) { if(trailTextureMap.containsKey(trailTexture)) { return trailTextureMap.get(trailTexture); } ResourceLocation resLoc = new ResourceLocation("flansmod", "skins/" + trailTexture + ".png"); trailTextureMap.put(trailTexture, resLoc); return resLoc; } private static HashMap customPaintjobSkins = new HashMap<>(); private static HashMap customPaintjobIcons = new HashMap<>(); private static final int BYTES_PER_PIXEL = 4; public static boolean HasResourceForHash(int customPaintHash) { return customPaintjobSkins.containsKey(customPaintHash) && customPaintjobIcons.containsKey(customPaintHash); } public static void CreateSkinResourceFromByteArray(byte[] byteArray, int textureWidth, int textureHeight, int customPaintHash) { String internalLocation = "skins/skin_" + customPaintHash + ".png"; String fileLocation = "Flan/Customs/assets/flansmod/" + internalLocation; try { DataBuffer buffer = new DataBufferByte(byteArray, byteArray.length); WritableRaster raster = Raster.createInterleavedRaster(buffer, textureWidth, textureHeight, BYTES_PER_PIXEL * textureWidth, BYTES_PER_PIXEL, new int[]{0, 1, 2}, null); ColorModel cm = new ComponentColorModel(ColorModel.getRGBdefault().getColorSpace(), false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); BufferedImage image = new BufferedImage(cm, raster, true, null); File file = new File(fileLocation); if(!file.exists()) { file.mkdirs(); file.createNewFile(); } ImageIO.write(image, "png", file); customPaintjobSkins.put(customPaintHash, new ResourceLocation("flansmod", internalLocation)); } catch(IOException e) { FlansMod.log.error("Failed to create custom skin!"); return; } } public static void CreateIconResourceFromByteArray(byte[] byteArray, int textureWidth, int textureHeight, int customPaintHash) { String location = "customs/icon_" + customPaintHash + ".png"; try { DataBuffer buffer = new DataBufferByte(byteArray, byteArray.length); WritableRaster raster = Raster.createInterleavedRaster(buffer, textureWidth, textureHeight, BYTES_PER_PIXEL * textureWidth, BYTES_PER_PIXEL, new int[]{0, 1, 2, 3}, null); ColorModel cm = new ComponentColorModel(ColorModel.getRGBdefault().getColorSpace(), false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); BufferedImage image = new BufferedImage(cm, raster, true, null); ImageIO.write(image, "png", new File(location)); customPaintjobIcons.put(customPaintHash, new ResourceLocation("flansmod", location)); } catch(IOException e) { FlansMod.log.error("Failed to create custom icon!"); return; } } public static ResourceLocation GetSkinResourceFromHash(int customPaintHash) { return customPaintjobSkins.get(customPaintHash); } public static ResourceLocation GetIconResourceFromHash(int customPaintHash) { return customPaintjobIcons.get(customPaintHash); } } ================================================ FILE: src/main/java/com/flansmod/client/handlers/KeyInputHandler.java ================================================ package com.flansmod.client.handlers; import org.lwjgl.input.Keyboard; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiChat; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraftforge.client.settings.KeyConflictContext; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.client.FlansModClient; import com.flansmod.client.gui.teams.GuiLandingPage; import com.flansmod.client.gui.teams.GuiTeamScores; import com.flansmod.client.model.GunAnimations; import com.flansmod.client.model.GunAnimations.LookAtState; import com.flansmod.client.util.FlansKeyConflictContext; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.enchantments.EnchantmentModule; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.network.PacketReload; import com.flansmod.common.network.PacketRequestDebug; @SideOnly(value = Side.CLIENT) public class KeyInputHandler { public static KeyBinding downKey = new KeyBinding("key.pitchDown.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_LCONTROL, "key.flansmod.category"); public static KeyBinding vehicleMenuKey = new KeyBinding("key.vehicleMenu.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_M, "key.flansmod.category"); public static KeyBinding bombKey = new KeyBinding("key.dropBomb.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_B, "key.flansmod.category"); public static KeyBinding gunKey = new KeyBinding("key.fireVehicleGuns.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_V, "key.flansmod.category"); public static KeyBinding controlSwitchKey = new KeyBinding("key.switchControlMode.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_C, "key.flansmod.category"); public static KeyBinding reloadKey = new KeyBinding("key.reload.desc", FlansKeyConflictContext.GUN, Keyboard.KEY_R, "key.flansmod.category"); public static KeyBinding teamsMenuKey = new KeyBinding("key.teamsMenu.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_G, "key.flansmod.category"); public static KeyBinding teamsScoresKey = new KeyBinding("key.teamsScores.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_H, "key.flansmod.category"); public static KeyBinding leftRollKey = new KeyBinding("key.rollLeft.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_Z, "key.flansmod.category"); public static KeyBinding rightRollKey = new KeyBinding("key.rollRight.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_X, "key.flansmod.category"); public static KeyBinding gearKey = new KeyBinding("key.toggleLandingGear.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_L, "key.flansmod.category"); public static KeyBinding doorKey = new KeyBinding("key.toggleDoors.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_K, "key.flansmod.category"); public static KeyBinding modeKey = new KeyBinding("key.switchMovementMode.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_J, "key.flansmod.category"); public static KeyBinding lookAtGunKey = new KeyBinding("key.lookAtGun.desc", FlansKeyConflictContext.GUN, Keyboard.KEY_L, "key.flansmod.category"); public static KeyBinding debugKey = new KeyBinding("key.debug.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_F10, "key.flansmod.category"); public static KeyBinding reloadModelsKey = new KeyBinding("key.reloadModels.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_F9, "key.flansmod.category"); public static KeyBinding toggleCameraPerspective = new KeyBinding("key.toggleCameraPerspective.desc", FlansKeyConflictContext.VEHICLE, Keyboard.KEY_F5, "key.flansmod.category"); public static KeyBinding primaryVehicleInteract = new KeyBinding("key.primaryVehicleInteract.desc", FlansKeyConflictContext.VEHICLE, Minecraft.getMinecraft().gameSettings.keyBindAttack.getKeyCode(), "key.flansmod.category"); public static KeyBinding secondaryVehicleInteract = new KeyBinding("key.secondaryVehicleInteract.desc", FlansKeyConflictContext.VEHICLE, Minecraft.getMinecraft().gameSettings.keyBindUseItem.getKeyCode(), "key.flansmod.category"); private Minecraft mc; KeyInputHandler() { ClientRegistry.registerKeyBinding(downKey); ClientRegistry.registerKeyBinding(vehicleMenuKey); ClientRegistry.registerKeyBinding(bombKey); ClientRegistry.registerKeyBinding(gunKey); ClientRegistry.registerKeyBinding(controlSwitchKey); ClientRegistry.registerKeyBinding(reloadKey); ClientRegistry.registerKeyBinding(teamsMenuKey); ClientRegistry.registerKeyBinding(teamsScoresKey); ClientRegistry.registerKeyBinding(leftRollKey); ClientRegistry.registerKeyBinding(rightRollKey); ClientRegistry.registerKeyBinding(gearKey); ClientRegistry.registerKeyBinding(doorKey); ClientRegistry.registerKeyBinding(modeKey); ClientRegistry.registerKeyBinding(lookAtGunKey); ClientRegistry.registerKeyBinding(debugKey); ClientRegistry.registerKeyBinding(reloadModelsKey); ClientRegistry.registerKeyBinding(primaryVehicleInteract); ClientRegistry.registerKeyBinding(secondaryVehicleInteract); mc = Minecraft.getMinecraft(); } void checkTickKeys() { EntityPlayer player = mc.player; if(player == null) { return; } Entity ridingEntity = player.getRidingEntity(); if(ridingEntity instanceof IControllable) { IControllable controllable = (IControllable)ridingEntity; if(mc.gameSettings.keyBindForward.isKeyDown()) controllable.pressKey(0, player, false); if(mc.gameSettings.keyBindBack.isKeyDown()) controllable.pressKey(1, player, false); if(mc.gameSettings.keyBindLeft.isKeyDown()) controllable.pressKey(2, player, false); if(mc.gameSettings.keyBindRight.isKeyDown()) controllable.pressKey(3, player, false); if(mc.gameSettings.keyBindJump.isKeyDown()) controllable.pressKey(4, player, false); if(downKey.isKeyDown()) controllable.pressKey(5, player, false); if(secondaryVehicleInteract.isKeyDown()) controllable.pressKey(8, player, false); if(primaryVehicleInteract.isKeyDown()) controllable.pressKey(9, player, false); if(leftRollKey.isKeyDown()) controllable.pressKey(11, player, false); if(rightRollKey.isKeyDown()) controllable.pressKey(12, player, false); } } void checkEventKeys() { if(FMLClientHandler.instance().isGUIOpen(GuiChat.class) || mc.currentScreen != null) return; EntityPlayer player = mc.player; if(teamsMenuKey.isPressed()) { mc.displayGuiScreen(new GuiLandingPage()); return; } if(teamsScoresKey.isPressed()) { mc.displayGuiScreen(new GuiTeamScores()); return; } if(reloadKey.isPressed()) { PlayerData data = PlayerHandler.getPlayerData(player, Side.CLIENT); ItemStack stack = player.getHeldItemMainhand(); if(data.shootTimeRight <= 0.0f) { if(stack.getItem() instanceof ItemGun) { ItemGun item = (ItemGun)stack.getItem(); GunType type = item.GetType(); if(item.CanReload(stack, player.inventory)) { FlansMod.getPacketHandler().sendToServer(new PacketReload(EnumHand.MAIN_HAND, true)); // Set player shoot delay to be the reload delay // Set both gun delays to avoid reloading two guns at once data.shootTimeRight = data.shootTimeLeft = (int)type.getReloadTime(stack); float reloadDelay = EnchantmentModule.ModifyReloadTime(type.reloadTime, player, player.getHeldItemOffhand()); GunAnimations animations = FlansModClient.getGunAnimations(player, EnumHand.MAIN_HAND); int pumpDelay = type.model == null ? 0 : type.model.pumpDelayAfterReload; int pumpTime = type.model == null ? 1 : type.model.pumpTime; animations.doReload(type.reloadTime, pumpDelay, pumpTime); data.reloadingRight = true; data.burstRoundsRemainingRight = 0; } } } return; } if(lookAtGunKey.isPressed()) { FlansModClient.getGunAnimations(mc.player, EnumHand.MAIN_HAND).lookAt = LookAtState.TILT1; FlansModClient.getGunAnimations(mc.player, EnumHand.OFF_HAND).lookAt = LookAtState.TILT1; return; } if(debugKey.isPressed()) { if(FlansMod.DEBUG) FlansMod.DEBUG = false; else { FlansMod.packetHandler.sendToServer(new PacketRequestDebug()); } return; } if(reloadModelsKey.isPressed()) { FlansModClient.reloadModels(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)); return; } if(player == null) { return; } Entity ridingEntity = player.getRidingEntity(); if(ridingEntity instanceof IControllable) { IControllable controllable = (IControllable)ridingEntity; if(mc.gameSettings.keyBindSneak.isPressed()) controllable.pressKey(6, player, true); if(vehicleMenuKey.isPressed()) controllable.pressKey(7, player, true); if(primaryVehicleInteract.isPressed()) controllable.pressKey(9, player, true); if(secondaryVehicleInteract.isPressed()) controllable.pressKey(8, player, true); if(controlSwitchKey.isPressed()) controllable.pressKey(10, player, true); if(gearKey.isPressed()) controllable.pressKey(13, player, true); if(doorKey.isPressed()) controllable.pressKey(14, player, true); if(modeKey.isPressed()) controllable.pressKey(15, player, true); if(toggleCameraPerspective.isKeyDown()) controllable.pressKey(18, player, true); } } } ================================================ FILE: src/main/java/com/flansmod/client/handlers/MouseInputHandler.java ================================================ package com.flansmod.client.handlers; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.client.event.MouseEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; @SideOnly(Side.CLIENT) public class MouseInputHandler { private Minecraft mc; public MouseInputHandler() { mc = Minecraft.getMinecraft(); } public void checkMouseInput(MouseEvent event) { if(mc.currentScreen != null) { return; } //Handle driving controls EntityPlayer player = mc.player; Entity ridingEntity = player.getRidingEntity(); if(ridingEntity instanceof IControllable) { IControllable riding = (IControllable)ridingEntity; riding.onMouseMoved(event.getDx(), event.getDy()); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/AnimTankTrack.java ================================================ package com.flansmod.client.model; import java.util.ArrayList; import com.flansmod.common.vector.Vector3f; public class AnimTankTrack { public ArrayList points; public float trackLinkLength; public AnimTankTrack(ArrayList trackPoints, float linkLength) { points = trackPoints; trackLinkLength = linkLength; } public void setLinkLength(float length) { trackLinkLength = length; } public float distBetweenPoints(Vector3f p1, Vector3f p2) { float distance; float x = p1.x - p2.x; float y = p1.y - p2.y; distance = (float)Math.sqrt((x * x) + (y * y)); return distance; } public float getTrackLength() { float length = 0; for(int i = 0; i < points.size(); i++) { length += distBetweenPoints(points.get(i), points.get((i == 0) ? points.size() - 1 : i - 1)); } return length; } public int getTrackPart(float distance) { float length = 0; for(int i = 0; i < points.size(); i++) { if(length >= distance) { return i; } else { length += distBetweenPoints(points.get(i), points.get((i == (points.size() - 1)) ? 0 : i + 1)); } } return 0; } public float getProgressAlongTrackPart(float distance, int trackPart) { float length = 0; for(int i = 0; i < trackPart + 1; i++) { if(i != 0) { length += distBetweenPoints(points.get(i - 1), points.get(i)); } } return length; } public Vector3f getPositionOnTrack(float distance) { int trackPart = getTrackPart(distance); Vector3f p2 = points.get((trackPart == 0) ? points.size() - 1 : trackPart - 1); Vector3f p1 = points.get(trackPart); float partLength = distBetweenPoints(p2, p1); float prog = distance - (getProgressAlongTrackPart(distance, (trackPart == 0) ? points.size() - 1 : trackPart - 1)); float progress = prog / partLength; return new Vector3f(lerp(p2.x, p1.x, progress), lerp(p2.y, p1.y, progress), lerp(p2.z, p1.z, progress)); } public float lerp(float a, float b, float f) { return (a + f * (b - a)); } } ================================================ FILE: src/main/java/com/flansmod/client/model/AnimTrackLink.java ================================================ package com.flansmod.client.model; import com.flansmod.common.RotatedAxes; import com.flansmod.common.vector.Vector3f; public class AnimTrackLink { public Vector3f position; public Vector3f prevPosition; public float zRot = 0; public float prevZRot; public float progress; public RotatedAxes rot; public AnimTrackLink(float prog) { progress = prog; } } ================================================ FILE: src/main/java/com/flansmod/client/model/CustomItemRenderType.java ================================================ package com.flansmod.client.model; public enum CustomItemRenderType { ENTITY, EQUIPPED, EQUIPPED_FIRST_PERSON, INVENTORY, } ================================================ FILE: src/main/java/com/flansmod/client/model/CustomItemRenderer.java ================================================ package com.flansmod.client.model; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; public interface CustomItemRenderer { void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data); } ================================================ FILE: src/main/java/com/flansmod/client/model/EnumAnimationType.java ================================================ package com.flansmod.client.model; public enum EnumAnimationType { NONE, BOTTOM_CLIP, PISTOL_CLIP, TOP_CLIP, SIDE_CLIP, P90, SHOTGUN, RIFLE, REVOLVER, END_LOADED, RIFLE_TOP, BULLPUP, ALT_PISTOL_CLIP, GENERIC, BACK_LOADED, STRIKER, BREAK_ACTION, CUSTOM } ================================================ FILE: src/main/java/com/flansmod/client/model/EnumMeleeAnimation.java ================================================ package com.flansmod.client.model; public enum EnumMeleeAnimation { DEFAULT, NONE, BLUNT_SWING, BLUNT_BASH, STAB_UNDERARM, STAB_OVERARM } ================================================ FILE: src/main/java/com/flansmod/client/model/GunAnimations.java ================================================ package com.flansmod.client.model; import java.util.Random; import com.flansmod.common.vector.Vector3f; public class GunAnimations { public static GunAnimations defaults = new GunAnimations(); /** (Purely aesthetic) gun animation variables */ /** * Slide */ public float gunSlide = 0F, lastGunSlide = 0F; /** * Delayed Reload Animations */ public int timeUntilPump = 0, timeToPumpFor = 0; /** * Delayed Reload Animations : -1, 1 = At rest, 0 = Mid Animation */ public float pumped = -1F, lastPumped = -1F; /** * Delayed Reload Animations : Doing the delayed animation */ public boolean pumping = false; public int muzzleFlash = 0; public boolean reloading = false; public float reloadAnimationTime = 0; public float reloadAnimationProgress = 0F, lastReloadAnimationProgress = 0F; public float minigunBarrelRotation = 0F; public float minigunBarrelRotationSpeed = 0F; /** * Melee animations */ public int meleeAnimationProgress = 0, meleeAnimationLength = 0; public float recoil = 0.0f, antiRecoil = 0.0f, recoilAngle = 0.0f; public Vector3f recoilOffset = new Vector3f(), recoilVelocity = new Vector3f(); public Random random = new Random(); public LookAtState lookAt = LookAtState.NONE; public float lookAtTimer = 0; public static final int[] lookAtTimes = new int[]{1, 10, 20, 10, 20, 10}; public enum LookAtState { NONE, TILT1, LOOK1, TILT2, LOOK2, UNTILT } public GunAnimations() { } public void update() { lastPumped = pumped; muzzleFlash--; if(timeUntilPump > 0) { timeUntilPump--; if(timeUntilPump == 0) { //Pump it! pumping = true; lastPumped = pumped = -1F; } } if(pumping) { pumped += 2F / timeToPumpFor; if(pumped >= 0.999F) pumping = false; } lastGunSlide = gunSlide; if(gunSlide > 0) gunSlide *= 0.4F; lastReloadAnimationProgress = reloadAnimationProgress; if(reloading) reloadAnimationProgress += 1F / reloadAnimationTime; if(reloading && reloadAnimationProgress >= 1F) reloading = false; //TODO cycle after one rotation minigunBarrelRotation += minigunBarrelRotationSpeed; minigunBarrelRotationSpeed *= 0.9F; if(meleeAnimationLength > 0) { meleeAnimationProgress++; //If we are done, reset if(meleeAnimationProgress == meleeAnimationLength) meleeAnimationProgress = meleeAnimationLength = 0; } float scale = 0.5f; float offsetScale = 0.005f; if(recoil > 0) recoil *= 0.5F; recoilVelocity.x += (random.nextGaussian() - 0.5f) * recoil * offsetScale; recoilVelocity.y += (random.nextGaussian() - 0.5f) * recoil * offsetScale; recoilVelocity.z += (random.nextGaussian() - 0.25f) * recoil * offsetScale; recoilVelocity.scale(0.5f); Vector3f.add(recoilOffset, recoilVelocity, recoilOffset); recoilOffset.scale(0.9f); recoilAngle -= recoil * scale; antiRecoil += recoil; recoilAngle += antiRecoil * 0.2f * scale; antiRecoil *= 0.8F; switch(lookAt) { case NONE: lookAtTimer = 0; break; case TILT1: case LOOK1: case TILT2: case LOOK2: case UNTILT: { lookAtTimer++; if(lookAtTimer >= lookAtTimes[lookAt.ordinal()]) { lookAt = LookAtState.values()[(lookAt.ordinal() + 1) % LookAtState.values().length]; lookAtTimer = 0; } break; } default: break; } } public void addMinigunBarrelRotationSpeed(Float speed) { minigunBarrelRotationSpeed += speed; } public void doShoot(int pumpDelay, int pumpTime) { lastGunSlide = gunSlide = 1F; timeUntilPump = pumpDelay; timeToPumpFor = pumpTime; muzzleFlash = 2; } public void doReload(int reloadTime, int pumpDelay, int pumpTime) { reloading = true; lastReloadAnimationProgress = reloadAnimationProgress = 0F; reloadAnimationTime = reloadTime; timeUntilPump = pumpDelay; timeToPumpFor = pumpTime; } public void doMelee(int meleeTime) { meleeAnimationLength = meleeTime; } } ================================================ FILE: src/main/java/com/flansmod/client/model/InstantBulletRenderer.java ================================================ package com.flansmod.client.model; import java.util.ArrayList; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.util.WorldRenderer; import com.flansmod.common.vector.Vector3f; public class InstantBulletRenderer { private static TextureManager textureManager; private static ArrayList trails = new ArrayList<>(); public static void AddTrail(InstantShotTrail trail) { trails.add(trail); } public static void RenderAllTrails(float partialTicks) { for(InstantShotTrail trail : trails) { trail.Render(partialTicks); } } public static void UpdateAllTrails() { for(int i = trails.size() - 1; i >= 0; i--) { if(trails.get(i).Update()) { trails.remove(i); } } } public static class InstantShotTrail { private Vector3f origin; private Vector3f hitPos; private float width; private float length; private float distanceToTarget; private float bulletSpeed; private int ticksExisted; private ResourceLocation texture; public InstantShotTrail(Vector3f origin, Vector3f hitPos, float width, float length, float bulletSpeed, String trailTexture) { this.origin = origin; this.hitPos = hitPos; this.width = width; this.length = length; this.bulletSpeed = bulletSpeed; this.ticksExisted = 0; this.texture = FlansModResourceHandler.getTrailTexture(trailTexture); Vector3f dPos = Vector3f.sub(hitPos, origin, null); this.distanceToTarget = dPos.length(); if(Math.abs(distanceToTarget) > 300.0f) { distanceToTarget = 300.0f; } } // Return true if this needs deleting public boolean Update() { ticksExisted++; return (ticksExisted) * bulletSpeed >= distanceToTarget - length; } public void Render(float partialTicks) { //Make sure we actually have the renderEngine if(textureManager == null) textureManager = Minecraft.getMinecraft().renderEngine; textureManager.bindTexture(texture); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.pushMatrix(); //Get the camera frustrum for clipping Entity camera = Minecraft.getMinecraft().getRenderViewEntity(); double x = camera.lastTickPosX + (camera.posX - camera.lastTickPosX) * partialTicks; double y = camera.lastTickPosY + (camera.posY - camera.lastTickPosY) * partialTicks; double z = camera.lastTickPosZ + (camera.posZ - camera.lastTickPosZ) * partialTicks; GlStateManager.translate(-(float)x, -(float)y, -(float)z); float parametric = ((float)(ticksExisted) + partialTicks) * bulletSpeed; Vector3f dPos = Vector3f.sub(hitPos, origin, null); dPos.normalise(); float startParametric = parametric - length * 0.5f; Vector3f startPos = new Vector3f(origin.x + dPos.x * startParametric, origin.y + dPos.y * startParametric, origin.z + dPos.z * startParametric); float endParametric = parametric + length * 0.5f; Vector3f endPos = new Vector3f(origin.x + dPos.x * endParametric, origin.y + dPos.y * endParametric, origin.z + dPos.z * endParametric); WorldRenderer worldrenderer = FlansModClient.getWorldRenderer(); dPos.normalise(); EntityPlayer player = Minecraft.getMinecraft().player; Vector3f vectorToPlayer = new Vector3f(player.posX - hitPos.x, player.posY - hitPos.y, player.posZ - hitPos.z); vectorToPlayer.normalise(); Vector3f trailTangent = Vector3f.cross(dPos, vectorToPlayer, null); trailTangent.normalise(); trailTangent.scale(-width * 0.5f); Vector3f normal = Vector3f.cross(trailTangent, dPos, null); normal.normalise(); GlStateManager.enableRescaleNormal(); GlStateManager.glNormal3f(normal.x, normal.y, normal.z); worldrenderer.startDrawingQuads(); worldrenderer.addVertexWithUV(startPos.x + trailTangent.x, startPos.y + trailTangent.y, startPos.z + trailTangent.z, 0.0f, 0.0f); worldrenderer.addVertexWithUV(startPos.x - trailTangent.x, startPos.y - trailTangent.y, startPos.z - trailTangent.z, 0.0f, 1.0f); worldrenderer.addVertexWithUV(endPos.x - trailTangent.x, endPos.y - trailTangent.y, endPos.z - trailTangent.z, 1.0f, 1.0f); worldrenderer.addVertexWithUV(endPos.x + trailTangent.x, endPos.y + trailTangent.y, endPos.z + trailTangent.z, 1.0f, 0.0f); // worldrenderer.addVertexWithUV(endPos.x + trailTangent.x*10, endPos.y + trailTangent.y*10, endPos.z + trailTangent.z*10, 1.0f, 0.0f); worldrenderer.draw(); GlStateManager.disableRescaleNormal(); GlStateManager.popMatrix(); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelAAGun.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.guns.EntityAAGun; public class ModelAAGun extends ModelBase { public boolean oldModel = false; public void renderBase(float f, float f1, float f2, float f3, float f4, float f5, EntityAAGun aa) { for(ModelRendererTurbo aBaseModel : baseModel) { aBaseModel.render(f5); } } public void renderGun(float f, float f1, float f2, float f3, float f4, float f5, EntityAAGun aa) { for(ModelRendererTurbo aSeatModel : seatModel) { aSeatModel.render(f5); } for(ModelRendererTurbo aGunModel : gunModel) { aGunModel.setPosition(barrelX, barrelY, barrelZ); aGunModel.rotateAngleZ = -aa.gunPitch / 180F * 3.141592653589793238462643383279502884197169399F; aGunModel.render(f5); } for(ModelRendererTurbo aGunsightModel : gunsightModel) { aGunsightModel.rotateAngleZ = -aa.gunPitch / 180F * 3.141592653589793238462643383279502884197169399F; aGunsightModel.render(f5); } for(int i = 0; i < barrelModel.length; i++) { for(int j = 0; j < barrelModel[i].length; j++) { barrelModel[i][j].setPosition(-aa.barrelRecoil[i] * (float)(Math.cos(-aa.gunPitch * 3.14159265358979F / 180F)) + barrelX, -aa.barrelRecoil[i] * (float)(Math.sin(-aa.gunPitch * 3.14159265358979F / 180F)) + barrelY, barrelZ); barrelModel[i][j].rotateAngleZ = -aa.gunPitch / 180F * 3.141592653589793238462643383279502884197169399F; barrelModel[i][j].render(f5); } } for(int i = 0; i < ammoModel.length; i++) { if(aa.ammo[i] != null) { for(int j = 0; j < ammoModel[i].length; j++) { ammoModel[i][j].setPosition(barrelX, barrelY, barrelZ); ammoModel[i][j].rotateAngleZ = -aa.gunPitch / 180F * 3.141592653589793238462643383279502884197169399F; ammoModel[i][j].render(f5); } } } } public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) { } public void flipAll() { for(ModelRendererTurbo aBaseModel : baseModel) { aBaseModel.doMirror(false, true, true); aBaseModel.setRotationPoint(aBaseModel.rotationPointX, -aBaseModel.rotationPointY, -aBaseModel.rotationPointZ); } for(ModelRendererTurbo aSeatModel : seatModel) { aSeatModel.doMirror(false, true, true); aSeatModel.setRotationPoint(aSeatModel.rotationPointX, -aSeatModel.rotationPointY, -aSeatModel.rotationPointZ); } for(ModelRendererTurbo aGunModel : gunModel) { aGunModel.doMirror(false, true, true); aGunModel.setRotationPoint(aGunModel.rotationPointX, -aGunModel.rotationPointY, -aGunModel.rotationPointZ); } for(ModelRendererTurbo aGunsightModel : gunsightModel) { aGunsightModel.doMirror(false, true, true); aGunsightModel.setRotationPoint(aGunsightModel.rotationPointX, -aGunsightModel.rotationPointY, -aGunsightModel.rotationPointZ); } for(ModelRendererTurbo[] aBarrelModel : barrelModel) { for(ModelRendererTurbo anABarrelModel : aBarrelModel) { anABarrelModel.doMirror(false, true, true); anABarrelModel.setRotationPoint(anABarrelModel.rotationPointX, -anABarrelModel.rotationPointY, -anABarrelModel.rotationPointZ); } } for(ModelRendererTurbo[] anAmmoModel : ammoModel) { for(ModelRendererTurbo anAnAmmoModel : anAmmoModel) { anAnAmmoModel.doMirror(false, true, true); anAnAmmoModel.setRotationPoint(anAnAmmoModel.rotationPointX, -anAnAmmoModel.rotationPointY, -anAnAmmoModel.rotationPointZ); } } } public ModelRendererTurbo baseModel[] = new ModelRendererTurbo[0]; //The base which stays put public ModelRendererTurbo seatModel[] = new ModelRendererTurbo[0]; //The bit which swivels around the yaw axis, but which does not pitch public ModelRendererTurbo gunModel[] = new ModelRendererTurbo[0]; //The bit of the gun that points where you look, but doesn't move public ModelRendererTurbo barrelModel[][] = new ModelRendererTurbo[0][0]; //The end of the barrel that recoils public ModelRendererTurbo ammoModel[][] = new ModelRendererTurbo[0][0]; //The magazines for each barrel. public ModelRendererTurbo gunsightModel[] = new ModelRendererTurbo[0]; //The gunsight for the Gun. public int barrelX, barrelY, barrelZ; } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelAttachment.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelAttachment extends ModelBase { public ModelRendererTurbo[] attachmentModel = new ModelRendererTurbo[0]; public Vector3f muzzleFlashPoint = new Vector3f(); /** * For big scopes, so that the player actually looks through them properly */ public float renderOffset = 0F; public void renderAttachment(float f) { for(ModelRendererTurbo model : attachmentModel) if(model != null) model.render(f); } public void flipAll() { for(ModelRendererTurbo anAttachmentModel : attachmentModel) { anAttachmentModel.doMirror(false, true, true); anAttachmentModel.setRotationPoint(anAttachmentModel.rotationPointX, -anAttachmentModel.rotationPointY, -anAttachmentModel.rotationPointZ); } } protected void translate(ModelRendererTurbo[] model, float x, float y, float z) { for(ModelRendererTurbo anAttachmentModel : attachmentModel) { anAttachmentModel.rotationPointX += x; anAttachmentModel.rotationPointY += y; anAttachmentModel.rotationPointZ += z; } } public void translateAll(float x, float y, float z) { translate(attachmentModel, x, y, z); } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelBomb.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import net.minecraft.entity.Entity; import com.flansmod.client.tmt.ModelRendererTurbo; public class ModelBomb extends ModelBase { public ModelBomb() { bombModel = new ModelRendererTurbo[4]; bombModel[0] = new ModelRendererTurbo(this, 104, 0, 128, 64); bombModel[1] = new ModelRendererTurbo(this, 104, 0, 128, 64); bombModel[2] = new ModelRendererTurbo(this, 56, 8, 128, 64); bombModel[3] = new ModelRendererTurbo(this, 56, 8, 128, 64); bombModel[0].addTrapezoid(-2F, 0F, -2F, 4, 1, 4, 0.0F, 1.0F, ModelRendererTurbo.MR_TOP); bombModel[1].addBox(-2F, 1F, -2F, 4, 6, 4, 0.0F); bombModel[2].addTrapezoid(-2F, 7F, -2F, 4, 1, 4, 0.0F, 1.0F, ModelRendererTurbo.MR_BOTTOM); bombModel[3].addBox(-2F, 8F, -2F, 4, 2, 4, 0.0F); } @Override public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { for(int i = 0; i < 4; i++) { bombModel[i].render(f5); } } public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) { } public ModelRendererTurbo bombModel[]; } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelBullet.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.Entity; public class ModelBullet extends ModelBase { public ModelRenderer bulletModel; public ModelBullet() { bulletModel = new ModelRenderer(this, 0, 0); bulletModel.addBox(-0.5F, -1.5F, -0.5F, 1, 3, 1); } @Override public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { GlStateManager.scale(0.5F, 0.5F, 0.5F); bulletModel.render(f5); } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelCustomArmour.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.teams.ArmourType; public class ModelCustomArmour extends ModelBiped { public ArmourType type; public ModelRendererTurbo[] headModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] bodyModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftArmModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightArmModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] skirtFrontModel = new ModelRendererTurbo[0]; //Acts like a leg piece, but its pitch is set to the maximum of the two legs public ModelRendererTurbo[] skirtRearModel = new ModelRendererTurbo[0]; //Acts like a leg piece, but its pitch is set to the minimum of the two legs public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { GlStateManager.pushMatrix(); GlStateManager.scale(type.modelScale, type.modelScale, type.modelScale); isSneak = entity.isSneaking(); ItemStack itemstack = ((EntityLivingBase)entity).getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); rightArmPose = itemstack.isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM; if(!itemstack.isEmpty()) { EnumAction enumaction = itemstack.getItemUseAction(); if(enumaction == EnumAction.BLOCK) { rightArmPose = ArmPose.BLOCK; } else if(enumaction == EnumAction.BOW) { rightArmPose = ArmPose.BOW_AND_ARROW; } } setRotationAngles(f, f1, f2, f3, f4, f5, entity); if(isSneak) { GlStateManager.translate(0.0F, 0.4F, 0.0F); } render(headModel, bipedHead, f5, type.modelScale); render(bodyModel, bipedBody, f5, type.modelScale); render(leftArmModel, bipedLeftArm, f5, type.modelScale); render(rightArmModel, bipedRightArm, f5, type.modelScale); render(leftLegModel, bipedLeftLeg, f5, type.modelScale); render(rightLegModel, bipedRightLeg, f5, type.modelScale); //Skirt front { for(ModelRendererTurbo mod : skirtFrontModel) { mod.rotationPointX = (bipedLeftLeg.rotationPointX + bipedRightLeg.rotationPointX) / 2F / type.modelScale; mod.rotationPointY = (bipedLeftLeg.rotationPointY + bipedRightLeg.rotationPointY) / 2F / type.modelScale; mod.rotationPointZ = (bipedLeftLeg.rotationPointZ + bipedRightLeg.rotationPointZ) / 2F / type.modelScale; mod.rotateAngleX = Math.min(bipedLeftLeg.rotateAngleX, bipedRightLeg.rotateAngleX); mod.rotateAngleY = bipedLeftLeg.rotateAngleY; mod.rotateAngleZ = bipedLeftLeg.rotateAngleZ; mod.render(f5); } } //Skirt back { for(ModelRendererTurbo mod : skirtRearModel) { mod.rotationPointX = (bipedLeftLeg.rotationPointX + bipedRightLeg.rotationPointX) / 2F / type.modelScale; mod.rotationPointY = (bipedLeftLeg.rotationPointY + bipedRightLeg.rotationPointY) / 2F / type.modelScale; mod.rotationPointZ = (bipedLeftLeg.rotationPointZ + bipedRightLeg.rotationPointZ) / 2F / type.modelScale; mod.rotateAngleX = Math.max(bipedLeftLeg.rotateAngleX, bipedRightLeg.rotateAngleX); mod.rotateAngleY = bipedLeftLeg.rotateAngleY; mod.rotateAngleZ = bipedLeftLeg.rotateAngleZ; mod.render(f5); } } GlStateManager.popMatrix(); } public void render(ModelRendererTurbo[] models, ModelRenderer bodyPart, float f5, float scale) { setBodyPart(models, bodyPart, scale); for(ModelRendererTurbo mod : models) { mod.rotateAngleX = bodyPart.rotateAngleX; mod.rotateAngleY = bodyPart.rotateAngleY; mod.rotateAngleZ = bodyPart.rotateAngleZ; mod.render(f5); } } public void setBodyPart(ModelRendererTurbo[] models, ModelRenderer bodyPart, float scale) { for(ModelRendererTurbo mod : models) { mod.rotationPointX = bodyPart.rotationPointX / scale; mod.rotationPointY = bodyPart.rotationPointY / scale; mod.rotationPointZ = bodyPart.rotationPointZ / scale; } } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelDefaultMuzzleFlash.java ================================================ package com.flansmod.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import net.minecraft.client.model.ModelBase; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; public class ModelDefaultMuzzleFlash extends ModelMuzzleFlash { private static final ResourceLocation texture = new ResourceLocation("flansmod", "skins/muzzleflash.png"); public ModelDefaultMuzzleFlash() { mfModel = new ModelRendererTurbo[3]; mfModel[0] = new ModelRendererTurbo(this, 0, 0, 16, 16); mfModel[1] = new ModelRendererTurbo(this, 0, 0, 16, 16); mfModel[2] = new ModelRendererTurbo(this, 0, 8, 16, 16); mfModel[0].addBox(0f, -2f, -2f, 0, 4, 4); mfModel[1].addBox(0f, 0f, -2f, 4, 0, 4); mfModel[2].addBox(0f, -2f, 0f, 4, 4, 0); } @Override public void renderMuzzleFlash(float f5) { for(ModelRendererTurbo mr : mfModel) { mr.render(f5); } } @Override public ResourceLocation GetTexture() { return texture; } public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) { } public ModelRendererTurbo mfModel[]; } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelDriveable.java ================================================ package com.flansmod.client.model; import java.util.HashMap; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.math.AxisAlignedBB; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; public class ModelDriveable extends ModelBase { public static final float pi = 3.14159265F; public static final float tau = 2 * pi; public HashMap gunModels = new HashMap<>(); public ModelRendererTurbo bodyModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo bodyDoorOpenModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo bodyDoorCloseModel[] = new ModelRendererTurbo[0]; /** * Set to true to use the old rotation order (ZYX) rather than (YZX) */ public boolean oldRotateOrder = false; /** * For rendering a specific entity */ public void render(EntityDriveable driveable, float f1) { } /** * For rendering from GUIs */ public void render(DriveableType type) { renderPart(bodyModel); renderPart(bodyDoorCloseModel); for(ModelRendererTurbo[][] gun : gunModels.values()) for(ModelRendererTurbo[] gunPart : gun) renderPart(gunPart); } /** * Renders the specified parts */ public void renderPart(ModelRendererTurbo[] part) { for(ModelRendererTurbo bit : part) { bit.render(0.0625F, oldRotateOrder); } } public void registerGunModel(String name, ModelRendererTurbo[][] gunModel) { gunModels.put(name, gunModel); } protected void flip(ModelRendererTurbo[] model) { for(ModelRendererTurbo part : model) { part.doMirror(false, true, true); part.setRotationPoint(part.rotationPointX, -part.rotationPointY, -part.rotationPointZ); } } public void flipAll() { flip(bodyModel); flip(bodyDoorOpenModel); flip(bodyDoorCloseModel); for(ModelRendererTurbo[][] modsOfMods : gunModels.values()) { for(ModelRendererTurbo[] mods : modsOfMods) { flip(mods); } } } protected void translate(ModelRendererTurbo[] model, float x, float y, float z) { for(ModelRendererTurbo mod : model) { mod.rotationPointX += x; mod.rotationPointY += y; mod.rotationPointZ += z; } } public void translateAll(float x, float y, float z) { translate(bodyModel, x, y, z); translate(bodyDoorOpenModel, x, y, z); translate(bodyDoorCloseModel, x, y, z); for(ModelRendererTurbo[][] modsOfMods : gunModels.values()) { for(ModelRendererTurbo[] mods : modsOfMods) { translate(mods, x, y, z); } } } public void translateAll(int x, int y, int z) { translateAll((float)x, (float)y, (float)z); } /** * Renders a box with the bounds of the AABB trasnlated by an offset. * Copied from Render.class, but without the forced white colour */ public static void renderOffsetAABB(AxisAlignedBB boundingBox, double x, double y, double z) { GlStateManager.disableTexture2D(); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); bufferbuilder.setTranslation(x, y, z); bufferbuilder.begin(7, DefaultVertexFormats.POSITION_NORMAL); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(0.0F, -1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(0.0F, -1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, -1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, -1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 1.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(-1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(-1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(-1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(-1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(1.0F, 0.0F, 0.0F).endVertex(); bufferbuilder.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(1.0F, 0.0F, 0.0F).endVertex(); tessellator.draw(); bufferbuilder.setTranslation(0.0D, 0.0D, 0.0D); GlStateManager.enableTexture2D(); } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelFlagpole.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import com.flansmod.common.teams.EntityFlag; import com.flansmod.common.teams.EntityFlagpole; public class ModelFlagpole extends ModelBase { public ModelFlagpole() { poleModel = new ModelRenderer[3]; poleModel[0] = new ModelRenderer(this, 0, 16); poleModel[1] = new ModelRenderer(this, 0, 16); poleModel[2] = new ModelRenderer(this, 0, 20); poleModel[0].addBox(-48F, -1F, -1F, 24, 2, 2, 0.0F); poleModel[1].addBox(-24F, -1F, -1F, 24, 2, 2, 0.0F); poleModel[2].addBox(-2F, -2F, -2F, 4, 2, 4, 0.0F); poleModel[0].rotateAngleZ = 1.57079633F; poleModel[1].rotateAngleZ = 1.57079633F; flagModel = new ModelRenderer[1]; flagModel[0] = new ModelRenderer(this, 0, 0); flagModel[0].addBox(-8F, -16F, 0F, 16, 16, 0, 0.0F); flagModel[0].setRotationPoint(8F, 0F, 0F); } public void renderPole(float f, float f1, float f2, float f3, float f4, float f5, EntityFlagpole entityflag) { for(ModelRenderer model : poleModel) { model.render(f5); } } public void renderFlag(float f, float f1, float f2, float f3, float f4, float f5, EntityFlag entityflag) { for(ModelRenderer model : flagModel) { model.render(f5); } } public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) { } public ModelRenderer poleModel[]; public ModelRenderer flagModel[]; } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelGun.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelGun extends ModelBase { public static final Vector3f invalid = new Vector3f(0f, Float.MAX_VALUE, 0f); //Shapebox template. For quick copy pasting //, 0F, /* 0 */ 0F, 0F, 0F, /* 1 */ 0F, 0F, 0F, /* 2 */ 0F, 0F, 0F, /* 3 */ 0F, 0F, 0F, /* 4 */ 0F, 0F, 0F, /* 5 */ 0F, 0F, 0F, /* 6 */ 0F, 0F, 0F, /* 7 */ 0F, 0F, 0F); //These first 6 models are static with no animation public ModelRendererTurbo[] gunModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] backpackModel = new ModelRendererTurbo[0]; //For flamethrowers and such like. Rendered on the player's back //These models appear when no attachment exists public ModelRendererTurbo[] defaultBarrelModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] defaultScopeModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] defaultStockModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] defaultGripModel = new ModelRendererTurbo[0]; //Animated models follow. public ModelRendererTurbo[] ammoModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] revolverBarrelModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] breakActionModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] slideModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] pumpModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] minigunBarrelModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leverActionModel = new ModelRendererTurbo[0]; /** * The point about which the minigun barrel rotates. Rotation is along the line of the gun through this point */ public Vector3f minigunBarrelOrigin = new Vector3f(); //These designate the locations of 3D attachment models on the gun public Vector3f barrelAttachPoint = new Vector3f(); public Vector3f scopeAttachPoint = new Vector3f(); public Vector3f stockAttachPoint = new Vector3f(); public Vector3f gripAttachPoint = new Vector3f(); public Vector3f muzzleFlashPoint = invalid; //Various animation parameters public float gunSlideDistance = 1F / 4F; public EnumAnimationType animationType = EnumAnimationType.NONE; public EnumMeleeAnimation meleeAnimation = EnumMeleeAnimation.DEFAULT; public float tiltGunTime = 0.25F, unloadClipTime = 0.25F, loadClipTime = 0.25F, untiltGunTime = 0.25F; /** * If true, then the scope attachment will move with the top slide */ public boolean scopeIsOnSlide = false; /** * If true, then the scope attachment will move with the break action. Can be combined with the above */ public boolean scopeIsOnBreakAction = false; /** * For rifles and shotguns. Currently a generic reload animation regardless of how full the internal magazine already is */ public float numBulletsInReloadAnimation = 1; /** * For shotgun pump handles and rifle bolts */ public int pumpDelay = 0, pumpDelayAfterReload = 0, pumpTime = 1; /** * For shotgun pump handle */ public float pumpHandleDistance = 4F / 16F; /** * For end loaded projectiles */ public float endLoadedAmmoDistance = 1F; /** * If true, then the grip attachment will move with the shotgun pump */ public boolean gripIsOnPump = false; /** * The rotation point for the barrel break */ public Vector3f barrelBreakPoint = new Vector3f(); /** * The amount the revolver barrel flips out by */ public float revolverFlipAngle = 15F; /** * The rotation point for the revolver flip */ public Vector3f revolverFlipPoint = new Vector3f(); /** * The angle the gun is broken by for break actions */ public float breakAngle = 45F; /** * If true, then the gun will perform a spinning reload animation */ public boolean spinningCocking = false; /** * The point, in model co-ordinates, about which the gun is spun */ public Vector3f spinPoint = new Vector3f(); /** * Custom reload Parameters. If Enum.CUSTOM is set, these parameters can build an animation within the gun model classes */ public float rotateGunVertical = 0F; public float rotateGunHorizontal = 0F; public float tiltGun = 0F; public Vector3f translateGun = new Vector3f(0F, 0F, 0F); /* Ammo Model reload parameters */ public float rotateClipVertical = 0F; public float rotateClipHorizontal = 0F; public float tiltClip = 0F; public Vector3f translateClip = new Vector3f(0F, 0F, 0F); /** * This offsets the render position for third person */ public Vector3f thirdPersonOffset = new Vector3f(); /** * This offsets the render position for item frames */ public Vector3f itemFrameOffset = new Vector3f(); public void renderGun(float f) { render(gunModel, f); } public void renderCustom(float f, GunAnimations anims) { } public void renderSlide(float f) { render(slideModel, f); } public void renderPump(float f) { render(pumpModel, f); } public void renderDefaultScope(float f) { render(defaultScopeModel, f); } public void renderDefaultBarrel(float f) { render(defaultBarrelModel, f); } public void renderDefaultStock(float f) { render(defaultStockModel, f); } public void renderDefaultGrip(float f) { render(defaultGripModel, f); } public void renderAmmo(float f) { render(ammoModel, f); } public void renderMinigunBarrel(float f) { render(minigunBarrelModel, f); } public void renderRevolverBarrel(float f) { render(revolverBarrelModel, f); } public void renderBreakAction(float f) { render(breakActionModel, f); } /** * For renderering models simply */ protected void render(ModelRendererTurbo[] models, float f) { for(ModelRendererTurbo model : models) if(model != null) model.render(f); } /** * Flips the model. Generally only for backwards compatibility */ public void flipAll() { flip(gunModel); flip(defaultBarrelModel); flip(defaultScopeModel); flip(defaultStockModel); flip(defaultGripModel); flip(ammoModel); flip(slideModel); flip(pumpModel); flip(minigunBarrelModel); flip(revolverBarrelModel); flip(breakActionModel); } protected void flip(ModelRendererTurbo[] model) { for(ModelRendererTurbo part : model) { part.doMirror(false, true, true); part.setRotationPoint(part.rotationPointX, -part.rotationPointY, -part.rotationPointZ); } } /** * Translates the model */ public void translateAll(float x, float y, float z) { translate(gunModel, x, y, z); translate(defaultBarrelModel, x, y, z); translate(defaultScopeModel, x, y, z); translate(defaultStockModel, x, y, z); translate(defaultGripModel, x, y, z); translate(ammoModel, x, y, z); translate(slideModel, x, y, z); translate(pumpModel, x, y, z); translate(minigunBarrelModel, x, y, z); translate(revolverBarrelModel, x, y, z); translate(breakActionModel, x, y, z); translateAttachment(barrelAttachPoint, x, y, z); translateAttachment(scopeAttachPoint, x, y, z); translateAttachment(gripAttachPoint, x, y, z); translateAttachment(stockAttachPoint, x, y, z); } protected void translate(ModelRendererTurbo[] model, float x, float y, float z) { for(ModelRendererTurbo mod : model) { mod.rotationPointX += x; mod.rotationPointY += y; mod.rotationPointZ += z; } } protected void translateAttachment(Vector3f vector, float x, float y, float z) { vector.x -= x / 16F; vector.y -= y / 16F; vector.z -= z / 16F; } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelItemHolder.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.vector.Vector3f; public class ModelItemHolder extends ModelBase { public ModelRendererTurbo[] baseModel; public Vector3f itemOffset = new Vector3f(), itemRotation = new Vector3f(); public void render() { float f5 = 1F / 16F; for(ModelRendererTurbo model : baseModel) model.render(f5); } /** * Flips the model. Generally only for backwards compatibility */ public void flipAll() { flip(baseModel); } protected void flip(ModelRendererTurbo[] model) { for(ModelRendererTurbo part : model) { part.doMirror(false, true, true); part.setRotationPoint(part.rotationPointX, -part.rotationPointY, -part.rotationPointZ); } } /** * Translates the model */ public void translateAll(float x, float y, float z) { translate(baseModel, x, y, z); } protected void translate(ModelRendererTurbo[] model, float x, float y, float z) { for(ModelRendererTurbo mod : model) { mod.rotationPointX += x; mod.rotationPointY += y; mod.rotationPointZ += z; } } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelMG.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.guns.EntityMG; public class ModelMG extends ModelBase { public ModelRendererTurbo bipodModel[]; public ModelRendererTurbo gunModel[]; public ModelRendererTurbo ammoModel[]; public ModelRendererTurbo ammoBoxModel[] = new ModelRendererTurbo[0]; public void renderBipod(float f, float f1, float f2, float f3, float f4, float f5, EntityMG mg) { for(ModelRendererTurbo bipodPart : bipodModel) { bipodPart.render(f5); } if(mg.reloadTimer > 0 || mg.ammo.isEmpty()) return; for(ModelRendererTurbo ammoBoxPart : ammoBoxModel) { ammoBoxPart.render(f5); } } public void renderGun(float f, float f1, float f2, float f3, float f4, float f5, float f6, EntityMG mg) { for(ModelRendererTurbo gunPart : gunModel) { gunPart.rotateAngleX = -(mg.prevRotationPitch + (mg.rotationPitch - mg.prevRotationPitch) * f6) / 180F * 3.141592653589793238462643383279502884197169399F; gunPart.render(f5); } if(mg.reloadTimer > 0 || mg.ammo.isEmpty()) return; for(ModelRendererTurbo ammoPart : ammoModel) { ammoPart.rotateAngleX = -(mg.prevRotationPitch + (mg.rotationPitch - mg.prevRotationPitch) * f6) / 180F * 3.141592653589793238462643383279502884197169399F; ammoPart.render(f5); } } public void flipAll() { for(ModelRendererTurbo aBipodModel : bipodModel) { aBipodModel.doMirror(false, true, true); aBipodModel.setRotationPoint(aBipodModel.rotationPointX, -aBipodModel.rotationPointY, -aBipodModel.rotationPointZ); } for(ModelRendererTurbo aGunModel : gunModel) { aGunModel.doMirror(false, true, true); aGunModel.setRotationPoint(aGunModel.rotationPointX, -aGunModel.rotationPointY, -aGunModel.rotationPointZ); } for(ModelRendererTurbo anAmmoModel : ammoModel) { anAmmoModel.doMirror(false, true, true); anAmmoModel.setRotationPoint(anAmmoModel.rotationPointX, -anAmmoModel.rotationPointY, -anAmmoModel.rotationPointZ); } for(ModelRendererTurbo anAmmoBoxModel : ammoBoxModel) { anAmmoBoxModel.doMirror(false, true, true); anAmmoBoxModel.setRotationPoint(anAmmoBoxModel.rotationPointX, -anAmmoBoxModel.rotationPointY, -anAmmoBoxModel.rotationPointZ); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelMecha.java ================================================ package com.flansmod.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.vector.Vector3f; import net.minecraft.client.renderer.GlStateManager; public class ModelMecha extends ModelDriveable { public ModelRendererTurbo[] leftArmModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightArmModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftHandModel = new ModelRendererTurbo[0]; //Renderered when the mecha is not holding anything public ModelRendererTurbo[] rightHandModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] hipsModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftRearLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightRearLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftRearFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightRearFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftFrontLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightFrontLegModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftFrontFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightFrontFootModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] headModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] barrelModel = new ModelRendererTurbo[0]; /** * The point at which various attachment models are rendered */ public Vector3f hipsAttachmentPoint = new Vector3f(); @Override public void render(EntityDriveable driveable, float f1) { render(0.0625F, (EntityMecha)driveable, f1); } @Override /** GUI render method */ public void render(DriveableType type) { super.render(type); MechaType mechaType = (MechaType)type; renderPart(hipsModel); renderPart(leftLegModel); renderPart(rightLegModel); renderPart(leftFootModel); renderPart(rightFootModel); renderPart(leftRearLegModel); renderPart(rightRearLegModel); renderPart(leftRearFootModel); renderPart(rightRearFootModel); renderPart(leftFrontLegModel); renderPart(rightFrontLegModel); renderPart(leftFrontFootModel); renderPart(rightFrontFootModel); renderPart(barrelModel); renderPart(headModel); GlStateManager.pushMatrix(); GlStateManager.translate(mechaType.leftArmOrigin.x / mechaType.modelScale, mechaType.leftArmOrigin.y / mechaType.modelScale, mechaType.leftArmOrigin.z / mechaType.modelScale); renderPart(leftArmModel); renderPart(leftHandModel); GlStateManager.popMatrix(); GlStateManager.pushMatrix(); GlStateManager.translate(mechaType.rightArmOrigin.x / mechaType.modelScale, mechaType.rightArmOrigin.y / mechaType.modelScale, mechaType.rightArmOrigin.z / mechaType.modelScale); renderPart(rightArmModel); renderPart(rightHandModel); GlStateManager.popMatrix(); } public void render(float f5, EntityMecha mecha, float f) { //Rendering the body if(mecha.isPartIntact(EnumDriveablePart.core)) for(ModelRendererTurbo aBodyModel : bodyModel) aBodyModel.render(f5); if(mecha.isPartIntact(EnumDriveablePart.head)) for(ModelRendererTurbo model : headModel) model.render(f5); float pitch = mecha.getSeat(0) == null ? 0F : mecha.getSeat(0).looking.getPitch(); if(mecha.isPartIntact(EnumDriveablePart.barrel)) { for(ModelRendererTurbo aBarrelModel : barrelModel) { aBarrelModel.rotateAngleZ = -pitch * 3.14159265F / 180F; aBarrelModel.render(f5, oldRotateOrder); } } } public void renderLeftArm(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftArmModel) model.render(f5); } public void renderLeftHand(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftHandModel) model.render(f5); } public void renderRightArm(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightArmModel) model.render(f5); } public void renderRightHand(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightHandModel) model.render(f5); } public void renderRightFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightFootModel) model.render(f5); } public void renderLeftFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftFootModel) model.render(f5); } public void renderRightLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightLegModel) model.render(f5); } public void renderLeftLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftLegModel) model.render(f5); } public void renderRightRearFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightRearFootModel) model.render(f5); } public void renderLeftRearFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftRearFootModel) model.render(f5); } public void renderRightRearLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightRearLegModel) model.render(f5); } public void renderLeftRearLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftRearLegModel) model.render(f5); } public void renderRightFrontFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightFrontFootModel) model.render(f5); } public void renderLeftFrontFoot(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftFrontFootModel) model.render(f5); } public void renderRightFrontLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : rightFrontLegModel) model.render(f5); } public void renderLeftFrontLeg(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : leftFrontLegModel) model.render(f5); } public void renderHips(float f5, EntityMecha mecha, float f) { for(ModelRendererTurbo model : hipsModel) model.render(f5); } @Override public void flipAll() { super.flipAll(); flip(leftArmModel); flip(rightArmModel); flip(leftHandModel); flip(rightHandModel); flip(hipsModel); flip(leftLegModel); flip(rightLegModel); flip(leftFootModel); flip(rightFootModel); flip(leftRearLegModel); flip(rightRearLegModel); flip(leftRearFootModel); flip(rightRearFootModel); flip(leftFrontLegModel); flip(rightFrontLegModel); flip(leftFrontFootModel); flip(rightFrontFootModel); flip(headModel); flip(barrelModel); } @Override public void translateAll(float x, float y, float z) { super.translateAll(x, y, z); translate(leftArmModel, x, y, z); translate(rightArmModel, x, y, z); translate(leftHandModel, x, y, z); translate(rightHandModel, x, y, z); translate(hipsModel, x, y, z); translate(leftLegModel, x, y, z); translate(rightLegModel, x, y, z); translate(leftFootModel, x, y, z); translate(rightFootModel, x, y, z); translate(leftRearLegModel, x, y, z); translate(rightRearLegModel, x, y, z); translate(leftRearFootModel, x, y, z); translate(rightRearFootModel, x, y, z); translate(leftFrontLegModel, x, y, z); translate(rightFrontLegModel, x, y, z); translate(leftFrontFootModel, x, y, z); translate(rightFrontFootModel, x, y, z); translate(headModel, x, y, z); translate(barrelModel, x, y, z); } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelMechaTool.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.driveables.mechas.EntityMecha; public class ModelMechaTool extends ModelBase { /** * This is the base, common across all Mecha Tools */ public ModelRendererTurbo[] baseModel = new ModelRendererTurbo[0]; /** * This bit spins */ public ModelRendererTurbo[] drillModel = new ModelRendererTurbo[0]; /** * This bit spins on a different axis */ public ModelRendererTurbo[] sawModel = new ModelRendererTurbo[0]; public void render(EntityMecha mecha, float f1) { float f5 = 1F / 16F; for(ModelRendererTurbo model : baseModel) model.render(f5); } public void renderDrill(EntityMecha mecha, float f1) { float f5 = 1F / 16F; for(ModelRendererTurbo model : drillModel) model.render(f5); } public void renderSaw(EntityMecha mecha, float f1, boolean spin) { float f5 = 1F / 16F; for(ModelRendererTurbo model : sawModel) { GlStateManager.pushMatrix(); if(spin) { GlStateManager.translate(model.rotationPointX / 16F, model.rotationPointY / 16F, model.rotationPointZ / 16F); GlStateManager.rotate(25F * (float)mecha.ticksExisted, 0F, 1F, 0F); GlStateManager.translate(-model.rotationPointX / 16F, -model.rotationPointY / 16F, -model.rotationPointZ / 16F); } model.render(f5); GlStateManager.popMatrix(); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelMuzzleFlash.java ================================================ package com.flansmod.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import net.minecraft.client.model.ModelBase; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; public abstract class ModelMuzzleFlash extends ModelBase { public ModelMuzzleFlash() { } @Override public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { renderMuzzleFlash(f5); } public abstract ResourceLocation GetTexture(); public abstract void renderMuzzleFlash(float f5); public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) { } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelNull.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; public class ModelNull extends ModelBase { } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelPlane.java ================================================ package com.flansmod.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.EnumPlaneMode; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.Propeller; import com.flansmod.common.vector.Vector3f; /** * Extensible ModelPlane class for rendering plane models */ public class ModelPlane extends ModelDriveable { //Shapebox template for copy paste //, 0F, /* 0 */ 0F, 0F, 0F, /* 1 */ 0F, 0F, 0F, /* 2 */ 0F, 0F, 0F, /* 3 */ 0F, 0F, 0F, /* 4 */ 0F, 0F, 0F, /* 5 */ 0F, 0F, 0F, /* 6 */ 0F, 0F, 0F, /* 7 */ 0F, 0F, 0F); public ModelRendererTurbo noseModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo leftWingModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo rightWingModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo topWingModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo bayModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo tailModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo propellerModels[][] = new ModelRendererTurbo[0][0]; //Propeller array [numProps][prop blades] public ModelRendererTurbo yawFlapModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo pitchFlapLeftModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo pitchFlapRightModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo pitchFlapLeftWingModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo pitchFlapRightWingModel[] = new ModelRendererTurbo[0]; //Helicopter bits public ModelRendererTurbo heliMainRotorModels[][] = new ModelRendererTurbo[0][0]; //Helicopter main rotors model array [numProps][prop blades] public Vector3f[] heliMainRotorOrigins = new Vector3f[0]; //Rotation origin of the rotors [numProps] public float[] heliRotorSpeeds = new float[0]; //Speed for rotor rotation. Make this negative for reverse blades public ModelRendererTurbo heliTailRotorModels[][] = new ModelRendererTurbo[0][0]; //Helicopter tail rotors model array [numProps][prop blades] public Vector3f[] heliTailRotorOrigins = new Vector3f[0]; //Rotation origin of the tail rotors [numProps] public ModelRendererTurbo skidsModel[] = new ModelRendererTurbo[0]; //Same as landing gear, but for helicopters //VTOL bits. They are swapped between when you swap modes public ModelRendererTurbo helicopterModeParts[] = new ModelRendererTurbo[0]; public ModelRendererTurbo planeModeParts[] = new ModelRendererTurbo[0]; public ModelRendererTurbo bodyWheelModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo tailWheelModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo leftWingWheelModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo rightWingWheelModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo tailDoorOpenModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo tailDoorCloseModel[] = new ModelRendererTurbo[0]; public ModelRendererTurbo rightWingPos1Model[] = new ModelRendererTurbo[0]; public ModelRendererTurbo rightWingPos2Model[] = new ModelRendererTurbo[0]; public ModelRendererTurbo leftWingPos1Model[] = new ModelRendererTurbo[0]; public ModelRendererTurbo leftWingPos2Model[] = new ModelRendererTurbo[0]; public ModelRendererTurbo hudModel[] = new ModelRendererTurbo[0]; @Override public void render(EntityDriveable driveable, float f1) { render(0.0625F, (EntityPlane)driveable, f1); } @Override /** GUI render method */ public void render(DriveableType type) { super.render(type); renderPart(noseModel); renderPart(leftWingModel); renderPart(rightWingModel); renderPart(topWingModel); renderPart(bayModel); renderPart(tailModel); for(ModelRendererTurbo[] prop : propellerModels) { for(int j = 0; j < prop.length; j++) { prop[j].rotateAngleX = (j * 2F * 3.1415926535F) / (prop.length); prop[j].render(0.0625F); } } for(ModelRendererTurbo[] heliMainRotorModel : heliMainRotorModels) renderPart(heliMainRotorModel); for(ModelRendererTurbo[] heliTailRotorModel : heliTailRotorModels) renderPart(heliTailRotorModel); renderPart(helicopterModeParts); renderPart(skidsModel); renderPart(yawFlapModel); renderPart(pitchFlapLeftModel); renderPart(pitchFlapRightModel); renderPart(pitchFlapLeftWingModel); renderPart(pitchFlapRightWingModel); renderPart(bodyWheelModel); renderPart(tailWheelModel); renderPart(leftWingWheelModel); renderPart(rightWingWheelModel); renderPart(tailDoorCloseModel); renderPart(rightWingPos1Model); renderPart(leftWingPos1Model); renderPart(hudModel); } public void render(float f5, EntityPlane plane, float f) { PlaneType type = plane.getPlaneType(); //Rotating the propeller float angle = plane.propAngle; for(Propeller propeller : plane.getPlaneType().propellers) { if(plane.isPartIntact(propeller.planePart) && propellerModels.length > propeller.ID) { int numParts = propellerModels[propeller.ID].length; for(int j = 0; j < numParts; j++) { propellerModels[propeller.ID][j].rotateAngleX = angle + (j * 2F * 3.1415926535F) / (numParts); propellerModels[propeller.ID][j].render(f5); } } } if(plane.isPartIntact(EnumDriveablePart.nose)) { //Nose for(ModelRendererTurbo aNoseModel : noseModel) { aNoseModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.bay)) { //Bay for(ModelRendererTurbo aBayModel : bayModel) { aBayModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.tail)) { //Rendering the tail for(ModelRendererTurbo aTailModel : tailModel) { aTailModel.render(f5); } //Doors for(ModelRendererTurbo aTailDoorOpenModel : tailDoorOpenModel) { if(plane.varDoor) aTailDoorOpenModel.render(f5); } for(ModelRendererTurbo aTailDoorCloseModel : tailDoorCloseModel) { if(!plane.varDoor) aTailDoorCloseModel.render(f5); } //Rotating the yaw flap for(ModelRendererTurbo aYawFlapModel : yawFlapModel) { aYawFlapModel.rotateAngleY = plane.flapsYaw * 3.14159265F / 180F; aYawFlapModel.render(f5); } //Rotating the left pitch flap for(ModelRendererTurbo aPitchFlapLeftModel : pitchFlapLeftModel) { aPitchFlapLeftModel.rotateAngleZ = plane.flapsPitchLeft * 3.14159265F / 180F; aPitchFlapLeftModel.render(f5); } //Rotating the right pitch flap for(ModelRendererTurbo aPitchFlapRightModel : pitchFlapRightModel) { aPitchFlapRightModel.rotateAngleZ = plane.flapsPitchRight * 3.14159265F / 180F; aPitchFlapRightModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.skids)) { //Skids for(ModelRendererTurbo aSkidsModel : skidsModel) { if(plane.varGear) aSkidsModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.tailWheel)) { //Gear for(ModelRendererTurbo aTailWheelModel : tailWheelModel) { if(plane.varGear) aTailWheelModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.leftWing)) { //Rendering the left wing for(ModelRendererTurbo aLeftWingModel : leftWingModel) { aLeftWingModel.render(f5); } //Changeable Wings for(ModelRendererTurbo aLeftWingPos1Model : leftWingPos1Model) { if(plane.varWing) aLeftWingPos1Model.render(f5); } for(ModelRendererTurbo aLeftWingPos2Model : leftWingPos2Model) { if(!plane.varWing) aLeftWingPos2Model.render(f5); } //Rotating the left wing pitch flap for(ModelRendererTurbo aPitchFlapLeftWingModel : pitchFlapLeftWingModel) { aPitchFlapLeftWingModel.rotateAngleZ = plane.flapsPitchLeft * 3.14159265F / 180F; aPitchFlapLeftWingModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.rightWing)) { //Rendering the right wing for(ModelRendererTurbo aRightWingModel : rightWingModel) { aRightWingModel.render(f5); } //Changeable Wings for(ModelRendererTurbo aRightWingPos1Model : rightWingPos1Model) { if(plane.varWing) aRightWingPos1Model.render(f5); } for(ModelRendererTurbo aRightWingPos2Model : rightWingPos2Model) { if(!plane.varWing) aRightWingPos2Model.render(f5); } //Rotating the right wing pitch flap for(ModelRendererTurbo aPitchFlapRightWingModel : pitchFlapRightWingModel) { aPitchFlapRightWingModel.rotateAngleZ = plane.flapsPitchRight * 3.14159265F / 180F; aPitchFlapRightWingModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.leftWingWheel)) { //Gear for(ModelRendererTurbo aLeftWingWheelModel : leftWingWheelModel) { if(plane.varGear) aLeftWingWheelModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.rightWingWheel)) { //Gear for(ModelRendererTurbo aRightWingWheelModel : rightWingWheelModel) { if(plane.varGear) aRightWingWheelModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.core)) { //Rendering the body for(ModelRendererTurbo aBodyModel : bodyModel) { aBodyModel.render(f5); } //Doors for(ModelRendererTurbo aBodyDoorOpenModel : bodyDoorOpenModel) { if(plane.varDoor) aBodyDoorOpenModel.render(f5); } for(ModelRendererTurbo aBodyDoorCloseModel : bodyDoorCloseModel) { if(!plane.varDoor) aBodyDoorCloseModel.render(f5); } for(ModelRendererTurbo aHudModel : hudModel) { aHudModel.rotateAngleX = -(plane.axes.getRoll() * 3.14159265F / 180F); aHudModel.render(f5); } //VTOL bits if(plane.mode == EnumPlaneMode.HELI) { renderPart(helicopterModeParts); } else renderPart(planeModeParts); } if(plane.isPartIntact(EnumDriveablePart.coreWheel)) { //Gear for(ModelRendererTurbo aBodyWheelModel : bodyWheelModel) { if(plane.varGear) aBodyWheelModel.render(f5); } } if(plane.isPartIntact(EnumDriveablePart.topWing)) { //Rendering the top wing for(ModelRendererTurbo aTopWingModel : topWingModel) { aTopWingModel.render(f5); } } //Render guns for(EntitySeat seat : plane.getSeats()) { //If the seat has a gun model attached if(seat != null && seat.seatInfo != null && seat.seatInfo.gunName != null && gunModels.get(seat.seatInfo.gunName) != null && plane.isPartIntact(seat.seatInfo.part)) { float yaw = seat.prevLooking.getYaw() + (seat.looking.getYaw() - seat.prevLooking.getYaw()) * f; float pitch = seat.prevLooking.getPitch() + (seat.looking.getPitch() - seat.prevLooking.getPitch()) * f; //Iterate over the parts of that model ModelRendererTurbo[][] gunModel = gunModels.get(seat.seatInfo.gunName); //Yaw only parts for(ModelRendererTurbo gunModelPart : gunModel[0]) { //Yaw and render gunModelPart.rotateAngleY = (180F - yaw) * 3.14159265F / 180F; gunModelPart.render(f5); } //Yaw and pitch, no recoil parts for(ModelRendererTurbo gunModelPart : gunModel[1]) { //Yaw, pitch and render gunModelPart.rotateAngleY = (180F - yaw) * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5); } //Yaw, pitch and recoil parts for(ModelRendererTurbo gunModelPart : gunModel[2]) { //Yaw, pitch, recoil and render gunModelPart.rotateAngleY = (180F - yaw) * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5); } if(gunModel.length > 3) { //Minigun barrel part float minigunSpeed = seat.getMinigunSpeed(); for(ModelRendererTurbo gunModelPart : gunModel[3]) { //Yaw, pitch, recoil and render gunModelPart.rotateAngleY = (180F - yaw) * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.rotateAngleX = seat.minigunAngle * 0.5F; gunModelPart.render(f5); } } } } } /** * Renders helicopter rotor number i. */ public void renderRotor(EntityPlane plane, float f5, int i) { PlaneType type = plane.getPlaneType(); //If its not covered by the plane type heli propellers, render it. Otherwise, see if the part is intact if(i >= type.heliPropellers.size() || plane.isPartIntact(type.heliPropellers.get(i).planePart)) { for(int j = 0; j < heliMainRotorModels[i].length; j++) { heliMainRotorModels[i][j].render(f5); } } } /** * Renders helicopter tail rotor number i. */ public void renderTailRotor(EntityPlane plane, float f5, int i) { PlaneType type = plane.getPlaneType(); //If its not covered by the plane type heli propellers, render it. Otherwise, see if the part is intact if(i >= type.heliTailPropellers.size() || plane.isPartIntact(type.heliTailPropellers.get(i).planePart)) { for(int j = 0; j < heliTailRotorModels[i].length; j++) { heliTailRotorModels[i][j].render(f5); } } } @Override public void flipAll() { super.flipAll(); flip(noseModel); flip(leftWingModel); flip(rightWingModel); flip(topWingModel); flip(bayModel); flip(tailModel); flip(yawFlapModel); flip(skidsModel); flip(helicopterModeParts); flip(planeModeParts); flip(pitchFlapLeftModel); flip(pitchFlapRightModel); flip(pitchFlapLeftWingModel); flip(pitchFlapRightWingModel); flip(bodyWheelModel); flip(tailWheelModel); flip(leftWingWheelModel); flip(rightWingWheelModel); flip(tailDoorOpenModel); flip(tailDoorCloseModel); flip(rightWingPos1Model); flip(rightWingPos2Model); flip(leftWingPos1Model); flip(leftWingPos2Model); flip(hudModel); for(ModelRendererTurbo[] propellerModel : propellerModels) { flip(propellerModel); } for(ModelRendererTurbo[] propellerModel : heliMainRotorModels) { flip(propellerModel); } for(ModelRendererTurbo[] propellerModel : heliTailRotorModels) { flip(propellerModel); } } @Override public void translateAll(float x, float y, float z) { super.translateAll(x, y, z); translate(noseModel, x, y, z); translate(leftWingModel, x, y, z); translate(rightWingModel, x, y, z); translate(topWingModel, x, y, z); translate(bayModel, x, y, z); translate(tailModel, x, y, z); translate(yawFlapModel, x, y, z); translate(skidsModel, x, y, z); translate(helicopterModeParts, x, y, z); translate(planeModeParts, x, y, z); translate(pitchFlapLeftModel, x, y, z); translate(pitchFlapRightModel, x, y, z); translate(pitchFlapLeftWingModel, x, y, z); translate(pitchFlapRightWingModel, x, y, z); translate(bodyWheelModel, x, y, z); translate(tailWheelModel, x, y, z); translate(leftWingWheelModel, x, y, z); translate(rightWingWheelModel, x, y, z); translate(tailDoorOpenModel, x, y, z); translate(tailDoorCloseModel, x, y, z); translate(rightWingPos1Model, x, y, z); translate(rightWingPos2Model, x, y, z); translate(leftWingPos1Model, x, y, z); translate(leftWingPos2Model, x, y, z); translate(hudModel, x, y, z); for(ModelRendererTurbo[] mods : propellerModels) { translate(mods, x, y, z); } for(ModelRendererTurbo[] mods : heliMainRotorModels) { translate(mods, x, y, z); } for(ModelRendererTurbo[] mods : heliTailRotorModels) { translate(mods, x, y, z); } for(Vector3f o : heliMainRotorOrigins) Vector3f.add(o, new Vector3f(x / 16F, y / 16F, z / 16F), o); for(Vector3f o : heliTailRotorOrigins) Vector3f.add(o, new Vector3f(x / 16F, y / 16F, z / 16F), o); } } ================================================ FILE: src/main/java/com/flansmod/client/model/ModelVehicle.java ================================================ package com.flansmod.client.model; import com.flansmod.client.tmt.ModelRendererTurbo; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.VehicleType; import com.flansmod.common.vector.Vector3f; //Extensible ModelVehicle class for rendering vehicle models public class ModelVehicle extends ModelDriveable { public ModelRendererTurbo[] turretModel = new ModelRendererTurbo[0]; //The turret (for tanks) public ModelRendererTurbo[] barrelModel = new ModelRendererTurbo[0]; //The barrel of the main turret public ModelRendererTurbo[][] ammoModel = new ModelRendererTurbo[0][0]; //Ammo models for the main turret. ammoModel[i] will render if the vehicle has less than 3 ammo slots or if slot i is full. Checks shell / missile inventory public ModelRendererTurbo[] frontWheelModel = new ModelRendererTurbo[0]; //Front and back wheels are for bicycles and motorbikes and whatnot public ModelRendererTurbo[] backWheelModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftFrontWheelModel = new ModelRendererTurbo[0]; //This set of 4 wheels are for 4 or more wheeled things public ModelRendererTurbo[] rightFrontWheelModel = new ModelRendererTurbo[0]; //The front wheels will turn as the player steers, and the back ones will not public ModelRendererTurbo[] leftBackWheelModel = new ModelRendererTurbo[0]; //They will all turn as the car drives if the option to do so is set on public ModelRendererTurbo[] rightBackWheelModel = new ModelRendererTurbo[0]; //In the vehicle type file public ModelRendererTurbo[] rightTrackModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] leftTrackModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] rightTrackWheelModels = new ModelRendererTurbo[0]; //These go with the tracks but rotate public ModelRendererTurbo[] leftTrackWheelModels = new ModelRendererTurbo[0]; public ModelRendererTurbo[] fancyTrackModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[][] leftAnimTrackModel = new ModelRendererTurbo[0][0]; //Unlimited frame track animations public ModelRendererTurbo[][] rightAnimTrackModel = new ModelRendererTurbo[0][0]; public ModelRendererTurbo[] bodyDoorOpenModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] bodyDoorCloseModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] trailerModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] steeringWheelModel = new ModelRendererTurbo[0]; public ModelRendererTurbo[] drillHeadModel = new ModelRendererTurbo[0]; //Drill head. Rotates around public Vector3f drillHeadOrigin = new Vector3f(); //this point //recoiling barrel part public ModelRendererTurbo[] animBarrelModel = new ModelRendererTurbo[0]; public Vector3f barrelAttach = new Vector3f(); public int animFrame = 0; @Override public void render(EntityDriveable driveable, float f1) { render(0.0625F, (EntityVehicle)driveable, f1); } @Override /** GUI render method */ public void render(DriveableType type) { super.render(type); renderPart(leftBackWheelModel); renderPart(rightBackWheelModel); renderPart(leftFrontWheelModel); renderPart(rightFrontWheelModel); renderPart(rightTrackModel); renderPart(leftTrackModel); renderPart(rightTrackWheelModels); renderPart(leftTrackWheelModels); renderPart(bodyDoorCloseModel); renderPart(trailerModel); renderPart(turretModel); renderPart(barrelModel); renderPart(drillHeadModel); for(ModelRendererTurbo[] mods : ammoModel) renderPart(mods); //This might cause all animation frames to render simultaneously in the crafting box... but it doesn't crash. Which is a plus I guess? for(ModelRendererTurbo[] latm : leftAnimTrackModel) renderPart(latm); for(ModelRendererTurbo[] ratm : rightAnimTrackModel) renderPart(ratm); renderPart(steeringWheelModel); } public void render(float f5, EntityVehicle vehicle, float f) { boolean rotateWheels = vehicle.getVehicleType().rotateWheels; animFrame = vehicle.animFrame; //Rendering the body if(vehicle.isPartIntact(EnumDriveablePart.core)) { for(ModelRendererTurbo aBodyModel : bodyModel) { aBodyModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo aBodyDoorOpenModel : bodyDoorOpenModel) { if(vehicle.varDoor) aBodyDoorOpenModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo aBodyDoorCloseModel : bodyDoorCloseModel) { if(!vehicle.varDoor) aBodyDoorCloseModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo aSteeringWheelModel : steeringWheelModel) { aSteeringWheelModel.rotateAngleX = vehicle.wheelsYaw * 3.14159265F / 180F * 3F; aSteeringWheelModel.render(f5, oldRotateOrder); } } //Wheels if(vehicle.isPartIntact(EnumDriveablePart.backLeftWheel)) { for(ModelRendererTurbo aLeftBackWheelModel : leftBackWheelModel) { aLeftBackWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aLeftBackWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.backRightWheel)) { for(ModelRendererTurbo aRightBackWheelModel : rightBackWheelModel) { aRightBackWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aRightBackWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.frontLeftWheel)) { for(ModelRendererTurbo aLeftFrontWheelModel : leftFrontWheelModel) { aLeftFrontWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aLeftFrontWheelModel.rotateAngleY = -vehicle.wheelsYaw * 3.14159265F / 180F * 3F; aLeftFrontWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.frontRightWheel)) { for(ModelRendererTurbo aRightFrontWheelModel : rightFrontWheelModel) { aRightFrontWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aRightFrontWheelModel.rotateAngleY = -vehicle.wheelsYaw * 3.14159265F / 180F * 3F; aRightFrontWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.frontWheel)) { for(ModelRendererTurbo aFrontWheelModel : frontWheelModel) { aFrontWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aFrontWheelModel.rotateAngleY = -vehicle.wheelsYaw * 3.14159265F / 180F * 3F; aFrontWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.backWheel)) { for(ModelRendererTurbo aBackWheelModel : backWheelModel) { aBackWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; aBackWheelModel.render(f5, oldRotateOrder); } } if(vehicle.isPartIntact(EnumDriveablePart.leftTrack)) { for(ModelRendererTurbo aLeftTrackModel : leftTrackModel) { aLeftTrackModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo leftTrackWheelModel : leftTrackWheelModels) { leftTrackWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; leftTrackWheelModel.render(f5, oldRotateOrder); } for(int i = 0; i < leftAnimTrackModel.length; i++) { if(i == animFrame) { for(ModelRendererTurbo aLeftAnimTrackModel : leftAnimTrackModel[i]) { aLeftAnimTrackModel.render(f5, oldRotateOrder); } } } } if(vehicle.isPartIntact(EnumDriveablePart.rightTrack)) { for(ModelRendererTurbo aRightTrackModel : rightTrackModel) { aRightTrackModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo rightTrackWheelModel : rightTrackWheelModels) { rightTrackWheelModel.rotateAngleZ = rotateWheels ? -vehicle.wheelsAngle : 0; rightTrackWheelModel.render(f5, oldRotateOrder); } for(int i = 0; i < rightAnimTrackModel.length; i++) { if(i == animFrame) { for(ModelRendererTurbo aRightAnimTrackModel : rightAnimTrackModel[i]) { aRightAnimTrackModel.render(f5, oldRotateOrder); } } } } if(vehicle.isPartIntact(EnumDriveablePart.trailer)) { for(ModelRendererTurbo aTrailerModel : trailerModel) { aTrailerModel.render(f5, oldRotateOrder); } } //Render guns for(EntitySeat seat : vehicle.getSeats()) { //If the seat has a gun model attached if(seat != null && seat.seatInfo != null && seat.seatInfo.gunName != null && gunModels.get(seat.seatInfo.gunName) != null && vehicle.isPartIntact(seat.seatInfo.part) && !vehicle.rotateWithTurret(seat.seatInfo)) { float yaw = seat.prevLooking.getYaw() + (seat.looking.getYaw() - seat.prevLooking.getYaw()) * f; float pitch = seat.prevLooking.getPitch() + (seat.looking.getPitch() - seat.prevLooking.getPitch()) * f; //Iterate over the parts of that model ModelRendererTurbo[][] gunModel = gunModels.get(seat.seatInfo.gunName); //Yaw only parts for(ModelRendererTurbo gunModelPart : gunModel[0]) { //Yaw and render gunModelPart.rotateAngleY = -yaw * 3.14159265F / 180F; gunModelPart.render(f5); } //Yaw and pitch, no recoil parts for(ModelRendererTurbo gunModelPart : gunModel[1]) { //Yaw, pitch and render gunModelPart.rotateAngleY = -yaw * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5); } //Yaw, pitch and recoil parts for(ModelRendererTurbo gunModelPart : gunModel[2]) { //Yaw, pitch, recoil and render gunModelPart.rotateAngleY = -yaw * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5); } } } } /** * Render the tank turret * * @param dt */ public void renderTurret(float f, float f1, float f2, float f3, float f4, float f5, EntityVehicle vehicle, float dt) { VehicleType type = vehicle.getVehicleType(); //Render main turret barrel { float yaw = vehicle.getSeat(0).looking.getYaw(); float pitch = vehicle.getSeat(0).looking.getPitch(); for(ModelRendererTurbo aTurretModel : turretModel) { aTurretModel.render(f5, oldRotateOrder); } for(ModelRendererTurbo aBarrelModel : barrelModel) { aBarrelModel.rotateAngleZ = -pitch * 3.14159265F / 180F; aBarrelModel.render(f5, oldRotateOrder); } for(int i = 0; i < ammoModel.length; i++) { if(i >= type.numMissileSlots || vehicle.getDriveableData().missiles[i] != null) { for(int j = 0; j < ammoModel[i].length; j++) { ammoModel[i][j].rotateAngleZ = -pitch * 3.14159265F / 180F; ammoModel[i][j].render(f5, oldRotateOrder); } } } } //Render turret guns for(EntitySeat seat : vehicle.getSeats()) { //If the seat has a gun model attached if(seat != null && seat.seatInfo != null && seat.seatInfo.gunName != null && gunModels.get(seat.seatInfo.gunName) != null && vehicle.isPartIntact(seat.seatInfo.part) && vehicle.rotateWithTurret(seat.seatInfo)) { EntitySeat driverSeat = vehicle.getSeat(0); float driverYaw = driverSeat.prevLooking.getYaw() + (driverSeat.looking.getYaw() - driverSeat.prevLooking.getYaw()) * dt; float yaw = seat.prevLooking.getYaw() + (seat.looking.getYaw() - seat.prevLooking.getYaw()) * dt; float pitch = seat.prevLooking.getPitch() + (seat.looking.getPitch() - seat.prevLooking.getPitch()) * dt; float effectiveYaw = yaw - driverYaw; //Iterate over the parts of that model ModelRendererTurbo[][] gunModel = gunModels.get(seat.seatInfo.gunName); //Yaw only parts for(ModelRendererTurbo gunModelPart : gunModel[0]) { //Yaw and render gunModelPart.rotateAngleY = -effectiveYaw * 3.14159265F / 180F; gunModelPart.render(f5, oldRotateOrder); } //Yaw and pitch, no recoil parts for(ModelRendererTurbo gunModelPart : gunModel[1]) { //Yaw, pitch and render gunModelPart.rotateAngleY = -effectiveYaw * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5, oldRotateOrder); } //Yaw, pitch and recoil parts for(ModelRendererTurbo gunModelPart : gunModel[2]) { //Yaw, pitch, recoil and render gunModelPart.rotateAngleY = -effectiveYaw * 3.14159265F / 180F; gunModelPart.rotateAngleZ = -pitch * 3.14159265F / 180F; gunModelPart.render(f5, oldRotateOrder); } } } } public void renderAnimBarrel(float f, float f1, float f2, float f3, float f4, float f5, EntityVehicle vehicle, float dt) { if(vehicle.isPartIntact(EnumDriveablePart.turret)) { for(ModelRendererTurbo aAnimBarrelModel : animBarrelModel) { aAnimBarrelModel.render(f5, oldRotateOrder); } } } public void renderDrillBit(EntityVehicle vehicle, float f) { if(vehicle.isPartIntact(EnumDriveablePart.harvester)) { for(ModelRendererTurbo adrillHeadModel : drillHeadModel) { adrillHeadModel.render(0.0625F, oldRotateOrder); } } } public void renderFancyTracks(EntityVehicle vehicle, float f) { for(ModelRendererTurbo adrillHeadModel : fancyTrackModel) { adrillHeadModel.render(0.0625F, oldRotateOrder); } } @Override public void flipAll() { super.flipAll(); flip(bodyDoorOpenModel); flip(bodyDoorCloseModel); flip(turretModel); flip(barrelModel); flip(leftFrontWheelModel); flip(rightFrontWheelModel); flip(leftBackWheelModel); flip(rightBackWheelModel); flip(rightTrackModel); flip(leftTrackModel); flip(rightTrackWheelModels); flip(leftTrackWheelModels); flip(trailerModel); flip(steeringWheelModel); flip(frontWheelModel); flip(backWheelModel); flip(drillHeadModel); flip(fancyTrackModel); for(ModelRendererTurbo[] latm : leftAnimTrackModel) flip(latm); for(ModelRendererTurbo[] ratm : rightAnimTrackModel) flip(ratm); } @Override public void translateAll(float x, float y, float z) { super.translateAll(x, y, z); translate(bodyDoorOpenModel, x, y, z); translate(bodyDoorCloseModel, x, y, z); translate(turretModel, x, y, z); translate(barrelModel, x, y, z); translate(leftFrontWheelModel, x, y, z); translate(rightFrontWheelModel, x, y, z); translate(leftBackWheelModel, x, y, z); translate(rightBackWheelModel, x, y, z); translate(rightTrackModel, x, y, z); translate(leftTrackModel, x, y, z); translate(rightTrackWheelModels, x, y, z); translate(leftTrackWheelModels, x, y, z); translate(trailerModel, x, y, z); translate(steeringWheelModel, x, y, z); translate(frontWheelModel, x, y, z); translate(backWheelModel, x, y, z); translate(drillHeadModel, x, y, z); for(ModelRendererTurbo[] latm : leftAnimTrackModel) translate(latm, x, y, z); for(ModelRendererTurbo[] ratm : rightAnimTrackModel) translate(ratm, x, y, z); } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderAAGun.java ================================================ package com.flansmod.client.model; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.guns.EntityAAGun; public class RenderAAGun extends Render { public RenderAAGun(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } public void render(EntityAAGun aa, double d, double d1, double d2, float f, float f1) { bindEntityTexture(aa); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.scale(1F, 1F, 1.0F); float dYaw = aa.gunYaw - aa.prevGunYaw; for(; dYaw > 180F; dYaw -= 360F) { } for(; dYaw <= -180F; dYaw += 360F) { } ModelAAGun modelAAGun = aa.type.model; if(modelAAGun != null) { modelAAGun.renderBase(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, aa); GlStateManager.rotate(180F - (aa.prevGunYaw + dYaw * f1), 0.0F, 1.0F, 0.0F); modelAAGun.renderGun(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, aa); } GlStateManager.popMatrix(); } @Override public void doRender(EntityAAGun entity, double d, double d1, double d2, float f, float f1) { render(entity, d, d1, d2, f, f1); } @Override protected ResourceLocation getEntityTexture(EntityAAGun entity) { return FlansModResourceHandler.getTexture(entity.type); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderAAGun(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderBullet.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.guns.EntityBullet; public class RenderBullet extends Render { public RenderBullet(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } public void render(EntityBullet bullet, double d, double d1, double d2, float f, float f1) { //TODO may fix this again //if(bullet.owner == Minecraft.getMinecraft().player && bullet.ticksExisted < 1) // return; bindEntityTexture(bullet); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.rotate(f, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(90F - bullet.prevRotationPitch - (bullet.rotationPitch - bullet.prevRotationPitch) * f1, 1.0F, 0.0F, 0.0F); ModelBase model = bullet.getFiredShot().getBulletType().model; if(model != null) model.render(bullet, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F); GlStateManager.popMatrix(); } @Override public void doRender(EntityBullet entity, double d, double d1, double d2, float f, float f1) { render(entity, d, d1, d2, f, f1); } @Override protected ResourceLocation getEntityTexture(EntityBullet entity) { return FlansModResourceHandler.getTexture(entity.getFiredShot().getBulletType()); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderBullet(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderFlag.java ================================================ package com.flansmod.client.model; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.FlansModClient; import com.flansmod.common.teams.EntityFlag; import com.flansmod.common.teams.EntityFlagpole; import com.flansmod.common.teams.Team; public class RenderFlag extends Render { private static final ResourceLocation texture = new ResourceLocation("flansmod", "teamsMod/Flagpole.png"); public ModelFlagpole modelFlagpole; public static float angle; public RenderFlag(RenderManager renderManager) { super(renderManager); modelFlagpole = new ModelFlagpole(); } @Override public void doRender(EntityFlag flag, double d, double d1, double d2, float f, float f1) { bindEntityTexture(flag); int teamID = flag.getTeamID(); Team team = FlansModClient.getTeam(teamID); if(team == null) { //Give each team a default colour switch(teamID) { case 0: GlStateManager.color(0x80 / 255F, 0x80 / 255F, 0x80 / 255F); break; //No team case 1: GlStateManager.color(0x40 / 255F, 0x40 / 255F, 0x40 / 255F); break; //Spectators case 2: GlStateManager.color(0xa1 / 255F, 0x7f / 255F, 0xff / 255F); break; //Team 1 case 3: GlStateManager.color(0xff / 255F, 0x7f / 255F, 0xb6 / 255F); break; //Team 2 } } else { int colour = team.teamColour; GlStateManager.color(((colour >> 16) & 0xff) / 255F, ((colour >> 8) & 0xff) / 255F, (colour & 0xff) / 255F); } GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.rotate(f, 0.0F, 1.0F, 0.0F); if(!(flag.getRidingEntity() instanceof EntityFlagpole)) { GlStateManager.rotate(angle, 0.0F, 1.0F, 0.0F); GlStateManager.translate(0.5F, 0F, 0F); } else { GlStateManager.translate(0F, 0.5F, 0F); } GlStateManager.scale(-1F, -1F, 1F); modelFlagpole.renderFlag(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, flag); GlStateManager.popMatrix(); GlStateManager.color(1F, 1F, 1F); } @Override protected ResourceLocation getEntityTexture(EntityFlag entity) { return texture; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderFlag(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderFlagpole.java ================================================ package com.flansmod.client.model; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.teams.EntityFlagpole; public class RenderFlagpole extends Render { private static final ResourceLocation texture = new ResourceLocation("flansmod", "teamsMod/Flagpole.png"); public ModelFlagpole modelFlagpole; public RenderFlagpole(RenderManager renderManager) { super(renderManager); modelFlagpole = new ModelFlagpole(); } @Override public void doRender(EntityFlagpole flagpole, double d, double d1, double d2, float f, float f1) { bindEntityTexture(flagpole); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.rotate(f, 0.0F, 1.0F, 0.0F); GlStateManager.scale(-1F, -1F, 1F); GlStateManager.color(1F, 1F, 1F); modelFlagpole.renderPole(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, flagpole); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntityFlagpole entity) { return texture; } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderFlagpole(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderGrenade.java ================================================ package com.flansmod.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.guns.ItemGrenade; public class RenderGrenade extends Render implements CustomItemRenderer { public RenderGrenade(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } @Override public void doRender(EntityGrenade grenade, double d, double d1, double d2, float f, float f1) { bindEntityTexture(grenade); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); if(grenade.stuck) { GlStateManager.rotate(180F - grenade.axes.getYaw(), 0.0F, 1.0F, 0.0F); GlStateManager.rotate(grenade.axes.getPitch(), 0.0F, 0.0F, 1.0F); GlStateManager.rotate(grenade.axes.getRoll(), 1.0F, 0.0F, 0.0F); } else { float dYaw = (grenade.axes.getYaw() - grenade.prevRotationYaw); for(; dYaw > 180F; dYaw -= 360F) { } for(; dYaw <= -180F; dYaw += 360F) { } float dPitch = (grenade.axes.getPitch() - grenade.prevRotationPitch); for(; dPitch > 180F; dPitch -= 360F) { } for(; dPitch <= -180F; dPitch += 360F) { } float dRoll = (grenade.axes.getRoll() - grenade.prevRotationRoll); for(; dRoll > 180F; dRoll -= 360F) { } for(; dRoll <= -180F; dRoll += 360F) { } GlStateManager.rotate(180F - grenade.prevRotationYaw - dYaw * f1, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(grenade.prevRotationPitch + dPitch * f1, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(grenade.prevRotationRoll + dRoll * f1, 1.0F, 0.0F, 0.0F); } ModelBase model = grenade.type.model; if(model != null) model.render(grenade, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntityGrenade entity) { ResourceLocation texture = FlansModResourceHandler.getTexture(entity.type); if(texture == null) return FlansModResourceHandler.getIcon(entity.type); return texture; } public boolean handleRenderType(ItemStack item, CustomItemRenderType type) { switch(type) { case EQUIPPED: case EQUIPPED_FIRST_PERSON: return item != null && item.getItem() instanceof ItemGrenade && ((ItemGrenade)item.getItem()).type.model != null; default: break; } return false; } @Override public void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data) { GlStateManager.pushMatrix(); if(item != null && item.getItem() instanceof ItemGrenade) { GrenadeType grenadeType = ((ItemGrenade)item.getItem()).type; if(grenadeType.model != null) { switch(type) { case EQUIPPED: { //GlStateManager.rotate(35F, 0F, 0F, 1F); //GlStateManager.rotate(-5F, 0F, 1F, 0F); //GlStateManager.translate(0.75F, -0.22F, -0.08F); //GlStateManager.translate(0F, 0.25F, 0F); break; } case EQUIPPED_FIRST_PERSON: { if(hand == EnumHand.MAIN_HAND) { GlStateManager.translate(-1.25F, 0.8F, 0.1F); } else { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-1F, 0.8F, -2F); GlStateManager.rotate(-135F, 0F, 1F, 0F); } break; } default: break; } Minecraft.getMinecraft().renderEngine.bindTexture(FlansModResourceHandler.getTexture(grenadeType)); ModelBase model = grenadeType.model; model.render(null, 0F, 0F, 0F, 0F, 0F, 1F / 16F); } } GlStateManager.popMatrix(); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderGrenade(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderGun.java ================================================ package com.flansmod.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.IScope; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.vector.Vector3f; public class RenderGun implements CustomItemRenderer { private static TextureManager renderEngine; public static float smoothing; public static boolean bindTextures = true; @Override public void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data) { //Avoid any broken cases by returning if(!(item.getItem() instanceof ItemGun)) return; GunType gunType = ((ItemGun)item.getItem()).GetType(); if(gunType == null) return; ModelGun model = gunType.model; if(model == null) return; //Render main hand gun GunAnimations animations = (type == CustomItemRenderType.ENTITY || type == CustomItemRenderType.INVENTORY) ? new GunAnimations() : FlansModClient.getGunAnimations((EntityLivingBase)data[1], hand); renderGun(type, item, gunType, animations, hand, data); } //Render off-hand gun in 3rd person public void renderOffHandGun(EntityPlayer player, ItemStack offHandItemStack) { GunAnimations animations = FlansModClient.gunAnimationsLeft.get(player); if(animations == null) { animations = new GunAnimations(); FlansModClient.gunAnimationsLeft.put(player, animations); } GunType offHandGunType = ((ItemGun)offHandItemStack.getItem()).GetType(); renderGun(CustomItemRenderType.INVENTORY, offHandItemStack, offHandGunType, animations, EnumHand.OFF_HAND, player); } private void renderGun(CustomItemRenderType type, ItemStack item, GunType gunType, GunAnimations animations, EnumHand hand, Object... data) { //The model scale float f = 1F / 16F; ModelGun model = gunType.model; int flip = hand == EnumHand.OFF_HAND ? -1 : 1; GlStateManager.pushMatrix(); { //Get the reload animation rotation float reloadRotate = 0F; //Setup transforms based on gun position switch(type) { case ENTITY: { //EntityItem entity = (EntityItem)data[1]; //GlStateManager.rotate(entity.getAge() + (entity.getAge() == 0 ? 0 : smoothing), 0F, 1F, 0F); GlStateManager.translate(-0.45F + model.itemFrameOffset.x, -0.05F + model.itemFrameOffset.y, model.itemFrameOffset.z); break; } case INVENTORY: { GlStateManager.translate(model.itemFrameOffset.x, model.itemFrameOffset.y, model.itemFrameOffset.z); break; } case EQUIPPED: { if(hand == EnumHand.OFF_HAND) { GlStateManager.rotate(-70F, 1F, 0F, 0F); GlStateManager.rotate(48F, 0F, 0F, 1F); GlStateManager.rotate(105F, 0F, 1F, 0F); GlStateManager.translate(-0.1F, -0.22F, -0.15F); } else { GlStateManager.rotate(90F, 0F, 0F, 1F); GlStateManager.rotate(-90F, 1F, 0F, 0F); GlStateManager.translate(0.2F, 0.05F, -0F); GlStateManager.scale(1F, 1F, -1F); } GlStateManager.translate(model.thirdPersonOffset.x, model.thirdPersonOffset.y, model.thirdPersonOffset.z); /* if(animations.meleeAnimationProgress > 0 && animations.meleeAnimationProgress < gunType.meleePath.size()) { Vector3f meleePos = gunType.meleePath.get(animations.meleeAnimationProgress); Vector3f nextMeleePos = animations.meleeAnimationProgress + 1 < gunType.meleePath.size() ? gunType.meleePath.get(animations.meleeAnimationProgress + 1) : new Vector3f(); GlStateManager.translate(meleePos.x + (nextMeleePos.x - meleePos.x) * smoothing, meleePos.y + (nextMeleePos.y - meleePos.y) * smoothing, meleePos.z + (nextMeleePos.z - meleePos.z) * smoothing); } */ break; } case EQUIPPED_FIRST_PERSON: { IScope scope = gunType.getCurrentScope(item); if(FlansModClient.zoomProgress > 0.9F && scope.hasZoomOverlay()) { GlStateManager.popMatrix(); return; } float adsSwitch = FlansModClient.lastZoomProgress + (FlansModClient.zoomProgress - FlansModClient.lastZoomProgress) * smoothing;//0F;//((float)Math.sin((FlansMod.ticker) / 10F) + 1F) / 2F; if(hand == EnumHand.OFF_HAND) { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-1F, 0.675F, -1.8F); } else { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.rotate(0F - 5F * adsSwitch, 0F, 0F, 1F); GlStateManager.translate(-1F, 0.675F + 0.180F * adsSwitch, -1F - 0.395F * adsSwitch); if(gunType.hasScopeOverlay) GlStateManager.translate(-0.7F * adsSwitch, -0.12F * adsSwitch, -0.05F * adsSwitch); GlStateManager.rotate(4.5F * adsSwitch, 0F, 0F, 1F); GlStateManager.translate(0F, -0.03F * adsSwitch, 0F); } if(animations.meleeAnimationProgress > 0 && animations.meleeAnimationProgress < gunType.meleePath.size()) { Vector3f meleePos = gunType.meleePath.get(animations.meleeAnimationProgress); Vector3f nextMeleePos = animations.meleeAnimationProgress + 1 < gunType.meleePath.size() ? gunType.meleePath.get(animations.meleeAnimationProgress + 1) : new Vector3f(); GlStateManager.translate(meleePos.x + (nextMeleePos.x - meleePos.x) * smoothing, meleePos.y + (nextMeleePos.y - meleePos.y) * smoothing, meleePos.z + (nextMeleePos.z - meleePos.z) * smoothing); Vector3f meleeAngles = gunType.meleePathAngles.get(animations.meleeAnimationProgress); Vector3f nextMeleeAngles = animations.meleeAnimationProgress + 1 < gunType.meleePathAngles.size() ? gunType.meleePathAngles.get(animations.meleeAnimationProgress + 1) : new Vector3f(); GlStateManager.rotate(meleeAngles.y + (nextMeleeAngles.y - meleeAngles.y) * smoothing, 0F, 1F, 0F); GlStateManager.rotate(meleeAngles.z + (nextMeleeAngles.z - meleeAngles.z) * smoothing, 0F, 0F, 1F); GlStateManager.rotate(meleeAngles.x + (nextMeleeAngles.x - meleeAngles.x) * smoothing, 1F, 0F, 0F); } // Look at gun stuff float interp = animations.lookAtTimer + smoothing; interp /= animations.lookAtTimes[animations.lookAt.ordinal()]; final Vector3f idlePos = new Vector3f(0.0f, 0.0f, 0.0f); final Vector3f look1Pos = new Vector3f(0.25f, 0.25f, 0.0f); final Vector3f look2Pos = new Vector3f(0.25f, 0.25f, -0.5f); final Vector3f idleAngles = new Vector3f(0.0f, 0.0f, 0.0f); final Vector3f look1Angles = new Vector3f(0.0f, 70.0f, 0.0f); final Vector3f look2Angles = new Vector3f(0.0f, -60.0f, 60.0f); Vector3f startPos, endPos, startAngles, endAngles; switch(animations.lookAt) { default: case NONE: startPos = endPos = idlePos; startAngles = endAngles = idleAngles; break; case LOOK1: startPos = endPos = look1Pos; startAngles = endAngles = look1Angles; break; case LOOK2: startPos = endPos = look2Pos; startAngles = endAngles = look2Angles; break; case TILT1: startPos = idlePos; startAngles = idleAngles; endPos = look1Pos; endAngles = look1Angles; break; case TILT2: startPos = look1Pos; startAngles = look1Angles; endPos = look2Pos; endAngles = look2Angles; break; case UNTILT: startPos = look2Pos; startAngles = look2Angles; endPos = idlePos; endAngles = idleAngles; break; } GlStateManager.rotate(startAngles.y + (endAngles.y - startAngles.y) * interp, 0f, 1f, 0f); GlStateManager.rotate(startAngles.z + (endAngles.z - startAngles.z) * interp, 0f, 0f, 1f); GlStateManager.translate(startPos.x + (endPos.x - startPos.x) * interp, startPos.y + (endPos.y - startPos.y) * interp, startPos.z + (endPos.z - startPos.z) * interp); //GlStateManager.rotate(70f, 0f, 1f, 0f); //GlStateManager.translate(0.25f, 0.25f, 0f); //GlStateManager.rotate(-60f, 0f, 1f, 0f); //GlStateManager.rotate(60f, 0f, 0f, 1f); //GlStateManager.translate(0.25f, 0.25f, -0.5f); GlStateManager.rotate(-animations.recoilAngle * (float)Math.sqrt(gunType.recoil) * 1.5f, 0F, 0F, 1F); GlStateManager.translate(animations.recoilOffset.x, animations.recoilOffset.y, animations.recoilOffset.z); if(model.spinningCocking) { GlStateManager.translate(model.spinPoint.x, model.spinPoint.y, model.spinPoint.z); float pumped = (animations.lastPumped + (animations.pumped - animations.lastPumped) * smoothing); GlStateManager.rotate(pumped * 180F + 180F, 0F, 0F, 1F); GlStateManager.translate(-model.spinPoint.x, -model.spinPoint.y, -model.spinPoint.z); } if(animations.reloading) { //Calculate the amount of tilt required for the reloading animation float effectiveReloadAnimationProgress = animations.lastReloadAnimationProgress + (animations.reloadAnimationProgress - animations.lastReloadAnimationProgress) * smoothing; reloadRotate = 1F; if(effectiveReloadAnimationProgress < model.tiltGunTime) reloadRotate = effectiveReloadAnimationProgress / model.tiltGunTime; if(effectiveReloadAnimationProgress > model.tiltGunTime + model.unloadClipTime + model.loadClipTime) reloadRotate = 1F - (effectiveReloadAnimationProgress - (model.tiltGunTime + model.unloadClipTime + model.loadClipTime)) / model.untiltGunTime; //Rotate the gun dependent on the animation type switch(model.animationType) { case BOTTOM_CLIP: case PISTOL_CLIP: case SHOTGUN: case END_LOADED: { GlStateManager.rotate(60F * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(30F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.25F * reloadRotate, 0F, 0F); break; } case BACK_LOADED: { GlStateManager.rotate(-75F * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(-30F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.5F * reloadRotate, 0F, 0F); break; } case BULLPUP: { GlStateManager.rotate(70F * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(10F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.5F * reloadRotate, -0.2F * reloadRotate, 0F); break; } case RIFLE: { GlStateManager.rotate(30F * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(-30F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.5F * reloadRotate, 0F, -0.5F * reloadRotate); break; } case RIFLE_TOP: case REVOLVER: { GlStateManager.rotate(30F * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(10F * reloadRotate, 0F, 1F, 0F); GlStateManager.rotate(-10F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.1F * reloadRotate, -0.2F * reloadRotate, -0.1F * reloadRotate); break; } case ALT_PISTOL_CLIP: { GlStateManager.rotate(60F * reloadRotate * flip, 0F, 1F, 0F); GlStateManager.translate(0.15F * reloadRotate, 0.25F * reloadRotate, 0F); break; } case STRIKER: { GlStateManager.rotate(-35F * reloadRotate * flip, 1F, 0F, 0F); GlStateManager.translate(0.2F * reloadRotate, 0F, -0.1F * reloadRotate); break; } case GENERIC: { //Gun reloads partly or completely off-screen. GlStateManager.rotate(45F * reloadRotate, 0F, 0F, 1F); GlStateManager.translate(-0.2F * reloadRotate, -0.5F * reloadRotate, 0F); break; } case CUSTOM: { GlStateManager.rotate(model.rotateGunVertical * reloadRotate, 0F, 0F, 1F); GlStateManager.rotate(model.rotateGunHorizontal * reloadRotate, 0F, 1F, 0F); GlStateManager.rotate(model.tiltGun * reloadRotate, 1F, 0F, 0F); GlStateManager.translate(model.translateGun.x * reloadRotate, model.translateGun.y * reloadRotate, model.translateGun.z * reloadRotate); break; } default: break; } } break; } default: break; } renderGun(item, gunType, f, model, animations, reloadRotate); } GlStateManager.popMatrix(); } /** * Gun render method, seperated from transforms so that mecha renderer may also call this */ public void renderGun(ItemStack item, GunType type, float f, ModelGun model, GunAnimations animations, float reloadRotate) { //Make sure we actually have the renderEngine if(renderEngine == null) renderEngine = Minecraft.getMinecraft().renderEngine; //If we have no animation variables, use defaults if(animations == null) animations = GunAnimations.defaults; // Do we have a muzzle flash ModelMuzzleFlash mfModel = type.muzzleFlashModel; boolean renderMuzzleFlash = mfModel != null && animations.muzzleFlash > 0; //Get all the attachments that we may need to render AttachmentType scopeAttachment = type.getScope(item); AttachmentType barrelAttachment = type.getBarrel(item); AttachmentType stockAttachment = type.getStock(item); AttachmentType gripAttachment = type.getGrip(item); ItemStack scopeItemStack = type.getScopeItemStack(item); ItemStack barrelItemStack = type.getBarrelItemStack(item); ItemStack stockItemStack = type.getStockItemStack(item); ItemStack gripItemStack = type.getGripItemStack(item); ItemStack[] bulletStacks = new ItemStack[type.numAmmoItemsInGun]; boolean empty = true; for(int i = 0; i < type.numAmmoItemsInGun; i++) { bulletStacks[i] = ((ItemGun)item.getItem()).getBulletItemStack(item, i); if(bulletStacks[i] != null && bulletStacks[i].getItem() instanceof ItemBullet && bulletStacks[i].getItemDamage() < bulletStacks[i].getMaxDamage()) empty = false; } //Load texture //renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(type.getPaintjob(item.getTagCompound().getString("Paint")))); Paintjob paintjob = type.getPaintjob(item.getItemDamage()); if(bindTextures) { if(PaintableType.HasCustomPaintjob(item)) { renderEngine.bindTexture(PaintableType.GetCustomPaintjobSkinResource(item)); } else { renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(paintjob)); } } if(scopeAttachment != null) GlStateManager.translate(0F, -scopeAttachment.model.renderOffset / 16F, 0F); //Render the gun and default attachment models GlStateManager.pushMatrix(); { GlStateManager.scale(type.modelScale, type.modelScale, type.modelScale); model.renderGun(f); model.renderCustom(f, animations); if(scopeAttachment == null && !model.scopeIsOnSlide && !model.scopeIsOnBreakAction) model.renderDefaultScope(f); if(barrelAttachment == null) model.renderDefaultBarrel(f); if(stockAttachment == null) model.renderDefaultStock(f); if(gripAttachment == null && !model.gripIsOnPump) model.renderDefaultGrip(f); //Render various shoot / reload animated parts //Render the slide GlStateManager.pushMatrix(); { GlStateManager.translate(-(animations.lastGunSlide + (animations.gunSlide - animations.lastGunSlide) * smoothing) * model.gunSlideDistance, 0F, 0F); model.renderSlide(f); if(scopeAttachment == null && model.scopeIsOnSlide) model.renderDefaultScope(f); } GlStateManager.popMatrix(); //Render the break action GlStateManager.pushMatrix(); { GlStateManager.translate(model.barrelBreakPoint.x, model.barrelBreakPoint.y, model.barrelBreakPoint.z); GlStateManager.rotate(reloadRotate * -model.breakAngle, 0F, 0F, 1F); GlStateManager.translate(-model.barrelBreakPoint.x, -model.barrelBreakPoint.y, -model.barrelBreakPoint.z); model.renderBreakAction(f); if(scopeAttachment == null && model.scopeIsOnBreakAction) model.renderDefaultScope(f); } GlStateManager.popMatrix(); //Render the pump-action handle GlStateManager.pushMatrix(); { GlStateManager.translate(-(1 - Math.abs(animations.lastPumped + (animations.pumped - animations.lastPumped) * smoothing)) * model.pumpHandleDistance, 0F, 0F); model.renderPump(f); if(gripAttachment == null && model.gripIsOnPump) model.renderDefaultGrip(f); } GlStateManager.popMatrix(); //Render the minigun barrels if(type.mode == EnumFireMode.MINIGUN) { GlStateManager.pushMatrix(); GlStateManager.translate(model.minigunBarrelOrigin.x, model.minigunBarrelOrigin.y, model.minigunBarrelOrigin.z); GlStateManager.rotate(animations.minigunBarrelRotation, 1F, 0F, 0F); GlStateManager.translate(-model.minigunBarrelOrigin.x, -model.minigunBarrelOrigin.y, -model.minigunBarrelOrigin.z); model.renderMinigunBarrel(f); GlStateManager.popMatrix(); } //Render the cocking handle //Render the revolver barrel GlStateManager.pushMatrix(); { GlStateManager.translate(model.revolverFlipPoint.x, model.revolverFlipPoint.y, model.revolverFlipPoint.z); GlStateManager.rotate(reloadRotate * model.revolverFlipAngle, 1F, 0F, 0F); GlStateManager.translate(-model.revolverFlipPoint.x, -model.revolverFlipPoint.y, -model.revolverFlipPoint.z); model.renderRevolverBarrel(f); } GlStateManager.popMatrix(); //Render the clip GlStateManager.pushMatrix(); { boolean shouldRender = true; //Check to see if the ammo should be rendered first switch(model.animationType) { case END_LOADED: case BACK_LOADED: { if(empty) shouldRender = false; break; } default: break; } //If it should be rendered, do the transformations required if(shouldRender && animations.reloading && Minecraft.getMinecraft().gameSettings.thirdPersonView == 0) { //Calculate the amount of tilt required for the reloading animation float effectiveReloadAnimationProgress = animations.lastReloadAnimationProgress + (animations.reloadAnimationProgress - animations.lastReloadAnimationProgress) * smoothing; float clipPosition = 0F; if(effectiveReloadAnimationProgress > model.tiltGunTime && effectiveReloadAnimationProgress < model.tiltGunTime + model.unloadClipTime) clipPosition = (effectiveReloadAnimationProgress - model.tiltGunTime) / model.unloadClipTime; if(effectiveReloadAnimationProgress >= model.tiltGunTime + model.unloadClipTime && effectiveReloadAnimationProgress < model.tiltGunTime + model.unloadClipTime + model.loadClipTime) clipPosition = 1F - (effectiveReloadAnimationProgress - (model.tiltGunTime + model.unloadClipTime)) / model.loadClipTime; float loadOnlyClipPosition = Math.max(0F, Math.min(1F, 1F - ((effectiveReloadAnimationProgress - model.tiltGunTime) / (model.unloadClipTime + model.loadClipTime)))); //Rotate the gun dependent on the animation type switch(model.animationType) { case BREAK_ACTION: { GlStateManager.translate(model.barrelBreakPoint.x, model.barrelBreakPoint.y, model.barrelBreakPoint.z); GlStateManager.rotate(reloadRotate * -model.breakAngle, 0F, 0F, 1F); GlStateManager.translate(-model.barrelBreakPoint.x, -model.barrelBreakPoint.y, -model.barrelBreakPoint.z); GlStateManager.translate(-1F * clipPosition, 0F, 0F); break; } case REVOLVER: { GlStateManager.translate(model.revolverFlipPoint.x, model.revolverFlipPoint.y, model.revolverFlipPoint.z); GlStateManager.rotate(reloadRotate * model.revolverFlipAngle, 1F, 0F, 0F); GlStateManager.translate(-model.revolverFlipPoint.x, -model.revolverFlipPoint.y, -model.revolverFlipPoint.z); GlStateManager.translate(-1F * clipPosition, 0F, 0F); break; } case BOTTOM_CLIP: { GlStateManager.rotate(-180F * clipPosition, 0F, 0F, 1F); GlStateManager.rotate(60F * clipPosition, 1F, 0F, 0F); GlStateManager.translate(0.5F * clipPosition, 0F, 0F); break; } case PISTOL_CLIP: { GlStateManager.rotate(-90F * clipPosition * clipPosition, 0F, 0F, 1F); GlStateManager.translate(0F, -1F * clipPosition, 0F); break; } case ALT_PISTOL_CLIP: { GlStateManager.rotate(5F * clipPosition, 0F, 0F, 1F); GlStateManager.translate(0F, -3F * clipPosition, 0F); break; } case SIDE_CLIP: { GlStateManager.rotate(180F * clipPosition, 0F, 1F, 0F); GlStateManager.rotate(60F * clipPosition, 0F, 1F, 0F); GlStateManager.translate(0.5F * clipPosition, 0F, 0F); break; } case BULLPUP: { GlStateManager.rotate(-150F * clipPosition, 0F, 0F, 1F); GlStateManager.rotate(60F * clipPosition, 1F, 0F, 0F); GlStateManager.translate(1F * clipPosition, -0.5F * clipPosition, 0F); break; } case P90: { GlStateManager.rotate(-15F * reloadRotate * reloadRotate, 0F, 0F, 1F); GlStateManager.translate(0F, 0.075F * reloadRotate, 0F); GlStateManager.translate(-2F * clipPosition, -0.3F * clipPosition, 0.5F * clipPosition); break; } case RIFLE: { float thing = clipPosition * model.numBulletsInReloadAnimation; int bulletNum = MathHelper.floor(thing); float bulletProgress = thing - bulletNum; GlStateManager.rotate(bulletProgress * 15F, 0F, 1F, 0F); GlStateManager.rotate(bulletProgress * 15F, 0F, 0F, 1F); GlStateManager.translate(bulletProgress * -1F, 0F, bulletProgress * 0.5F); break; } case RIFLE_TOP: { float thing = clipPosition * model.numBulletsInReloadAnimation; int bulletNum = MathHelper.floor(thing); float bulletProgress = thing - bulletNum; GlStateManager.rotate(bulletProgress * 55F, 0F, 1F, 0F); GlStateManager.rotate(bulletProgress * 95F, 0F, 0F, 1F); GlStateManager.translate(bulletProgress * -0.1F, bulletProgress * 1F, bulletProgress * 0.5F); break; } case SHOTGUN: case STRIKER: { float thing = clipPosition * model.numBulletsInReloadAnimation; int bulletNum = MathHelper.floor(thing); float bulletProgress = thing - bulletNum; GlStateManager.rotate(bulletProgress * -30F, 0F, 0F, 1F); GlStateManager.translate(bulletProgress * -0.5F, bulletProgress * -1F, 0F); break; } case CUSTOM: { GlStateManager.rotate(model.rotateClipVertical * clipPosition, 0F, 0F, 1F); GlStateManager.rotate(model.rotateClipHorizontal * clipPosition, 0F, 1F, 0F); GlStateManager.rotate(model.tiltClip * clipPosition, 1F, 0F, 0F); GlStateManager.translate(model.translateClip.x * clipPosition, model.translateClip.y * clipPosition, model.translateClip.z * clipPosition); break; } case END_LOADED: { //float bulletProgress = 1F; //if(effectiveReloadAnimationProgress > model.tiltGunTime) // bulletProgress = 1F - Math.min((effectiveReloadAnimationProgress - model.tiltGunTime) / (model.unloadClipTime + model.loadClipTime), 1); float dYaw = (loadOnlyClipPosition > 0.5F ? loadOnlyClipPosition * 2F - 1F : 0F); GlStateManager.rotate(-45F * dYaw, 0F, 0F, 1F); GlStateManager.translate(-model.endLoadedAmmoDistance * dYaw, -0.5F * dYaw, 0F); float xDisplacement = (loadOnlyClipPosition < 0.5F ? loadOnlyClipPosition * 2F : 1F); GlStateManager.translate(model.endLoadedAmmoDistance * xDisplacement, 0F, 0F); /* GlStateManager.translate(1F * bulletProgress, -3F * bulletProgress, 0F); if(bulletProgress > 0.5F) GlStateManager.rotate(-90F * (bulletProgress * 2F), 0F, 0F, 1F); if(bulletProgress < 0.5F) { GlStateManager.translate(-3F * (bulletProgress - 0.5F), 0F, 0F); } */ break; } case BACK_LOADED: { float dYaw = (loadOnlyClipPosition > 0.5F ? loadOnlyClipPosition * 2F - 1F : 0F); //GlStateManager.rotate(-45F * dYaw, 0F, 0F, 1F); GlStateManager.translate(model.endLoadedAmmoDistance * dYaw, -0.5F * dYaw, 0F); float xDisplacement = (loadOnlyClipPosition < 0.5F ? loadOnlyClipPosition * 2F : 1F); GlStateManager.translate(-model.endLoadedAmmoDistance * xDisplacement, 0F, 0F); } default: break; } } if(shouldRender) model.renderAmmo(f); } GlStateManager.popMatrix(); } GlStateManager.popMatrix(); //Render static attachments //Scope if(scopeAttachment != null) { GlStateManager.pushMatrix(); { Paintjob scopepaintjob = scopeAttachment.getPaintjob(scopeItemStack.getItemDamage()); renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(scopepaintjob)); if(model.scopeIsOnBreakAction) { GlStateManager.translate(model.barrelBreakPoint.x, model.barrelBreakPoint.y, model.barrelBreakPoint.z); GlStateManager.rotate(reloadRotate * -model.breakAngle, 0F, 0F, 1F); GlStateManager.translate(-model.barrelBreakPoint.x, -model.barrelBreakPoint.y, -model.barrelBreakPoint.z); } GlStateManager.translate(model.scopeAttachPoint.x * type.modelScale, model.scopeAttachPoint.y * type.modelScale, model.scopeAttachPoint.z * type.modelScale); if(model.scopeIsOnSlide) GlStateManager.translate(-(animations.lastGunSlide + (animations.gunSlide - animations.lastGunSlide) * smoothing) * model.gunSlideDistance, 0F, 0F); GlStateManager.scale(scopeAttachment.modelScale, scopeAttachment.modelScale, scopeAttachment.modelScale); ModelAttachment scopeModel = scopeAttachment.model; if(scopeModel != null) scopeModel.renderAttachment(f); } GlStateManager.popMatrix(); } //Grip if(gripAttachment != null) { GlStateManager.pushMatrix(); { Paintjob grippaintjob = gripAttachment.getPaintjob(gripItemStack.getItemDamage()); renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(grippaintjob)); GlStateManager.translate(model.gripAttachPoint.x * type.modelScale, model.gripAttachPoint.y * type.modelScale, model.gripAttachPoint.z * type.modelScale); if(model.gripIsOnPump) GlStateManager.translate(-(1 - Math.abs(animations.lastPumped + (animations.pumped - animations.lastPumped) * smoothing)) * model.pumpHandleDistance, 0F, 0F); GlStateManager.scale(gripAttachment.modelScale, gripAttachment.modelScale, gripAttachment.modelScale); ModelAttachment gripModel = gripAttachment.model; if(gripModel != null) gripModel.renderAttachment(f); } GlStateManager.popMatrix(); } //Barrel if(barrelAttachment != null) { GlStateManager.pushMatrix(); { Paintjob barrelpaintjob = barrelAttachment.getPaintjob(barrelItemStack.getItemDamage()); renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(barrelpaintjob)); GlStateManager.translate(model.barrelAttachPoint.x * type.modelScale, model.barrelAttachPoint.y * type.modelScale, model.barrelAttachPoint.z * type.modelScale); GlStateManager.scale(barrelAttachment.modelScale, barrelAttachment.modelScale, barrelAttachment.modelScale); ModelAttachment barrelModel = barrelAttachment.model; if(barrelModel != null) barrelModel.renderAttachment(f); } GlStateManager.popMatrix(); } //Stock if(stockAttachment != null) { GlStateManager.pushMatrix(); { Paintjob stockpaintjob = stockAttachment.getPaintjob(stockItemStack.getItemDamage()); renderEngine.bindTexture(FlansModResourceHandler.getPaintjobTexture(stockpaintjob)); GlStateManager.translate(model.stockAttachPoint.x * type.modelScale, model.stockAttachPoint.y * type.modelScale, model.stockAttachPoint.z * type.modelScale); GlStateManager.scale(stockAttachment.modelScale, stockAttachment.modelScale, stockAttachment.modelScale); ModelAttachment stockModel = stockAttachment.model; if(stockModel != null) stockModel.renderAttachment(f); } GlStateManager.popMatrix(); } if(renderMuzzleFlash) { Vector3f mfPoint = model.muzzleFlashPoint; if(mfPoint == ModelGun.invalid) { mfPoint = model.barrelAttachPoint; } if(barrelAttachment != null) { Vector3f.add(model.barrelAttachPoint, barrelAttachment.model.muzzleFlashPoint, mfPoint); } GlStateManager.pushMatrix(); { GlStateManager.disableLighting(); GlStateManager.enableBlend(); GlStateManager.disableAlpha(); GlStateManager.depthMask(false); GlStateManager.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); int i = 61680; int j = i % 65536; int k = i / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j, (float)k); GlStateManager.color(1f, 1f, 1f); renderEngine.bindTexture(mfModel.GetTexture()); GlStateManager.translate(mfPoint.x * type.modelScale, mfPoint.y * type.modelScale, mfPoint.z * type.modelScale); mfModel.render(null, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, f); GlStateManager.enableLighting(); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); GlStateManager.depthMask(true); } GlStateManager.popMatrix(); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderGunItem.java ================================================ package com.flansmod.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderEntityItem; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.guns.ItemGun; public class RenderGunItem extends RenderEntityItem { private RenderGun gunRenderer; public RenderGunItem(RenderManager renderManager, RenderItem renderItem) { super(renderManager, renderItem); this.gunRenderer = new RenderGun(); } @Override public void doRender(EntityItem entity, double x, double y, double z, float entityYaw, float partialTicks) { ItemStack stack = entity.getItem(); if(stack.getItem() instanceof ItemGun && ((ItemGun)stack.getItem()).GetType().model != null) { GlStateManager.pushMatrix(); GlStateManager.translate(x, y + 0.25D, z); GlStateManager.rotate(entity.ticksExisted + partialTicks, 0F, 1F, 0F); gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, stack); GlStateManager.popMatrix(); } else { super.doRender(entity, x, y, z, partialTicks, partialTicks); } } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderGunItem(manager, Minecraft.getMinecraft().getRenderItem()); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderItemHolder.java ================================================ package com.flansmod.client.model; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import com.flansmod.client.ClientProxy; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.ItemHolderType; import com.flansmod.common.TileEntityItemHolder; import com.flansmod.common.guns.ItemGun; public class RenderItemHolder extends TileEntitySpecialRenderer { public RenderItemHolder() { } @Override public void render(TileEntityItemHolder te, double posX, double posY, double posZ, float p_180535_8_, int p_180535_9_, float f) { TileEntityItemHolder holder = te; if(holder == null || holder.type == null) return; ModelItemHolder model = holder.type.model; if(model != null) { bindTexture(getTexture(holder.type)); GlStateManager.pushMatrix(); GlStateManager.translate((float)posX, (float)posY, (float)posZ); GlStateManager.rotate(180F, 0F, 0F, 1F); GlStateManager.disableLighting(); RenderHelper.enableStandardItemLighting(); GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); switch(EnumFacing.HORIZONTALS[holder.getBlockMetadata()]) { case NORTH: GlStateManager.translate(-1F, 0F, 0F); GlStateManager.rotate(0F, 0F, 1F, 0F); break; case EAST: GlStateManager.translate(-1F, 0F, 1F); GlStateManager.rotate(90F, 0F, 1F, 0F); break; case SOUTH: GlStateManager.translate(0F, 0F, 1F); GlStateManager.rotate(180F, 0F, 1F, 0F); break; case WEST: GlStateManager.rotate(270F, 0F, 1F, 0F); break; default: break; } model.render(); ItemStack stack = holder.getStackInSlot(0); if(stack != null && !stack.isEmpty()) { GlStateManager.rotate(180F, 0F, 0F, 1F); GlStateManager.translate(-0.5F, 0.5F, 0.5F); GlStateManager.translate(model.itemOffset.x, model.itemOffset.y, model.itemOffset.z); GlStateManager.rotate(model.itemRotation.x, 1F, 0F, 0F); GlStateManager.rotate(model.itemRotation.z, 0F, 0F, 1F); GlStateManager.rotate(model.itemRotation.y, 0F, 1F, 0F); if(stack.getItem() instanceof ItemGun && ((ItemGun)stack.getItem()).GetType().model != null) { ClientProxy.gunRenderer.renderItem(CustomItemRenderType.ENTITY, EnumHand.MAIN_HAND, stack); } else Minecraft.getMinecraft().getRenderItem().renderItem(stack, TransformType.NONE); } RenderHelper.disableStandardItemLighting(); GlStateManager.enableLighting(); GlStateManager.popMatrix(); } } protected ResourceLocation getTexture(ItemHolderType type) { return FlansModResourceHandler.getTexture(type); } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderMG.java ================================================ package com.flansmod.client.model; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.guns.EntityMG; public class RenderMG extends Render { public RenderMG(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } @Override public void doRender(EntityMG mg, double d, double d1, double d2, float f, float f1) { bindEntityTexture(mg); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.rotate(180F - mg.direction * 90F, 0.0F, 1.0F, 0.0F); ModelMG model = mg.type.deployableModel; if(model == null) return; //GlStateManager.scale(-1F, -1F, 1.0F); model.renderBipod(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, mg); GlStateManager.rotate(-(mg.prevRotationYaw + (mg.rotationYaw - mg.prevRotationYaw) * f1), 0.0F, 1.0F, 0.0F); model.renderGun(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, f1, mg); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntityMG entity) { return FlansModResourceHandler.getDeployableTexture(entity.type); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderMG(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderMecha.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.ClientProxy; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveablePosition; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.ShootPoint; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.EnumMechaSlotType; import com.flansmod.common.driveables.mechas.ItemMecha; import com.flansmod.common.driveables.mechas.ItemMechaAddon; import com.flansmod.common.driveables.mechas.MechaItemType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.Paintjob; public class RenderMecha extends Render implements CustomItemRenderer { private static final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png"); private static final ItemRenderer renderer = new ItemRenderer(Minecraft.getMinecraft()); private static RenderItem renderItem; public RenderMecha(RenderManager manager) { super(manager); renderItem = Minecraft.getMinecraft().getRenderItem(); shadowSize = 0.5F; } public void doRender(EntityMecha mecha, double d, double d1, double d2, float f, float f1) { bindEntityTexture(mecha); float scale = 1F / 16F; MechaType type = mecha.getMechaType(); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); float dYaw = (mecha.axes.getYaw() - mecha.prevRotationYaw); for(; dYaw > 180F; dYaw -= 360F) { } for(; dYaw <= -180F; dYaw += 360F) { } float dPitch = (mecha.axes.getPitch() - mecha.prevRotationPitch); for(; dPitch > 180F; dPitch -= 360F) { } for(; dPitch <= -180F; dPitch += 360F) { } float dRoll = (mecha.axes.getRoll() - mecha.prevRotationRoll); for(; dRoll > 180F; dRoll -= 360F) { } for(; dRoll <= -180F; dRoll += 360F) { } GlStateManager.rotate(-mecha.prevRotationYaw - dYaw * f1, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(mecha.prevRotationPitch + dPitch * f1, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(mecha.prevRotationRoll + dRoll * f1, 1.0F, 0.0F, 0.0F); float modelScale = mecha.getMechaType().modelScale; ModelMecha model = (ModelMecha)type.model; //Body Render { GlStateManager.pushMatrix(); GlStateManager.scale(modelScale, modelScale, modelScale); if(model != null) model.render(mecha, f1); //Render hips slot : jetpack item ItemStack hipsSlot = mecha.inventory.getStackInSlot(EnumMechaSlotType.hips); if(hipsSlot != null && hipsSlot.getItem() instanceof ItemMechaAddon) { MechaItemType hipsAddon = ((ItemMechaAddon)hipsSlot.getItem()).type; if(hipsAddon.model != null) { GlStateManager.translate(model.hipsAttachmentPoint.x, model.hipsAttachmentPoint.y, model.hipsAttachmentPoint.z); GlStateManager.scale(type.heldItemScale, type.heldItemScale, type.heldItemScale); if(hipsAddon.texture != null) bindTexture(FlansModResourceHandler.getTexture(hipsAddon)); hipsAddon.model.render(mecha, f1); } } GlStateManager.popMatrix(); } //Left arm render if(mecha.isPartIntact(EnumDriveablePart.leftArm)) { bindEntityTexture(mecha); GlStateManager.pushMatrix(); //Get the arm pitch from the mecha entity float smoothedPitch = 0F; if(mecha.getSeat(0) != null) smoothedPitch = mecha.getSeat(0).prevLooking.getPitch() + (mecha.getSeat(0).looking.getPitch() - mecha.getSeat(0).prevLooking.getPitch()) * f1; //Lower Limit if(smoothedPitch > type.lowerArmLimit) smoothedPitch = type.lowerArmLimit; //Upper Limit if(smoothedPitch < -type.upperArmLimit) smoothedPitch = -type.upperArmLimit; //Translate to the arm origin, rotate and render GlStateManager.translate(type.leftArmOrigin.x, mecha.getMechaType().leftArmOrigin.y, mecha.getMechaType().leftArmOrigin.z); GlStateManager.rotate(90F - smoothedPitch, 0F, 0F, 1F); GlStateManager.pushMatrix(); GlStateManager.scale(modelScale, modelScale, modelScale); model.renderLeftArm(scale, mecha, f1); GlStateManager.popMatrix(); //Move to the end of the arm and render the held item GlStateManager.translate(0F + type.leftHandModifierY, -type.armLength - type.leftHandModifierX, 0F + type.leftHandModifierZ); ItemStack holdingStack = mecha.inventory.getStackInSlot(EnumMechaSlotType.leftTool); GlStateManager.scale(modelScale, modelScale, modelScale); if(holdingStack == null || holdingStack.isEmpty()) { model.renderLeftHand(scale, mecha, f1); } else { GlStateManager.scale(type.heldItemScale, type.heldItemScale, type.heldItemScale); renderItem(mecha, holdingStack, 0, true, f1); } GlStateManager.popMatrix(); } //Right arm render if(mecha.isPartIntact(EnumDriveablePart.rightArm)) { bindEntityTexture(mecha); GlStateManager.pushMatrix(); //Get the arm pitch from the mecha entity float smoothedPitch = 0F; if(mecha.getSeat(0) != null) smoothedPitch = mecha.getSeat(0).prevLooking.getPitch() + (mecha.getSeat(0).looking.getPitch() - mecha.getSeat(0).prevLooking.getPitch()) * f1; //Lower Limit if(smoothedPitch > type.lowerArmLimit) smoothedPitch = type.lowerArmLimit; //Upper Limit if(smoothedPitch < -type.upperArmLimit) smoothedPitch = -type.upperArmLimit; //Translate to the arm origin, rotate and render GlStateManager.translate(type.rightArmOrigin.x, mecha.getMechaType().rightArmOrigin.y, mecha.getMechaType().rightArmOrigin.z); GlStateManager.rotate(90F - smoothedPitch, 0F, 0F, 1F); GlStateManager.pushMatrix(); GlStateManager.scale(modelScale, modelScale, modelScale); model.renderRightArm(scale, mecha, f1); GlStateManager.popMatrix(); //Move to the end of the arm and render the held item GlStateManager.translate(0F + type.rightHandModifierY, -type.armLength - type.rightHandModifierX, 0F + type.rightHandModifierZ); GlStateManager.scale(modelScale, modelScale, modelScale); ItemStack holdingStack = mecha.inventory.getStackInSlot(EnumMechaSlotType.rightTool); if(holdingStack == null || holdingStack.isEmpty()) { model.renderRightHand(scale, mecha, f1); } else { GlStateManager.scale(type.heldItemScale, type.heldItemScale, type.heldItemScale); renderItem(mecha, holdingStack, 0, false, f1); } GlStateManager.popMatrix(); } //Debug rendering if(FlansMod.DEBUG) { GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.disableDepth(); //Render boxes GlStateManager.color(1F, 0F, 0F, 0.3F); for(DriveablePart part : mecha.getDriveableData().parts.values()) { if(part.box == null) continue; ModelDriveable.renderOffsetAABB(new AxisAlignedBB(part.box.x / 16F, part.box.y / 16F, part.box.z / 16F, (part.box.x + part.box.w) / 16F, (part.box.y + part.box.h) / 16F, (part.box.z + part.box.d) / 16F), 0, 0, 0); } //Render shoot points GlStateManager.color(0F, 0F, 1F, 0.3F); for(ShootPoint point : type.shootPointsPrimary) { DriveablePosition driveablePosition = point.rootPos; ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } GlStateManager.color(0F, 1F, 0F, 0.3F); for(ShootPoint point : type.shootPointsSecondary) { DriveablePosition driveablePosition = point.rootPos; ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); GlStateManager.disableBlend(); GlStateManager.color(1F, 1F, 1F, 1F); } GlStateManager.popMatrix(); //Leg render if(mecha.isPartIntact(EnumDriveablePart.hips)) { bindEntityTexture(mecha); GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); dYaw = mecha.legAxes.getYaw() - mecha.prevLegsYaw; for(; dYaw > 180F; dYaw -= 360F) { } for(; dYaw <= -180F; dYaw += 360F) { } GlStateManager.rotate(-dYaw * f1 - mecha.prevLegsYaw, 0F, 1F, 0F); GlStateManager.rotate(mecha.prevRotationPitch + dPitch * f1, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(mecha.prevRotationRoll + dRoll * f1, 1.0F, 0.0F, 0.0F); GlStateManager.scale(modelScale, modelScale, modelScale); if(model != null) { float legLength = type.legLength; float rearlegLength = type.RearlegLength; float frontlegLength = type.FrontlegLength; float legTrans = type.LegTrans; float rearlegTrans = type.RearLegTrans; float frontlegTrans = type.FrontLegTrans; float legsYaw = (float)Math.sin(((mecha.ticksExisted) + f1) / type.legSwingTime) * mecha.legSwing; float footH = (float)Math.sin(legsYaw) * legLength; float footV = (float)Math.cos(legsYaw) * legLength; float footRH = (float)Math.sin(legsYaw) * rearlegLength; float footRV = (float)Math.cos(legsYaw) * rearlegLength; float footFH = (float)Math.sin(legsYaw) * frontlegLength; float footFV = (float)Math.cos(legsYaw) * frontlegLength; //Hips model.renderHips(scale, mecha, f1); GlStateManager.pushMatrix(); { GlStateManager.translate(legTrans, legLength, 0F); //Left Foot GlStateManager.pushMatrix(); GlStateManager.translate(footH, -footV, 0F); model.renderLeftFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Right Foot GlStateManager.pushMatrix(); GlStateManager.translate(-footH, -footV, 0F); model.renderRightFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Left Leg GlStateManager.pushMatrix(); GlStateManager.rotate(legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -legLength, 0F); model.renderLeftLeg(scale, mecha, f1); GlStateManager.popMatrix(); //Right Leg GlStateManager.pushMatrix(); GlStateManager.rotate(-legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -legLength, 0F); model.renderRightLeg(scale, mecha, f1); GlStateManager.popMatrix(); } GlStateManager.popMatrix(); GlStateManager.pushMatrix(); { GlStateManager.translate(rearlegTrans, rearlegLength, 0F); //Left Rear Foot GlStateManager.pushMatrix(); GlStateManager.translate(-footRH, -footRV, 0F); model.renderLeftRearFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Right Rear Foot GlStateManager.pushMatrix(); GlStateManager.translate(footRH, -footRV, 0F); model.renderRightRearFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Left Rear Leg GlStateManager.pushMatrix(); GlStateManager.rotate(-legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -rearlegLength, 0F); model.renderLeftRearLeg(scale, mecha, f1); GlStateManager.popMatrix(); //Right Leg GlStateManager.pushMatrix(); GlStateManager.rotate(legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -rearlegLength, 0F); model.renderRightRearLeg(scale, mecha, f1); GlStateManager.popMatrix(); } GlStateManager.popMatrix(); GlStateManager.pushMatrix(); { GlStateManager.translate(frontlegTrans, frontlegLength, 0F); //Left Front Foot GlStateManager.pushMatrix(); GlStateManager.translate(-footFH, -footFV, 0F); model.renderLeftFrontFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Right Front Foot GlStateManager.pushMatrix(); GlStateManager.translate(footFH, -footFV, 0F); model.renderRightFrontFoot(scale, mecha, f1); GlStateManager.popMatrix(); //Left Front Leg GlStateManager.pushMatrix(); GlStateManager.rotate(-legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -frontlegLength, 0F); model.renderLeftFrontLeg(scale, mecha, f1); GlStateManager.popMatrix(); //Right Front Leg GlStateManager.pushMatrix(); GlStateManager.rotate(legsYaw * 180F / 3.14159265F, 0F, 0F, 1F); GlStateManager.translate(0F, -frontlegLength, 0F); model.renderRightFrontLeg(scale, mecha, f1); GlStateManager.popMatrix(); } GlStateManager.popMatrix(); } GlStateManager.popMatrix(); } } @Override protected ResourceLocation getEntityTexture(EntityMecha entity) { DriveableType type = entity.getDriveableType(); Paintjob paintjob = type.getPaintjob(entity.getDriveableData().paintjobID); return FlansModResourceHandler.getPaintjobTexture(paintjob); } private void renderItem(EntityMecha mecha, ItemStack stack, int par3, boolean leftHand, float dT) { GlStateManager.pushMatrix(); TextureManager texturemanager = Minecraft.getMinecraft().getTextureManager(); Item item = stack.getItem(); //Render tools if(item instanceof ItemMechaAddon) { GlStateManager.rotate(-90F, 0F, 0F, 1F); GlStateManager.translate(0F, 0F, 0F); ItemMechaAddon toolItem = (ItemMechaAddon)item; MechaItemType toolType = toolItem.type; bindTexture(FlansModResourceHandler.getTexture(toolType)); if(toolType.model != null) { toolType.model.render(mecha, dT); GlStateManager.pushMatrix(); if((leftHand && mecha.primaryShootHeld) || (!leftHand && mecha.secondaryShootHeld)) { GlStateManager.rotate(25F * (float)mecha.ticksExisted, 1F, 0F, 0F); } toolType.model.renderDrill(mecha, dT); GlStateManager.popMatrix(); toolType.model.renderSaw(mecha, dT, (leftHand && mecha.primaryShootHeld) || (!leftHand && mecha.secondaryShootHeld)); } } else if(item instanceof ItemGun && ((ItemGun)item).GetType().model != null) { GunType gunType = ((ItemGun)item).GetType(); ModelGun model = gunType.model; GlStateManager.rotate(-90F, 0F, 0F, 1F); texturemanager.bindTexture(FlansModResourceHandler.getTexture(gunType)); ClientProxy.gunRenderer.renderGun(stack, gunType, 1F / 16F, model, leftHand ? mecha.leftAnimations : mecha.rightAnimations, 0F); } else { GlStateManager.rotate(-135F, 0F, 0F, 1F); GlStateManager.translate(0F, -0.4F, 0F); IBakedModel ibakedmodel = renderItem.getItemModelMesher().getItemModel(stack); renderItem.renderItem(stack, ibakedmodel); GlStateManager.disableRescaleNormal(); } GlStateManager.popMatrix(); } @Override public void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data) { GlStateManager.pushMatrix(); if(item != null && item.getItem() instanceof ItemMecha) { MechaType mechaType = ((ItemMecha)item.getItem()).type; if(mechaType.model != null) { float scale = 2F; switch(type) { case INVENTORY: { scale = 1.0F; GlStateManager.translate(0F, -0.35F, 0F); break; } case ENTITY: { scale = 1.5F; //GlStateManager.rotate(((EntityItem)data[1]).ticksExisted, 0F, 1F, 0F); break; } case EQUIPPED: { GlStateManager.rotate(0F, 0F, 0F, 1F); GlStateManager.rotate(270F, 1F, 0F, 0F); GlStateManager.rotate(270F, 0F, 1F, 0F); GlStateManager.translate(0F, 0.25F, 0F); scale = 0.5F; break; } case EQUIPPED_FIRST_PERSON: { //GlStateManager.rotate(25F, 0F, 0F, 1F); GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-0.5F, 0.5F, -0.5F); scale = 1F; break; } default: break; } GlStateManager.scale(scale / mechaType.cameraDistance, scale / mechaType.cameraDistance, scale / mechaType.cameraDistance); Minecraft.getMinecraft().renderEngine.bindTexture(FlansModResourceHandler.getTexture(mechaType)); ModelDriveable model = mechaType.model; model.render(mechaType); } } GlStateManager.popMatrix(); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderMecha(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderNull.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntitySeat; public class RenderNull extends Render { private static final ResourceLocation texture = new ResourceLocation("Flan", "null.png"); public RenderNull(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } public void func_157_a(Entity entity, double d, double d1, double d2, float f, float f1) { } @Override public void doRender(Entity entity, double d, double d1, double d2, float f, float f1) { if(FlansMod.DEBUG) { GlStateManager.pushMatrix(); GlStateManager.translate((float)d, (float)d1, (float)d2); GlStateManager.rotate(-entity.rotationYaw, 0F, 1F, 0F); GlStateManager.disableTexture2D(); //GlStateManager.enableBlend(); //GlStateManager.disableDepth(); if(entity instanceof EntitySeat) { GlStateManager.color(1F, 1F, 1F, 1F); } else GlStateManager.color(0F, 0F, 1F, 0.3F); GlStateManager.scale(-1F, 1F, -1F); renderOffsetAABB(new AxisAlignedBB(-1F, -1F, -1F, 1F, 1F, 1F), 0, 0, 0); GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); GlStateManager.disableBlend(); GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.popMatrix(); } } @Override protected ResourceLocation getEntityTexture(Entity entity) { return texture; } protected ModelBase model; public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderNull(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderParachute.java ================================================ package com.flansmod.client.model; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.IRenderFactory; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.tools.EntityParachute; public class RenderParachute extends Render { public RenderParachute(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; } @Override public void doRender(EntityParachute entity, double d0, double d1, double d2, float f, float f1) { bindEntityTexture(entity); GlStateManager.pushMatrix(); GlStateManager.translate((float)d0, (float)d1, (float)d2); GlStateManager.rotate(-f, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(-entity.prevRotationPitch - (entity.rotationPitch - entity.prevRotationPitch) * f1, 1.0F, 0.0F, 0.0F); ModelBase model = entity.type.model; model.render(entity, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F); GlStateManager.popMatrix(); } @Override protected ResourceLocation getEntityTexture(EntityParachute entity) { return FlansModResourceHandler.getTexture(entity.type); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderParachute(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderPlane.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveablePosition; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.ItemPlane; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.Propeller; import com.flansmod.common.driveables.ShootPoint; import com.flansmod.common.guns.Paintjob; public class RenderPlane extends Render implements CustomItemRenderer { public RenderPlane(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; MinecraftForge.EVENT_BUS.register(this); } public void render(EntityPlane entityPlane, double d, double d1, double d2, float f, float f1) { bindEntityTexture(entityPlane); PlaneType type = entityPlane.getPlaneType(); GlStateManager.pushMatrix(); GlStateManager.translate(d, d1, d2); float dYaw = (entityPlane.axes.getYaw() - entityPlane.prevRotationYaw); while(dYaw > 180F) { dYaw -= 360F; } while(dYaw <= -180F) { dYaw += 360F; } float dPitch = (entityPlane.axes.getPitch() - entityPlane.prevRotationPitch); while(dPitch > 180F) { dPitch -= 360F; } while(dPitch <= -180F) { dPitch += 360F; } float dRoll = (entityPlane.axes.getRoll() - entityPlane.prevRotationRoll); while(dRoll > 180F) { dRoll -= 360F; } while(dRoll <= -180F) { dRoll += 360F; } GlStateManager.rotate(180F - entityPlane.prevRotationYaw - dYaw * f1, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(entityPlane.prevRotationPitch + dPitch * f1, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(entityPlane.prevRotationRoll + dRoll * f1, 1.0F, 0.0F, 0.0F); float modelScale = type.modelScale; GlStateManager.scale(modelScale, modelScale, modelScale); ModelPlane model = (ModelPlane)type.model; if(model != null) { model.render(entityPlane, f1); // Render helicopter main rotors for(int i = 0; i < model.heliMainRotorModels.length; i++) { GlStateManager.pushMatrix(); GlStateManager.translate(model.heliMainRotorOrigins[i].x, model.heliMainRotorOrigins[i].y, model.heliMainRotorOrigins[i].z); GlStateManager.rotate((entityPlane.propAngle + f1 * entityPlane.throttle / 7F) * model.heliRotorSpeeds[i] * 1440F /3.14159265F, 0.0F, 1.0F, 0.0F); GlStateManager.translate(-model.heliMainRotorOrigins[i].x, -model.heliMainRotorOrigins[i].y,-model.heliMainRotorOrigins[i].z); model.renderRotor(entityPlane, 0.0625F, i); //work GlStateManager.popMatrix(); } // Render helicopter tail rotors for(int i = 0; i < model.heliTailRotorModels.length; i++) { GlStateManager.pushMatrix(); GlStateManager.translate(model.heliTailRotorOrigins[i].x, model.heliTailRotorOrigins[i].y, model.heliTailRotorOrigins[i].z); GlStateManager.rotate((entityPlane.propAngle + f1 * entityPlane.throttle / 7F) * 1440F / 3.14159265F, 0.0F, 0.0F, 1.0F); GlStateManager.translate(-model.heliTailRotorOrigins[i].x, -model.heliTailRotorOrigins[i].y, -model.heliTailRotorOrigins[i].z); model.renderTailRotor(entityPlane, 0.0625F, i); //work GlStateManager.popMatrix(); } } if(FlansMod.DEBUG) { GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.enableAlpha(); GlStateManager.disableDepth(); GlStateManager.disableLighting(); GlStateManager.color(1F, 0F, 0F, 0.3F); GlStateManager.scale(-1F, 1F, -1F); for(DriveablePart part : entityPlane.getDriveableData().parts.values()) { if(part.box == null) continue; GlStateManager.color(1F, entityPlane.isPartIntact(part.type) ? 1F : 0F, 0F, 0.3F); ModelDriveable.renderOffsetAABB(new AxisAlignedBB(part.box.x, part.box.y, part.box.z, (part.box.x + part.box.w), (part.box.y + part.box.h), (part.box.z + part.box.d)), 0, 0, 0); } GlStateManager.color(1F, 1F, 0F, 0.3F); for(Propeller prop : type.propellers) { ModelDriveable.renderOffsetAABB(new AxisAlignedBB(prop.x / 16F - 0.25F, prop.y / 16F - 0.25F, prop.z / 16F - 0.25F, prop.x / 16F + 0.25F, prop.y / 16F + 0.25F, prop.z / 16F + 0.25F), 0, 0, 0); } // Render shoot points GlStateManager.color(1F, 0F, 1F, 0.3F); for(ShootPoint point : type.shootPointsPrimary) { DriveablePosition driveablePosition = point.rootPos; ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } GlStateManager.color(0F, 1F, 0F, 0.3F); for(ShootPoint point : type.shootPointsSecondary) { DriveablePosition driveablePosition = point.rootPos; ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); GlStateManager.disableBlend(); GlStateManager.color(1F, 1F, 1F, 1F); } GlStateManager.popMatrix(); } @Override public boolean shouldRender(EntityPlane entity, ICamera camera, double camX, double camY, double camZ) { return true; } @Override public void doRender(EntityPlane entity, double d, double d1, double d2, float f, float f1) { //The plane is rendered by the renderWorld Method } @Override protected ResourceLocation getEntityTexture(EntityPlane entity) { DriveableType type = entity.getDriveableType(); Paintjob paintjob = type.getPaintjob(entity.getDriveableData().paintjobID); return FlansModResourceHandler.getPaintjobTexture(paintjob); } @SubscribeEvent(priority = EventPriority.HIGHEST) public void renderWorld(RenderWorldLastEvent event) { //Get the world World world = Minecraft.getMinecraft().world; if(world == null) return; //Get the camera frustrum for clipping Entity camera = Minecraft.getMinecraft().getRenderViewEntity(); double x = camera.lastTickPosX + (camera.posX - camera.lastTickPosX) * event.getPartialTicks(); double y = camera.lastTickPosY + (camera.posY - camera.lastTickPosY) * event.getPartialTicks(); double z = camera.lastTickPosZ + (camera.posZ - camera.lastTickPosZ) * event.getPartialTicks(); //Frustum frustrum = new Frustum(); //frustrum.setPosition(x, y, z); //Push GlStateManager.pushMatrix(); //Setup lighting Minecraft.getMinecraft().entityRenderer.enableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableLighting(); GlStateManager.disableBlend(); RenderHelper.enableStandardItemLighting(); //GlStateManager.translate(-x, -y, -z); for(Object entity : world.loadedEntityList) { if(entity instanceof EntityPlane) { EntityPlane plane = (EntityPlane)entity; int i = plane.getBrightnessForRender(); if(plane.isBurning()) { i = 15728880; } int j = i % 65536; int k = i / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); render(plane, (plane.prevPosX - x) + (plane.posX - plane.prevPosX) * event.getPartialTicks(), (plane.prevPosY - y) + (plane.posY - plane.prevPosY) * event.getPartialTicks(), (plane.prevPosZ - z) + (plane.posZ - plane.prevPosZ) * event.getPartialTicks(), 0F, event.getPartialTicks()); } } //Reset Lighting Minecraft.getMinecraft().entityRenderer.disableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableLighting(); //Pop GlStateManager.popMatrix(); } @Override public void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data) { GlStateManager.pushMatrix(); if(item != null && item.getItem() instanceof ItemPlane) { PlaneType planeType = ((ItemPlane)item.getItem()).type; if(planeType.model != null) { float scale = 0.5F; switch(type) { case INVENTORY: { GlStateManager.rotate(180F, 0F, 1F, 0F); scale = 1.0F; break; } case ENTITY: { scale = 1.5F; break; } case EQUIPPED: { GlStateManager.rotate(0F, 0F, 0F, 1F); GlStateManager.rotate(270F, 1F, 0F, 0F); GlStateManager.rotate(270F, 0F, 1F, 0F); GlStateManager.translate(0F, 0.25F, 0F); scale = 0.5F; break; } case EQUIPPED_FIRST_PERSON: { if(hand == EnumHand.MAIN_HAND) { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-0.5F, 0.5F, -0.5F); GlStateManager.rotate(180F, 0F, 1F, 0F); } else { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-0.5F, 0.5F, -2.3F); GlStateManager.rotate(180F, 0F, 1F, 0F); } scale = 1F; break; } default: break; } GlStateManager.scale(scale / planeType.cameraDistance, scale / planeType.cameraDistance, scale / planeType.cameraDistance); Minecraft.getMinecraft().renderEngine.bindTexture(FlansModResourceHandler.getTexture(planeType)); ModelDriveable model = planeType.model; model.render(planeType); } } GlStateManager.popMatrix(); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderPlane(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/model/RenderVehicle.java ================================================ package com.flansmod.client.model; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.IRenderFactory; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveablePosition; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.ItemVehicle; import com.flansmod.common.driveables.ShootPoint; import com.flansmod.common.driveables.VehicleType; import com.flansmod.common.guns.Paintjob; public class RenderVehicle extends Render implements CustomItemRenderer { public RenderVehicle(RenderManager renderManager) { super(renderManager); shadowSize = 0.5F; MinecraftForge.EVENT_BUS.register(this); } public void render(EntityVehicle vehicle, double d, double d1, double d2, float f, float f1) { bindEntityTexture(vehicle); VehicleType type = vehicle.getVehicleType(); GlStateManager.pushMatrix(); { GlStateManager.translate((float)d, (float)d1, (float)d2); float dYaw = (vehicle.axes.getYaw() - vehicle.prevRotationYaw); while(dYaw > 180F) { dYaw -= 360F; } while(dYaw <= -180F) { dYaw += 360F; } float dPitch = (vehicle.axes.getPitch() - vehicle.prevRotationPitch); while(dPitch > 180F) { dPitch -= 360F; } while(dPitch <= -180F) { dPitch += 360F; } float dRoll = (vehicle.axes.getRoll() - vehicle.prevRotationRoll); while(dRoll > 180F) { dRoll -= 360F; } while(dRoll <= -180F) { dRoll += 360F; } GlStateManager.rotate(180F - vehicle.prevRotationYaw - dYaw * f1, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(vehicle.prevRotationPitch + dPitch * f1, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(vehicle.prevRotationRoll + dRoll * f1, 1.0F, 0.0F, 0.0F); GlStateManager.rotate(180F, 0.0F, 1.0F, 0.0F); float modelScale = type.modelScale; GlStateManager.pushMatrix(); { float recoilDPos = (float)Math.sin(Math.toRadians(vehicle.recoilPos)) - (float)Math.sin(Math.toRadians(vehicle.lastRecoilPos)); float recoilPos = (float)Math.sin(Math.toRadians(vehicle.lastRecoilPos)) + recoilDPos * f1; GlStateManager.scale(modelScale, modelScale, modelScale); ModelVehicle modVehicle = (ModelVehicle)type.model; if(modVehicle != null) modVehicle.render(vehicle, f1); for(int i = 0; i < vehicle.trackLinksLeft.length; i++) { AnimTrackLink link = vehicle.trackLinksLeft[i]; float rotZ = link.zRot; GlStateManager.pushMatrix(); GlStateManager.translate(link.position.x / 16F, link.position.y / 16F, link.position.z / 16F); for(; rotZ > 180F; rotZ -= 360F) { } for(; rotZ <= -180F; rotZ += 360F) { } GlStateManager.rotate(rotZ * (float)(180 / Math.PI), 0, 0, 1); modVehicle.renderFancyTracks(vehicle, f1); GlStateManager.popMatrix(); } for(int i = 0; i < vehicle.trackLinksRight.length; i++) { AnimTrackLink link = vehicle.trackLinksRight[i]; float rotZ = link.zRot; for(; rotZ > 180F; rotZ -= 360F) { } for(; rotZ <= -180F; rotZ += 360F) { } GlStateManager.pushMatrix(); GlStateManager.translate(link.position.x / 16F, link.position.y / 16F, link.position.z / 16F); GlStateManager.rotate(rotZ * (float)(180 / Math.PI), 0, 0, 1); modVehicle.renderFancyTracks(vehicle, f1); GlStateManager.popMatrix(); } GlStateManager.pushMatrix(); if(type.turretOrigin != null && vehicle.isPartIntact(EnumDriveablePart.turret) && vehicle.getSeat(0) != null) { dYaw = (vehicle.getSeat(0).looking.getYaw() - vehicle.getSeat(0).prevLooking.getYaw()); while(dYaw > 180F) { dYaw -= 360F; } while(dYaw <= -180F) { dYaw += 360F; } float yaw = vehicle.getSeat(0).prevLooking.getYaw() + dYaw * f1; GlStateManager.translate(type.turretOrigin.x, type.turretOrigin.y, type.turretOrigin.z); GlStateManager.rotate(-yaw, 0.0F, 1.0F, 0.0F); GlStateManager.translate(-type.turretOrigin.x, -type.turretOrigin.y, -type.turretOrigin.z); if(modVehicle != null) modVehicle.renderTurret(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, vehicle, f1); //rotate and render barrel if(modVehicle != null) { EntitySeat[] seats = vehicle.getSeats(); GlStateManager.translate(modVehicle.barrelAttach.x, modVehicle.barrelAttach.y, -modVehicle.barrelAttach.z); float bPitch = (seats[0].looking.getPitch() - seats[0].prevLooking.getPitch()); float aPitch = seats[0].prevLooking.getPitch() + bPitch * f1; GlStateManager.rotate(-aPitch, 0F, 0F, 1F); GlStateManager.translate(recoilPos * -(5F / 16F), 0F, 0F); modVehicle.renderAnimBarrel(0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, vehicle, f1); } if(FlansMod.DEBUG) { GlStateManager.translate(type.turretOrigin.x, type.turretOrigin.y, type.turretOrigin.z); GlStateManager.rotate(-vehicle.getSeat(0).looking.getPitch(), 0.0F, 0.0F, 1.0F); GlStateManager.translate(-type.turretOrigin.x, -type.turretOrigin.y, -type.turretOrigin.z); //Render shoot points GlStateManager.color(0F, 0F, 1F, 0.3F); for(ShootPoint point : type.shootPointsPrimary) { DriveablePosition driveablePosition = point.rootPos; if(driveablePosition.part == EnumDriveablePart.turret) { renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } } GlStateManager.color(0F, 1F, 0F, 0.3F); for(ShootPoint point : type.shootPointsSecondary) { DriveablePosition driveablePosition = point.rootPos; if(driveablePosition.part == EnumDriveablePart.turret) renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } } } GlStateManager.popMatrix(); if(modVehicle != null) { GlStateManager.pushMatrix(); GlStateManager.translate(modVehicle.drillHeadOrigin.x, modVehicle.drillHeadOrigin.y, modVehicle.drillHeadOrigin.z); GlStateManager.rotate(vehicle.harvesterAngle * 50F, 1.0F, 0.0F, 0.0F); GlStateManager.translate(-modVehicle.drillHeadOrigin.x, -modVehicle.drillHeadOrigin.y, -modVehicle.drillHeadOrigin.z); modVehicle.renderDrillBit(vehicle, f1); GlStateManager.popMatrix(); } } GlStateManager.popMatrix(); if(FlansMod.DEBUG) { GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.disableDepth(); GlStateManager.color(1F, 0F, 0F, 0.3F); GlStateManager.scale(1F, 1F, 1F); for(DriveablePart part : vehicle.getDriveableData().parts.values()) { if(part.box == null) continue; ModelDriveable.renderOffsetAABB(new AxisAlignedBB(part.box.x, part.box.y, part.box.z, (part.box.x + part.box.w), (part.box.y + part.box.h), (part.box.z + part.box.d)), 0, 0, 0); } // Render shoot points GlStateManager.color(0F, 0F, 1F, 0.3F); for(ShootPoint point : type.shootPointsPrimary) { DriveablePosition driveablePosition = point.rootPos; if(driveablePosition.part != EnumDriveablePart.turret) { ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } } GlStateManager.color(0F, 1F, 0F, 0.3F); for(ShootPoint point : type.shootPointsSecondary) { DriveablePosition driveablePosition = point.rootPos; if(driveablePosition.part != EnumDriveablePart.turret) ModelDriveable.renderOffsetAABB(new AxisAlignedBB( driveablePosition.position.x - 0.25F, driveablePosition.position.y - 0.25F, driveablePosition.position.z - 0.25F, driveablePosition.position.x + 0.25F, driveablePosition.position.y + 0.25F, driveablePosition.position.z + 0.25F), 0, 0, 0); } GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); GlStateManager.disableBlend(); GlStateManager.color(1F, 1F, 1F, 1F); } } GlStateManager.popMatrix(); } @Override public void doRender(EntityVehicle entity, double d, double d1, double d2, float f, float f1) { //render((EntityVehicle)entity, d, d1, d2, f, f1); //The Vehicle is rendered by the renderWorld Method } @Override protected ResourceLocation getEntityTexture(EntityVehicle entity) { DriveableType type = entity.getDriveableType(); Paintjob paintjob = type.getPaintjob(entity.getDriveableData().paintjobID); return FlansModResourceHandler.getPaintjobTexture(paintjob); } @Override public void renderItem(CustomItemRenderType type, EnumHand hand, ItemStack item, Object... data) { GlStateManager.pushMatrix(); if(item != null && item.getItem() instanceof ItemVehicle) { VehicleType vehicleType = ((ItemVehicle)item.getItem()).type; if(vehicleType.model != null) { float scale = 1F; switch(type) { case ENTITY: { scale = 1.5F; break; } case INVENTORY: { scale = 0.70F; GlStateManager.translate(0F, -0.05F, 0F); break; } case EQUIPPED: { GlStateManager.rotate(0F, 0F, 0F, 1F); GlStateManager.rotate(270F, 1F, 0F, 0F); GlStateManager.rotate(270F, 0F, 1F, 0F); GlStateManager.translate(0F, 0.25F, 0F); scale = 0.5F; break; } case EQUIPPED_FIRST_PERSON: { if(hand == EnumHand.MAIN_HAND) { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-0.5F, 0.5F, -0.5F); } else { GlStateManager.rotate(45F, 0F, 1F, 0F); GlStateManager.translate(-0.5F, 0.5F, -2.3F); } break; } default: break; } GlStateManager.scale(scale / vehicleType.cameraDistance, scale / vehicleType.cameraDistance, scale / vehicleType.cameraDistance); Minecraft.getMinecraft().renderEngine.bindTexture(FlansModResourceHandler.getTexture(vehicleType)); ModelDriveable model = vehicleType.model; model.render(vehicleType); } } GlStateManager.popMatrix(); } @SubscribeEvent(priority = EventPriority.HIGHEST) public void renderWorld(RenderWorldLastEvent event) { //Get the world World world = Minecraft.getMinecraft().world; if(world == null) return; //Get the camera frustrum for clipping Entity camera = Minecraft.getMinecraft().getRenderViewEntity(); double x = camera.lastTickPosX + (camera.posX - camera.lastTickPosX) * event.getPartialTicks(); double y = camera.lastTickPosY + (camera.posY - camera.lastTickPosY) * event.getPartialTicks(); double z = camera.lastTickPosZ + (camera.posZ - camera.lastTickPosZ) * event.getPartialTicks(); //Frustum frustrum = new Frustum(); //frustrum.setPosition(x, y, z); //Push GlStateManager.pushMatrix(); //Setup lighting Minecraft.getMinecraft().entityRenderer.enableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.enableLighting(); GlStateManager.enableLighting(); GlStateManager.disableBlend(); RenderHelper.enableStandardItemLighting(); //GlStateManager.translate(-(float)x, -(float)y, -(float)z); for(Object entity : world.loadedEntityList) { if(entity instanceof EntityVehicle) { EntityVehicle vehicle = (EntityVehicle)entity; int i = vehicle.getBrightnessForRender(); if(vehicle.isBurning()) { i = 15728880; } int j = i % 65536; int k = i / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); render(vehicle, (vehicle.prevPosX - x) + (vehicle.posX - vehicle.prevPosX) * event.getPartialTicks(), (vehicle.prevPosY - y) + (vehicle.posY - vehicle.prevPosY) * event.getPartialTicks(), (vehicle.prevPosZ - z) + (vehicle.posZ - vehicle.prevPosZ) * event.getPartialTicks(), 0F, event.getPartialTicks()); } } //Reset Lighting Minecraft.getMinecraft().entityRenderer.disableLightmap(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableLighting(); //Pop GlStateManager.popMatrix(); } public static class Factory implements IRenderFactory { @Override public Render createRenderFor(RenderManager manager) { return new RenderVehicle(manager); } } } ================================================ FILE: src/main/java/com/flansmod/client/teams/ClientTeamsData.java ================================================ package com.flansmod.client.teams; import net.minecraft.client.Minecraft; import net.minecraftforge.fml.client.FMLClientHandler; import com.flansmod.client.gui.teams.GuiEditLoadout; import com.flansmod.client.gui.teams.GuiLandingPage; import com.flansmod.client.gui.teams.GuiMissionResults; import com.flansmod.client.gui.teams.GuiOpenRewardBox; import com.flansmod.client.gui.teams.GuiTeamScores; import com.flansmod.client.gui.teams.GuiTeamSelect; import com.flansmod.client.gui.teams.GuiVoting; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.network.PacketOpenRewardBox; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.RewardBoxInstance; import com.flansmod.common.teams.RoundFinishedData; public class ClientTeamsData { public enum RoundFinishedStage { NOT_FINISHED, SCORES, RANK_UPDATE, VOTING, } public static PlayerRankData theRankData = null; public static LoadoutPool currentPool = null; public static RoundFinishedData roundFinishedData; public static int timeLeftInStage = 0; public static int timeLeftTotal = 0; public static RoundFinishedStage stage = RoundFinishedStage.NOT_FINISHED; public static String motd = ""; public static void Tick() { timeLeftTotal--; timeLeftInStage--; switch(stage) { case NOT_FINISHED: break; case RANK_UPDATE: { if(StageFinished()) { if(roundFinishedData.votingEnabled) { timeLeftInStage = roundFinishedData.votingTime; SwitchTo(RoundFinishedStage.VOTING); } else { SwitchTo(RoundFinishedStage.NOT_FINISHED); } } break; } case SCORES: { if(StageFinished()) { timeLeftInStage = roundFinishedData.rankUpdateTime; SwitchTo(RoundFinishedStage.RANK_UPDATE); } break; } case VOTING: { if(StageFinished()) { SwitchTo(RoundFinishedStage.NOT_FINISHED); } break; } default: break; } if(stage != RoundFinishedStage.NOT_FINISHED && Minecraft.getMinecraft().currentScreen == null) { OpenMenu(); } } private static boolean StageFinished() { return timeLeftInStage <= 0; } private static void SwitchTo(RoundFinishedStage s) { stage = s; OpenMenu(); } private static void OpenMenu() { switch(stage) { case NOT_FINISHED: if((Minecraft.getMinecraft().currentScreen instanceof GuiVoting) || (Minecraft.getMinecraft().currentScreen instanceof GuiTeamScores) || (Minecraft.getMinecraft().currentScreen instanceof GuiMissionResults)) { Minecraft.getMinecraft().displayGuiScreen(null); } break; case RANK_UPDATE: Minecraft.getMinecraft().displayGuiScreen(new GuiMissionResults()); break; case SCORES: Minecraft.getMinecraft().displayGuiScreen(new GuiTeamScores()); break; case VOTING: Minecraft.getMinecraft().displayGuiScreen(new GuiVoting()); break; default: break; } } public static void SetRoundFinishedData(RoundFinishedData data) { roundFinishedData = data; if(theRankData == null) { FlansMod.Assert(false, "Rank data null"); return; } theRankData.pendingXP = roundFinishedData.pendingXP; } public static void StartTimers() { FlansMod.log.info("Starting round finished timers. Scores:" + roundFinishedData.scoresTime + " RankUpdate:" + roundFinishedData.rankUpdateTime + " Voting:" + roundFinishedData.votingTime); timeLeftInStage = roundFinishedData.scoresTime; timeLeftTotal = roundFinishedData.scoresTime + roundFinishedData.rankUpdateTime + roundFinishedData.votingTime; SwitchTo(RoundFinishedStage.SCORES); } public static void UpdateNumVotes(RoundFinishedData data) { if(roundFinishedData == null || roundFinishedData.votingOptions == null) { return; } for(int i = 0; i < data.votingOptions.length; i++) { if(i < roundFinishedData.votingOptions.length) { roundFinishedData.votingOptions[i].numVotes = data.votingOptions[i].numVotes; } else { FlansMod.Assert(false, "Voting options mismatch"); } } } public static void UnlockReward(int boxHash, int unlockHash) { Paintjob paintjob = Paintjob.GetPaintjob(unlockHash); if(paintjob == null) { FlansMod.Assert(false, "Null paintjob unlock!"); return; } boolean found = false; for(RewardBoxInstance instance : theRankData.rewardBoxData) { if(!instance.opened && instance.unlockHash == 0 && instance.boxHash == boxHash) { found = true; instance.opened = true; instance.unlockHash = unlockHash; break; } } if(!found) { FlansMod.Assert(false, "Never had this reward box!"); return; } if(Minecraft.getMinecraft().currentScreen instanceof GuiOpenRewardBox) { ((GuiOpenRewardBox)Minecraft.getMinecraft().currentScreen).SetTarget(paintjob); } } public static void OpenLandingPage() { FMLClientHandler.instance().getClient().displayGuiScreen(new GuiLandingPage()); } public static void OpenEditLoadoutPage(int loadout) { FMLClientHandler.instance().getClient().displayGuiScreen(new GuiEditLoadout(loadout)); } public static void OpenTeamSelectPage() { FMLClientHandler.instance().getClient().displayGuiScreen(new GuiTeamSelect()); } public static void OpenRewardBox(int i) { FlansMod.getPacketHandler().sendToServer(new PacketOpenRewardBox(currentPool.rewardBoxes[i])); FMLClientHandler.instance().getClient().displayGuiScreen(new GuiOpenRewardBox(currentPool.rewardBoxes[i])); } public static void AddRewardBox(int boxHash) { theRankData.AddRewardBoxInstance(RewardBoxInstance.CreateClientRewardBoxInstance(boxHash, 0)); } } ================================================ FILE: src/main/java/com/flansmod/client/tmt/Angle3D.java ================================================ package com.flansmod.client.tmt; /** * This class handles angles. Basically all it does it store angles. You can * directly alter the angles. * * @author GaryCXJk */ public class Angle3D { /** * The constructor to create a new Angle3D. * * @param x the x-rotation * @param y the y-rotation * @param z the z-rotation */ public Angle3D(float x, float y, float z) { angleX = x; angleY = y; angleZ = z; } /** * Adds the given angles to the current angles. * * @param x the x-rotation * @param y the y-rotation * @param z the z-rotation */ public void addAngles(float x, float y, float z) { angleX += x; angleY += y; angleZ += z; } /** * Adds the angles of another Angle3D to the current angles. * * @param angles the Angle3D */ public void addAngles(Angle3D angles) { angleX += angles.angleX; angleY += angles.angleY; angleZ += angles.angleZ; } /** * Multiplies the angles with the given angles. * * @param x the x-rotation * @param y the y-rotation * @param z the z-rotation */ public void multiplyAngles(float x, float y, float z) { angleX *= x; angleY *= y; angleZ *= z; } /** * Multiplies the angles with a given Angle3D. * * @param angles the Angle3D */ public void multiplyAngles(Angle3D angles) { angleX *= angles.angleX; angleY *= angles.angleY; angleZ *= angles.angleZ; } /** * Gets the center angle between two angles. * * @param angles1 the first Angle3D * @param angles2 the second Angle3D * @return the center Angle3D */ public static Angle3D getCenter(Angle3D angles1, Angle3D angles2) { Angle3D angles = new Angle3D(0, 0, 0); angles.addAngles(angles1); angles.addAngles(angles2); angles.multiplyAngles(0.5F, 0.5F, 0.5F); return angles; } /** * Copies the current Angle3D over to a new Angle3D instance. * * @return a copy of the Angle3D instance */ public Angle3D copy() { return new Angle3D(angleX, angleY, angleZ); } public float angleX; public float angleY; public float angleZ; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/Bone.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import net.minecraft.client.model.ModelRenderer; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; /** * The Bone class makes it possible to create skeletons, which should help you out in * animating your mobs a little bit more easy. However, since you won't work with a * graphical interface, creating bones will be different from what you are probably * used to. *

* First, you will need to instantiate every Bone in the constructor of your model * file. The default orientation, when all angles are set to zero, will be in the * vector (0, 0, length), meaning it will always point backwards on a regular model. * You can also set what its parent node is. If a Bone does not have a parent node, * it is assumed it is the root node. Each Bone can only have one parent, but several * children. Also, all children will inherit the offset position of the root node. *

* The neutral position basically defines in what direction the Bone normally faces * when in rest. This will not affect the rotation of any model currently attached * to it or the rotation of the child nodes, but will affect the position of the * child nodes when recalculating their positions. The length always defines how far * each child Bone will be placed, since child Bones are always placed at the end of * their parent Bone. *

* Once you're ready to render, you can call the prepareDraw method. You only need * to apply it to one Bone, since it will always search for the root node to execute * the code there. It will then automatically rotate every child Bone and places * them at the right position. Finally, use the setAnglesToModels method to rotate * each model and place them at the correct spot. Note that if you also apply custom * rotation for the individual models that you should apply that after you've run * setAnglesToModels, since this will override the settings the model originally had. * The best way to solve this is to make a separate method to rotate the Bones. *

* The following would be an example of a biped with a skeleton. It takes ModelBiped * as an example and extends it with a skeleton. First, we have the part that goes * in the constructor. *
 * // First, the origin will be placed. This is where the rest is attached to.
 * skeletonOrigin = new Bone(0, 0, 0, 0);
 *
 * // Next, the entire skeleton is built up.
 * skeletonHead = new Bone(-3.141593F / 2, 0, 0, 0, skeletonOrigin);
 * skeletonBody = new Bone(3.141593F / 2, 0, 0, 12, skeletonOrigin);
 * skeletonShoulderRight = new Bone(0, -3.141593F / 2, 0, 5, skeletonOrigin);
 * skeletonShoulderLeft = new Bone(0, 3.141593F / 2, 0, 5, skeletonOrigin);
 * skeletonArmRight = new Bone(3.141593F / 2, 0, 0, 12, skeletonShoulderRight);
 * skeletonArmLeft = new Bone(3.141593F / 2, 0, 0, 12, skeletonShoulderLeft);
 * skeletonPelvisRight = new Bone(0, -3.141593F / 2, 0, 2, skeletonBody);
 * skeletonPelvisLeft = new Bone(0, 3.141593F / 2, 0, 2, skeletonBody);
 * skeletonLegRight = new Bone(3.141593F / 2, 0, 0, 12, skeletonPelvisRight);
 * skeletonLegLeft = new Bone(3.141593F / 2, 0, 0, 12, skeletonPelvisLeft);
 *
 * // Finally, all models will be attached to the skeletons.
 * skeletonHead.addModel(bipedHead);
 * skeletonHead.addModel(bipedHeadwear);
 * skeletonBody.addModel(bipedBody);
 * skeletonArmRight.addModel(bipedRightArm);
 * skeletonArmLeft.addModel(bipedLeftArm);
 * skeletonLegRight.addModel(bipedRightLeg);
 * skeletonLegLeft.addModel(bipedRightLeg);
 * 
*

* After that, you could replace anything in the setRotationAngles method with * the following code. It's not a complete code, but you'll get the basics. *

*
 * skeletonHead.relativeAngles.angleY = f3 / 57.29578F;
 * skeletonHead.relativeAngles.angleX = f4 / 57.29578F;
 * skeletonArmRight.relativeAngles.angleX = MathHelper.cos(f * 0.6662F + 3.141593F) * 2.0F * f1 * 0.5F;
 * skeletonArmRight.relativeAngles.angleZ = 0.0F;
 * skeletonArmLeft.relativeAngles.angleX = MathHelper.cos(f * 0.6662F) * 2.0F * f1 * 0.5F;
 * skeletonArmLeft.relativeAngles.angleZ = 0.0F;
 * skeletonLegRight.relativeAngles.angleX = MathHelper.cos(f * 0.6662F) * 1.4F * f1;
 * skeletonLegRight.relativeAngles.angleY = 0.0F;
 * skeletonLegLeft.relativeAngles.angleX = MathHelper.cos(f * 0.6662F + 3.141593F) * 1.4F * f1;
 * skeletonLegLeft.relativeAngles.angleY = 0.0F;
 * 
*

* Finally, in the render method, you could use the following code. *

*
 * setRotationAngles(f, f1, f2, f3, f4, f5);
 * skeletonOrigin.prepareDraw();
 * skeletonOrigin.setAnglesToModels();
 * 
*

* This should generate the same animation of the regular biped. Don't forget to add * the individual render methods for each model though, as it won't automatically * render them. *

* * @author GaryCXJk */ public class Bone { /** * Constructor to create a bone. * * @param x the x-rotation of the bone * @param y the y-rotation of the bone * @param z the z-rotation of the bone * @param l the length of the bone */ public Bone(float x, float y, float z, float l) { neutralAngles = new Angle3D(x, y, z); relativeAngles = new Angle3D(0, 0, 0); absoluteAngles = new Angle3D(0, 0, 0); positionVector = new Vec3d(0, 0, 0); length = l; childNodes = new ArrayList<>(); models = new ArrayList<>(); modelBaseRot = new HashMap<>(); parentNode = null; offsetX = 0; offsetY = 0; offsetZ = 0; positionVector = new Vec3d(0, 0, 0); } /** * Constructor to create a bone. * * @param xOrig the x-offset of the origin * @param yOrig the y-offset of the origin * @param zOrig the z-offset of the origin * @param xRot the x-rotation of the bone * @param yRot the y-rotation of the bone * @param zRot the z-rotation of the bone * @param l the length of the bone */ public Bone(float xOrig, float yOrig, float zOrig, float xRot, float yRot, float zRot, float l) { this(xRot, yRot, zRot, l); positionVector = setOffset(xOrig, yOrig, zOrig); } /** * Constructor to create a bone. This attaches the bone to a parent bone, and will * calculate its current position relative to the origin. * * @param x the x-rotation of the bone * @param y the y-rotation of the bone * @param z the z-rotation of the bone * @param l the length of the bone * @param parent the parent Bone node this Bone is attached to */ public Bone(float x, float y, float z, float l, Bone parent) { this(x, y, z, l); attachBone(parent); } /** * Detaches the bone from its parent. */ public void detachBone() { parentNode.childNodes.remove(this); parentNode = null; } /** * Attaches the bone to a parent. If the parent is already set, detaches the bone * from the previous parent. * * @param parent the parent Bone node this Bone is attached to */ public void attachBone(Bone parent) { if(parentNode != null) detachBone(); parentNode = parent; parent.addChildBone(this); offsetX = parent.offsetX; offsetY = parent.offsetY; offsetZ = parent.offsetZ; resetOffset(); } /** * Sets the current offset of the parent root Bone. Note that this will * always set the parent root Bone, not the current Bone, as its offset * is determined by the offset, rotation and length of its parent. * * @param x the x-position * @param y the y-position * @param z the z-position * @return a Vec3d with the new coordinates of the current bone */ public Vec3d setOffset(float x, float y, float z) { if(parentNode != null) { Vec3d vector = parentNode.setOffset(x, y, z); offsetX = (float)vector.x; offsetY = (float)vector.y; offsetZ = (float)vector.z; return vector; } offsetX = x; offsetY = y; offsetZ = z; resetOffset(true); return new Vec3d(x, y, z); } /** * Resets the offset. */ public void resetOffset() { resetOffset(false); } /** * Resets the offset. * * @param doRecursive */ public void resetOffset(boolean doRecursive) { if(parentNode != null) { positionVector = new Vec3d(0, 0, parentNode.length); parentNode.setVectorRotations(positionVector); positionVector = positionVector.add(parentNode.positionVector); } if(doRecursive && !childNodes.isEmpty()) { for(Bone childNode : childNodes) { childNode.resetOffset(doRecursive); } } } /** * Sets the current neutral rotation of the bone. This is the same rotation as in * the constructor. * * @param x the x-rotation of the bone * @param y the y-rotation of the bone * @param z the z-rotation of the bone */ public void setNeutralRotation(float x, float y, float z) { neutralAngles.angleX = x; neutralAngles.angleY = y; neutralAngles.angleZ = z; } /** * Gets the root parent bone. * * @return the root parent Bone. */ public Bone getRootParent() { if(parentNode == null) return this; else return parentNode.getRootParent(); } /** * Attaches a model to the bone. Its base rotation will be set to the neutral * rotation of the model. * * @param model the model to attach */ public void addModel(ModelRenderer model) { addModel(model, false); } /** * Attaches a model to the bone. If inherit is true, it sets the base rotation * to the neutral rotation of the Bone, otherwise it's set to the neutral * rotation of the model. * * @param model the model to attach * @param inherit whether the model should inherit the Bone's base rotations */ public void addModel(ModelRenderer model, boolean inherit) { addModel(model, 0F, 0F, 0F, inherit); } /** * Attaches a model to the bone. If inherit is true, it sets the base rotation * to the neutral rotation of the Bone, otherwise it's set to the neutral * rotation of the model. When isUpright is set, the model will be rotated * (-PI / 2, 0, 0). * * @param model the model to attach * @param inherit whether the model should inherit the Bone's base rotations * @param isUpright whether the model is modeled in the upright position */ public void addModel(ModelRenderer model, boolean inherit, boolean isUpright) { addModel(model, 0F, 0F, 0F, inherit, isUpright); } /** * Attaches a model to the bone with a given base rotation. * * @param model the model to attach * @param x the base x-rotation * @param y the base y-rotation * @param z the base z-rotation */ public void addModel(ModelRenderer model, float x, float y, float z) { addModel(model, x, y, z, false); } /** * Attaches a model to the bone with a given base rotation. When inherit is * true, it will add the Bone's neutral rotation to the given angles. * * @param model the model to attach * @param x the base x-rotation * @param y the base y-rotation * @param z the base z-rotation * @param inherit whether the model should inherit the Bone's base rotations */ public void addModel(ModelRenderer model, float x, float y, float z, boolean inherit) { addModel(model, x, y, z, inherit, false); } /** * Attaches a model to the bone with a given base rotation. When inherit is * true, it will add the Bone's neutral rotation to the given angles. * When isUpright is set, the model will be rotated (-PI / 2, 0, 0). * * @param model the model to attach * @param x the base x-rotation * @param y the base y-rotation * @param z the base z-rotation * @param inherit whether the model should inherit the Bone's base rotations * @param isUpright whether the model is modeled in the upright position */ public void addModel(ModelRenderer model, float x, float y, float z, boolean inherit, boolean isUpright) { if(inherit) { x += neutralAngles.angleX + (isUpright ? (float)Math.PI / 2 : 0); y += neutralAngles.angleY; z += neutralAngles.angleZ; } models.add(model); modelBaseRot.put(model, new Angle3D(x, y, z)); } /** * Removes the given model from the Bone. Always detach the model before adding * it to another Bone. The best thing however is to just keep the model to one * bone. * * @param model the model to remove from the bone */ public void removeModel(ModelRenderer model) { models.remove(model); modelBaseRot.remove(model); } /** * Gets the current absolute angles. The absolute angle is calculated by getting * the sum of all parent Bones' relative angles plus the current relative angle. * This must be called after using the prepareDraw method. * * @return an Angle3D object which holds the current angles of the current node. */ public Angle3D getAbsoluteAngle() { return new Angle3D(absoluteAngles.angleX, absoluteAngles.angleY, absoluteAngles.angleZ); } /** * Gets the current position of the bone. You should call this after all rotations * and positions are applied, e.g. after prepareDraw has been called. * * @return a vector containing the current position relative to the origin. */ public Vec3d getPosition() { return new Vec3d(positionVector.x, positionVector.y, positionVector.z); } protected void addChildBone(Bone bone) { childNodes.add(bone); } /** * Prepares the bones for rendering. This will automatically take the root Bone * if it isn't. */ public void prepareDraw() { if(parentNode != null) parentNode.prepareDraw(); else { setAbsoluteRotations(); setVectors(); } } /** * Sets the current rotation of the Bone, not calculating any parent bones in. * * @param x * @param y * @param z */ public void setRotations(float x, float y, float z) { relativeAngles.angleX = x; relativeAngles.angleY = y; relativeAngles.angleZ = z; } protected void setAbsoluteRotations() { absoluteAngles.angleX = relativeAngles.angleX; absoluteAngles.angleY = relativeAngles.angleY; absoluteAngles.angleZ = relativeAngles.angleZ; for(Bone childNode : childNodes) { childNode.setAbsoluteRotations(absoluteAngles.angleX, absoluteAngles.angleY, absoluteAngles.angleZ); } } protected void setAbsoluteRotations(float x, float y, float z) { absoluteAngles.angleX = relativeAngles.angleX + x; absoluteAngles.angleY = relativeAngles.angleY + y; absoluteAngles.angleZ = relativeAngles.angleZ + z; for(Bone childNode : childNodes) { childNode.setAbsoluteRotations(absoluteAngles.angleX, absoluteAngles.angleY, absoluteAngles.angleZ); } } protected void setVectorRotations(Vec3d vector) { float x = neutralAngles.angleX + absoluteAngles.angleX; float y = neutralAngles.angleY + absoluteAngles.angleY; float z = neutralAngles.angleZ + absoluteAngles.angleZ; setVectorRotations(vector, x, y, z); } protected void setVectorRotations(Vec3d vector, float xRot, float yRot, float zRot) { float xC = MathHelper.cos(xRot); float xS = MathHelper.sin(xRot); float yC = MathHelper.cos(yRot); float yS = MathHelper.sin(yRot); float zC = MathHelper.cos(zRot); float zS = MathHelper.sin(zRot); double xVec = vector.x; double yVec = vector.y; double zVec = vector.z; // rotation around x double xy = xC * yVec - xS * zVec; double xz = xC * zVec + xS * yVec; // rotation around y double yz = yC * xz - yS * xVec; double yx = yC * xVec + yS * xz; // rotation around z double zx = zC * yx - zS * xy; double zy = zC * xy + zS * yx; xVec = zx; yVec = zy; zVec = yz; vector = new Vec3d(xVec, yVec, zVec); } protected void add(Vec3d destVec, Vec3d srcVec) { destVec = destVec.add(srcVec); } protected void setVectors() { Vec3d tempVec = new Vec3d(0, 0, length); positionVector = new Vec3d(offsetX, offsetY, offsetZ); add(tempVec, positionVector); setVectorRotations(tempVec); for(Bone childNode : childNodes) { childNode.setVectors(tempVec); } } protected void setVectors(Vec3d vector) { positionVector = vector; Vec3d tempVec = new Vec3d(0, 0, length); setVectorRotations(tempVec); add(tempVec, vector); for(Bone childNode : childNodes) { childNode.setVectors(tempVec); } } /** * Sets the current angles of the Bone to the models attached to it. */ public void setAnglesToModels() { for(ModelRenderer currentModel : models) { Angle3D baseAngles = modelBaseRot.get(currentModel); currentModel.rotateAngleX = baseAngles.angleX + absoluteAngles.angleX; currentModel.rotateAngleY = baseAngles.angleY + absoluteAngles.angleY; currentModel.rotateAngleZ = baseAngles.angleZ + absoluteAngles.angleZ; currentModel.rotationPointX = (float)positionVector.x; currentModel.rotationPointY = (float)positionVector.y; currentModel.rotationPointZ = (float)positionVector.z; } for(Bone childNode : childNodes) { childNode.setAnglesToModels(); } } protected Angle3D neutralAngles; public Angle3D relativeAngles; protected Angle3D absoluteAngles; private Vec3d positionVector; private float length; private Bone parentNode; protected ArrayList childNodes; private ArrayList models; private Map modelBaseRot; private float offsetX; private float offsetY; private float offsetZ; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/Coord2D.java ================================================ package com.flansmod.client.tmt; /** * This class represents a coordinate space and its UV coordinates. This allows for * easier flat shape planning. * * @author GaryCXJk */ public class Coord2D { public Coord2D(double x, double y) { xCoord = x; yCoord = y; uCoord = (int)Math.floor(x); vCoord = (int)Math.floor(y); } public Coord2D(double x, double y, int u, int v) { this(x, y); uCoord = u; vCoord = v; } public double xCoord; public double yCoord; public int uCoord; public int vCoord; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/ModelPool.java ================================================ package com.flansmod.client.tmt; import java.io.File; import java.util.HashMap; import java.util.Map; import net.minecraftforge.fml.common.Loader; import com.flansmod.common.FlansMod; public class ModelPool { public static ModelPoolEntry addFile(String file, Class modelClass, Map group, Map textureGroup) { ModelPoolEntry entry = null; if(modelMap.containsKey(file)) { entry = modelMap.get(file); entry.applyGroups(group, textureGroup); return entry; } try { entry = (ModelPoolEntry)modelClass.newInstance(); } catch(Exception e) { FlansMod.log.error("A new " + entry.getClass().getName() + " could not be initialized."); FlansMod.log.error(e.getMessage()); return null; } File modelFile = null; for(int i = 0; i < resourceDir.length && (modelFile == null || !modelFile.exists()); i++) { String absPath = new File(Loader.instance().getConfigDir().getParent(), resourceDir[i]).getAbsolutePath(); if(!absPath.endsWith("/") || !absPath.endsWith("\\")) absPath += "/"; modelFile = entry.checkValidPath(absPath + file); } if(modelFile == null || !modelFile.exists()) { FlansMod.log.warn("The model with the name " + file + " does not exist."); return null; } entry.groups = new HashMap<>(); entry.textures = new HashMap<>(); entry.name = file; entry.setGroup("0"); entry.setTextureGroup("0"); entry.getModel(modelFile); entry.applyGroups(group, textureGroup); modelMap.put(file, entry); return entry; } private static Map modelMap = new HashMap<>(); private static String[] resourceDir = new String[]{ "/resources/models/", "/resources/mod/models/", "/Flan/" }; public static final Class OBJ = ModelPoolObjEntry.class; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/ModelPoolEntry.java ================================================ package com.flansmod.client.tmt; import java.io.File; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; public abstract class ModelPoolEntry { public File checkValidPath(String path) { File file = null; for(int index = 0; index < fileExtensions.length && (file == null || !file.exists()); index++) { String absPath = path; if(!path.endsWith("." + fileExtensions[index])) absPath += "." + fileExtensions[index]; file = new File(absPath); } if(file == null || !file.exists()) return null; return file; } public abstract void getModel(File file); /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * * @param groupName the name of the transformation group you want to switch to */ protected void setGroup(String groupName) { setGroup(groupName, new Bone(0, 0, 0, 0), 1D); } /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * * @param groupName the name of the transformation group you want to switch to * @param bone the Bone this transformation group is attached to * @param weight the weight of the transformation group */ protected void setGroup(String groupName, Bone bone, double weight) { if(groups.isEmpty() || !groups.containsKey(groupName)) groups.put(groupName, new TransformGroupBone(bone, weight)); group = groups.get(groupName); } /** * Sets the current texture group, which is used to switch the * textures on a per-model base. Do note that any model that is * rendered afterwards will use the same texture. To counter it, * set a default texture, either at initialization or before * rendering. * * @param groupName The name of the texture group. If the texture * group doesn't exist, it creates a new group automatically. */ protected void setTextureGroup(String groupName) { if(textures.isEmpty() || !textures.containsKey(groupName)) { textures.put(groupName, new TextureGroup()); } texture = textures.get(groupName); } protected void applyGroups(Map groupsMap, Map texturesMap) { Set groupsCol = groups.keySet(); Collection texturesCol = textures.keySet(); Iterator groupsItr = groupsCol.iterator(); Iterator texturesItr = texturesCol.iterator(); while(groupsItr.hasNext()) { int nameIdx = 0; String groupKey = groupsItr.next(); String currentGroup = name + "_" + nameIdx + ":" + groupKey; while(groupsMap.size() > 0 && groupsMap.containsKey(currentGroup)) { nameIdx++; currentGroup = name + "_" + nameIdx + ":" + groupKey; } groupsMap.put(currentGroup, groups.get(groupKey)); } while(texturesItr.hasNext()) { int nameIdx = 0; String groupKey = texturesItr.next(); String currentGroup = name + "_" + nameIdx + ":" + groupKey; while(groupsMap.size() > 0 && texturesMap.containsKey(currentGroup)) { nameIdx++; currentGroup = name + "_" + nameIdx + ":" + groupKey; } texturesMap.put(currentGroup, textures.get(groupKey)); } } public String name; public PositionTransformVertex[] vertices; public TexturedPolygon[] faces; public Map groups; public Map textures; protected TransformGroupBone group; protected TextureGroup texture; protected String[] fileExtensions; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/ModelPoolObjEntry.java ================================================ package com.flansmod.client.tmt; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.ArrayList; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class ModelPoolObjEntry extends ModelPoolEntry { public ModelPoolObjEntry() { fileExtensions = new String[]{"obj"}; } @Override public void getModel(File file) { try { BufferedReader in = new BufferedReader(new FileReader(file)); String s; ArrayList verts = new ArrayList<>(); ArrayList uvs = new ArrayList<>(); ArrayList normals = new ArrayList<>(); ArrayList face = new ArrayList<>(); while((s = in.readLine()) != null) { if(s.contains("#")) { s = s.substring(0, s.indexOf("#")); } s = s.trim(); if(s.equals("")) continue; if(s.startsWith("g ")) { setTextureGroup(s.substring(s.indexOf(" ") + 1).trim()); continue; } if(s.startsWith("v ")) { s = s.substring(s.indexOf(" ") + 1).trim(); float[] v = new float[3]; for(int i = 0; i < 3; i++) { int ind = s.indexOf(" "); if(ind > -1) v[i] = Float.parseFloat(s.substring(0, ind)); else v[i] = Float.parseFloat(s); s = s.substring(s.indexOf(" ") + 1).trim(); } float flt = v[2]; v[2] = -v[1]; v[1] = flt; verts.add(new PositionTransformVertex(v[0], v[1], v[2], 0, 0)); continue; } if(s.startsWith("vt ")) { s = s.substring(s.indexOf(" ") + 1).trim(); float[] v = new float[2]; for(int i = 0; i < 2; i++) { int ind = s.indexOf(" "); if(ind > -1) v[i] = Float.parseFloat(s.substring(0, ind)); else v[i] = Float.parseFloat(s); s = s.substring(s.indexOf(" ") + 1).trim(); } uvs.add(new float[]{v[0], 1F - v[1]}); continue; } if(s.startsWith("vn ")) { s = s.substring(s.indexOf(" ") + 1).trim(); float[] v = new float[3]; for(int i = 0; i < 3; i++) { int ind = s.indexOf(" "); if(ind > -1) v[i] = Float.parseFloat(s.substring(0, ind)); else v[i] = Float.parseFloat(s); s = s.substring(s.indexOf(" ") + 1).trim(); } float flt = v[2]; v[2] = v[1]; v[1] = flt; normals.add(new float[]{v[0], v[1], v[2]}); continue; } if(s.startsWith("f ")) { s = s.substring(s.indexOf(" ") + 1).trim(); ArrayList v = new ArrayList<>(); String s1; int finalPhase = 0; float[] normal = new float[]{0F, 0F, 0F}; ArrayList iNormal = new ArrayList<>(); do { int vInt; float[] curUV; float[] curNormals; int ind = s.indexOf(" "); s1 = s; if(ind > -1) s1 = s.substring(0, ind); if(s1.contains("/")) { String[] f = s1.split("/"); vInt = Integer.parseInt(f[0]) - 1; if(f[1].equals("")) f[1] = f[0]; int vtInt = Integer.parseInt(f[1]) - 1; if(uvs.size() > vtInt) curUV = uvs.get(vtInt); else curUV = new float[]{0, 0}; int vnInt = 0; if(f.length == 3) { if(f[2].equals("")) f[2] = f[0]; vnInt = Integer.parseInt(f[2]) - 1; } else vnInt = Integer.parseInt(f[0]) - 1; if(normals.size() > vnInt) curNormals = normals.get(vnInt); else curNormals = new float[]{0, 0, 0}; } else { vInt = Integer.parseInt(s1) - 1; if(uvs.size() > vInt) curUV = uvs.get(vInt); else curUV = new float[]{0, 0}; if(normals.size() > vInt) curNormals = normals.get(vInt); else curNormals = new float[]{0, 0, 0}; } iNormal.add(new Vec3d(curNormals[0], curNormals[1], curNormals[2])); normal[0] += curNormals[0]; normal[1] += curNormals[1]; normal[2] += curNormals[2]; if(vInt < verts.size()) { v.add(verts.get(vInt).setTexturePosition(curUV[0], curUV[1])); if(verts.get(vInt) instanceof PositionTransformVertex) { verts.get(vInt).addGroup(group); } } if(ind > -1) s = s.substring(s.indexOf(" ") + 1).trim(); else finalPhase++; } while(finalPhase < 1); float d = MathHelper.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); normal[0] /= d; normal[1] /= d; normal[2] /= d; PositionTextureVertex[] vToArr = new PositionTextureVertex[v.size()]; for(int i = 0; i < v.size(); i++) { vToArr[i] = v.get(i); } TexturedPolygon poly = new TexturedPolygon(vToArr); poly.setNormals(normal[0], normal[1], normal[2]); poly.setNormals(iNormal); face.add(poly); texture.addPoly(poly); } } vertices = new PositionTransformVertex[verts.size()]; for(int i = 0; i < verts.size(); i++) { vertices[i] = verts.get(i); } faces = new TexturedPolygon[face.size()]; for(int i = 0; i < face.size(); i++) { faces[i] = face.get(i); } in.close(); } catch(Throwable ignored) { } } } ================================================ FILE: src/main/java/com/flansmod/client/tmt/ModelRendererTurbo.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.lwjgl.opengl.GL11; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.model.TexturedQuad; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; /** * An extension to the ModelRenderer class. It basically is a copy to ModelRenderer, * however, it contains various new methods to make your models. *

* Since the ModelRendererTurbo class gets loaded during startup, the models made * can be very complex. This is why I can afford to add, for example, Wavefont OBJ * support or have the addSprite method, methods that add a lot of vertices and * polygons. * * @author GaryCXJk */ public class ModelRendererTurbo extends ModelRenderer { public ModelRendererTurbo(ModelBase modelbase, String s) { super(modelbase, s); flip = false; compiled = false; displayList = 0; mirror = false; showModel = true; field_1402_i = false; vertices = new PositionTextureVertex[0]; faces = new TexturedPolygon[0]; forcedRecompile = false; transformGroup = new HashMap<>(); transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); textureGroup = new HashMap<>(); textureGroup.put("0", new TextureGroup()); currentTextureGroup = textureGroup.get("0"); boxName = s; defaultTexture = ""; useLegacyCompiler = false; } public ModelRendererTurbo(ModelBase modelbase) { this(modelbase, null); } /** * Creates a new ModelRenderTurbo object. It requires the coordinates of the * position of the texture. * * @param modelbase * @param textureX the x-coordinate on the texture * @param textureY the y-coordinate on the texture */ public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY) { this(modelbase, textureX, textureY, 64, 32); } /** * Creates a new ModelRenderTurbo object. It requires the coordinates of the * position of the texture, but also allows you to specify the width and height * of the texture, allowing you to use bigger textures instead. * * @param modelbase * @param textureX * @param textureY * @param textureU * @param textureV */ public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV) { this(modelbase); textureOffsetX = textureX; textureOffsetY = textureY; textureWidth = textureU; textureHeight = textureV; } /** * Creates a new polygon. * * @param verts an array of vertices */ public void addPolygon(PositionTextureVertex[] verts) { copyTo(verts, new TexturedPolygon[]{new TexturedPolygon(verts)}); } /** * Creates a new polygon, and adds UV mapping to it. * * @param verts an array of vertices * @param uv an array of UV coordinates */ public void addPolygon(PositionTextureVertex[] verts, int[][] uv) { try { for(int i = 0; i < verts.length; i++) { verts[i] = verts[i].setTexturePosition(uv[i][0] / textureWidth, uv[i][1] / textureHeight); } } finally { addPolygon(verts); } } /** * Creates a new polygon with a given UV. * * @param verts an array of vertices * @param u1 * @param v1 * @param u2 * @param v2 */ public void addPolygon(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { copyTo(verts, new TexturedPolygon[]{addPolygonReturn(verts, u1, v1, u2, v2)}); } private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2, float q1, float q2, float q3, float q4) { if(verts.length < 3) return null; float uOffs = 1.0F / (textureWidth * 10.0F); float vOffs = 1.0F / (textureHeight * 10.0F); if(verts.length < 4) { float xMin = -1; float yMin = -1; float xMax = 0; float yMax = 0; for(PositionTextureVertex vert : verts) { float xPos = vert.texturePositionX; float yPos = vert.texturePositionY; xMax = Math.max(xMax, xPos); xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); yMax = Math.max(yMax, yPos); yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); } float uMin = u1 / textureWidth + uOffs; float vMin = v1 / textureHeight + vOffs; float uSize = (u2 - u1) / textureWidth - uOffs * 2; float vSize = (v2 - v1) / textureHeight - vOffs * 2; float xSize = xMax - xMin; float ySize = yMax - yMin; for(int i = 0; i < verts.length; i++) { float xPos = verts[i].texturePositionX; float yPos = verts[i].texturePositionY; xPos = (xPos - xMin) / xSize; yPos = (yPos - yMin) / ySize; verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); } } else { verts[0] = verts[0].setTexturePosition((u2 / textureWidth - uOffs) * q1, (v1 / textureHeight + vOffs) * q1, q1); verts[1] = verts[1].setTexturePosition((u1 / textureWidth + uOffs) * q2, (v1 / textureHeight + vOffs) * q2, q2); verts[2] = verts[2].setTexturePosition((u1 / textureWidth + uOffs) * q3, (v2 / textureHeight - vOffs) * q3, q3); verts[3] = verts[3].setTexturePosition((u2 / textureWidth - uOffs) * q4, (v2 / textureHeight - vOffs) * q4, q4); } return new TexturedPolygon(verts); } private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { if(verts.length < 3) return null; float uOffs = 1.0F / (textureWidth * 10.0F); float vOffs = 1.0F / (textureHeight * 10.0F); if(verts.length < 4) { float xMin = -1; float yMin = -1; float xMax = 0; float yMax = 0; for(PositionTextureVertex vert : verts) { float xPos = vert.texturePositionX; float yPos = vert.texturePositionY; xMax = Math.max(xMax, xPos); xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); yMax = Math.max(yMax, yPos); yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); } float uMin = u1 / textureWidth + uOffs; float vMin = v1 / textureHeight + vOffs; float uSize = (u2 - u1) / textureWidth - uOffs * 2; float vSize = (v2 - v1) / textureHeight - vOffs * 2; float xSize = xMax - xMin; float ySize = yMax - yMin; for(int i = 0; i < verts.length; i++) { float xPos = verts[i].texturePositionX; float yPos = verts[i].texturePositionY; xPos = (xPos - xMin) / xSize; yPos = (yPos - yMin) / ySize; verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); } } else { verts[0] = verts[0].setTexturePosition(u2 / textureWidth - uOffs, v1 / textureHeight + vOffs); verts[1] = verts[1].setTexturePosition(u1 / textureWidth + uOffs, v1 / textureHeight + vOffs); verts[2] = verts[2].setTexturePosition(u1 / textureWidth + uOffs, v2 / textureHeight - vOffs); verts[3] = verts[3].setTexturePosition(u2 / textureWidth - uOffs, v2 / textureHeight - vOffs); } return new TexturedPolygon(verts); } /** * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, * as the method requires eight vector coordinates. * * @param v a float array with three values, the x, y and z coordinates of the vertex * @param v1 a float array with three values, the x, y and z coordinates of the vertex * @param v2 a float array with three values, the x, y and z coordinates of the vertex * @param v3 a float array with three values, the x, y and z coordinates of the vertex * @param v4 a float array with three values, the x, y and z coordinates of the vertex * @param v5 a float array with three values, the x, y and z coordinates of the vertex * @param v6 a float array with three values, the x, y and z coordinates of the vertex * @param v7 a float array with three values, the x, y and z coordinates of the vertex * @param w the width of the shape, used in determining the texture * @param h the height of the shape, used in determining the texture * @param d the depth of the shape, used in determining the texture */ public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d) { float[] var1 = new float[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d, var1); } /** * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, * as the method requires eight vector coordinates. Also does some special texture mapping. * * @param v a float array with three values, the x, y and z coordinates of the vertex * @param v1 a float array with three values, the x, y and z coordinates of the vertex * @param v2 a float array with three values, the x, y and z coordinates of the vertex * @param v3 a float array with three values, the x, y and z coordinates of the vertex * @param v4 a float array with three values, the x, y and z coordinates of the vertex * @param v5 a float array with three values, the x, y and z coordinates of the vertex * @param v6 a float array with three values, the x, y and z coordinates of the vertex * @param v7 a float array with three values, the x, y and z coordinates of the vertex * @param w the width of the shape, used in determining the texture * @param h the height of the shape, used in determining the texture * @param d the depth of the shape, used in determining the texture * @param qParam Array containing the q parameters in the order xBack, xBottom, xFront, xTop, yBack, yFront, yLeft, yRight, zBottom, zLeft, zRight, zTop */ public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d, float[] qParam) { PositionTextureVertex[] verts = new PositionTextureVertex[8]; TexturedPolygon[] poly = new TexturedPolygon[6]; PositionTextureVertex positionTexturevertex = new PositionTextureVertex(v[0], v[1], v[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(v1[0], v1[1], v1[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(v2[0], v2[1], v2[2], 8F, 8F); PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(v3[0], v3[1], v3[2], 8F, 0.0F); PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(v4[0], v4[1], v4[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(v5[0], v5[1], v5[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(v6[0], v6[1], v6[2], 8F, 8F); PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(v7[0], v7[1], v7[2], 8F, 0.0F); verts[0] = positionTexturevertex; verts[1] = positionTexturevertex1; verts[2] = positionTexturevertex2; verts[3] = positionTexturevertex3; verts[4] = positionTexturevertex4; verts[5] = positionTexturevertex5; verts[6] = positionTexturevertex6; verts[7] = positionTexturevertex7; poly[0] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 }, textureOffsetX + d + w, textureOffsetY + d, textureOffsetX + d + w + d, textureOffsetY + d + h, 1F, qParam[7], qParam[10] * qParam[7], qParam[10]); poly[1] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 }, textureOffsetX, textureOffsetY + d, textureOffsetX + d, textureOffsetY + d + h, qParam[9] * qParam[6], qParam[9], 1F, qParam[6]); poly[2] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 }, textureOffsetX + d, textureOffsetY, textureOffsetX + d + w, textureOffsetY + d, 1F, qParam[8], qParam[1] * qParam[8], qParam[1]); poly[3] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 }, textureOffsetX + d + w, textureOffsetY, textureOffsetX + d + w + w, textureOffsetY + d, qParam[3], qParam[3] * qParam[11], qParam[11], 1F); poly[4] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 }, textureOffsetX + d, textureOffsetY + d, textureOffsetX + d + w, textureOffsetY + d + h, qParam[0], qParam[0] * qParam[4], qParam[4], 1F); poly[5] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 }, textureOffsetX + d + w + d, textureOffsetY + d, textureOffsetX + d + w + d + w, textureOffsetY + d + h, qParam[2] * qParam[5], qParam[2], 1F, qParam[5]); if(mirror ^ flip) { for(TexturedPolygon aPoly : poly) { aPoly.flipFace(); } } copyTo(verts, poly); } /** * Adds a new box to the model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) */ @Override public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d) { addBox(x, y, z, w, h, d, 0.0F); return this; } /** * Adds a new box to the model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param expansion the expansion of the box. It increases the size in each direction by that many. */ @Override public void addBox(float x, float y, float z, int w, int h, int d, float expansion) { addBox(x, y, z, w, h, d, expansion, 1F); } /** * Adds a new box to the model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param expansion the expansion of the box. It increases the size in each direction by that many. It's independent from the scale. * @param scale */ public void addBox(float x, float y, float z, int w, int h, int d, float expansion, float scale) { float scaleX = w * scale; float scaleY = h * scale; float scaleZ = d * scale; float x1 = x + scaleX; float y1 = y + scaleY; float z1 = z + scaleZ; float expX = expansion + scaleX - w; float expY = expansion + scaleY - h; float expZ = expansion + scaleZ - d; x -= expX; y -= expY; z -= expZ; x1 += expansion; y1 += expansion; z1 += expansion; if(mirror) { float xTemp = x1; x1 = x; x = xTemp; } float[] v = {x, y, z}; float[] v1 = {x1, y, z}; float[] v2 = {x1, y1, z}; float[] v3 = {x, y1, z}; float[] v4 = {x, y, z1}; float[] v5 = {x1, y, z1}; float[] v6 = {x1, y1, z1}; float[] v7 = {x, y1, z1}; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param bottomScale the "scale" of the bottom * @param dir the side the scaling is applied to */ public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir) { float f4 = x + w; float f5 = y + h; float f6 = z + d; x -= scale; y -= scale; z -= scale; f4 += scale; f5 += scale; f6 += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = f4; f4 = x; x = f7; } float[] v = {x, y, z}; float[] v1 = {f4, y, z}; float[] v2 = {f4, f5, z}; float[] v3 = {x, f5, z}; float[] v4 = {x, y, f6}; float[] v5 = {f4, y, f6}; float[] v6 = {f4, f5, f6}; float[] v7 = {x, f5, f6}; switch(dir) { case MR_RIGHT: v[1] -= bottomScale; v[2] -= bottomScale; v3[1] += bottomScale; v3[2] -= bottomScale; v4[1] -= bottomScale; v4[2] += bottomScale; v7[1] += bottomScale; v7[2] += bottomScale; break; case MR_LEFT: v1[1] -= bottomScale; v1[2] -= bottomScale; v2[1] += bottomScale; v2[2] -= bottomScale; v5[1] -= bottomScale; v5[2] += bottomScale; v6[1] += bottomScale; v6[2] += bottomScale; break; case MR_FRONT: v[0] -= m * bottomScale; v[1] -= bottomScale; v1[0] += m * bottomScale; v1[1] -= bottomScale; v2[0] += m * bottomScale; v2[1] += bottomScale; v3[0] -= m * bottomScale; v3[1] += bottomScale; break; case MR_BACK: v4[0] -= m * bottomScale; v4[1] -= bottomScale; v5[0] += m * bottomScale; v5[1] -= bottomScale; v6[0] += m * bottomScale; v6[1] += bottomScale; v7[0] -= m * bottomScale; v7[1] += bottomScale; break; case MR_TOP: v[0] -= m * bottomScale; v[2] -= bottomScale; v1[0] += m * bottomScale; v1[2] -= bottomScale; v4[0] -= m * bottomScale; v4[2] += bottomScale; v5[0] += m * bottomScale; v5[2] += bottomScale; break; case MR_BOTTOM: v2[0] += m * bottomScale; v2[2] -= bottomScale; v3[0] -= m * bottomScale; v3[2] -= bottomScale; v6[0] += m * bottomScale; v6[2] += bottomScale; v7[0] -= m * bottomScale; v7[2] += bottomScale; break; } float[] qValues = new float[]{ Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) }; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param bScale1 the "scale" of the bottom - Top * @param bScale2 the "scale" of the bottom - Bottom * @param bScale3 the "scale" of the bottom - Left * @param bScale4 the "scale" of the bottom - Right * @param dir the side the scaling is applied to */ public void addFlexBox(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, int dir) { float f4 = x + w; float f5 = y + h; float f6 = z + d; x -= scale; y -= scale; z -= scale; f4 += scale; f5 += scale; f6 += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = f4; f4 = x; x = f7; } float[] v = {x, y, z}; float[] v1 = {f4, y, z}; float[] v2 = {f4, f5, z}; float[] v3 = {x, f5, z}; float[] v4 = {x, y, f6}; float[] v5 = {f4, y, f6}; float[] v6 = {f4, f5, f6}; float[] v7 = {x, f5, f6}; switch(dir) { case MR_RIGHT: v[1] -= bScale1; v[2] -= bScale3; v3[1] += bScale2; v3[2] -= bScale3; v4[1] -= bScale1; v4[2] += bScale4; v7[1] += bScale2; v7[2] += bScale4; break; case MR_LEFT: v1[1] -= bScale1; v1[2] -= bScale3; v2[1] += bScale2; v2[2] -= bScale3; v5[1] -= bScale1; v5[2] += bScale4; v6[1] += bScale2; v6[2] += bScale4; break; case MR_FRONT: v[0] -= m * bScale4; v[1] -= bScale1; v1[0] += m * bScale3; v1[1] -= bScale1; v2[0] += m * bScale3; v2[1] += bScale2; v3[0] -= m * bScale4; v3[1] += bScale2; break; case MR_BACK: v4[0] -= m * bScale4; v4[1] -= bScale1; v5[0] += m * bScale3; v5[1] -= bScale1; v6[0] += m * bScale3; v6[1] += bScale2; v7[0] -= m * bScale4; v7[1] += bScale2; break; case MR_TOP: v[0] -= m * bScale1; v[2] -= bScale3; v1[0] += m * bScale2; v1[2] -= bScale3; v4[0] -= m * bScale1; v4[2] += bScale4; v5[0] += m * bScale2; v5[2] += bScale4; break; case MR_BOTTOM: v2[0] += m * bScale2; v2[2] -= bScale3; v3[0] -= m * bScale1; v3[2] -= bScale3; v6[0] += m * bScale2; v6[2] += bScale4; v7[0] -= m * bScale1; v7[2] += bScale4; break; } float[] qValues = new float[]{ Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) }; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param bScale1 the "scale" of the bottom - Top * @param bScale2 the "scale" of the bottom - Bottom * @param bScale3 the "scale" of the bottom - Left * @param bScale4 the "scale" of the bottom - Right * @param fScale1 the "scale" of the top - Left * @param fScale2 the "scale" of the top - Right * @param dir the side the scaling is applied to */ public void addFlexTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, float fScale1, float fScale2, int dir) { float f4 = x + w; float f5 = y + h; float f6 = z + d; x -= scale; y -= scale; z -= scale; f4 += scale; f5 += scale; f6 += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = f4; f4 = x; x = f7; } float[] v = {x, y, z}; float[] v1 = {f4, y, z}; float[] v2 = {f4, f5, z}; float[] v3 = {x, f5, z}; float[] v4 = {x, y, f6}; float[] v5 = {f4, y, f6}; float[] v6 = {f4, f5, f6}; float[] v7 = {x, f5, f6}; switch(dir) { case MR_RIGHT: v[2] -= fScale1; v1[2] -= fScale1; v4[2] += fScale2; v5[2] += fScale2; v[1] -= bScale1; v[2] -= bScale3; v3[1] += bScale2; v3[2] -= bScale3; v4[1] -= bScale1; v4[2] += bScale4; v7[1] += bScale2; v7[2] += bScale4; break; case MR_LEFT: v[2] -= fScale1; v1[2] -= fScale1; v4[2] += fScale2; v5[2] += fScale2; v1[1] -= bScale1; v1[2] -= bScale3; v2[1] += bScale2; v2[2] -= bScale3; v5[1] -= bScale1; v5[2] += bScale4; v6[1] += bScale2; v6[2] += bScale4; break; case MR_FRONT: v1[1] -= fScale1; v5[1] -= fScale1; v2[1] += fScale2; v6[1] += fScale2; v[0] -= m * bScale4; v[1] -= bScale1; v1[0] += m * bScale3; v1[1] -= bScale1; v2[0] += m * bScale3; v2[1] += bScale2; v3[0] -= m * bScale4; v3[1] += bScale2; break; case MR_BACK: v1[1] -= fScale1; v5[1] -= fScale1; v2[1] += fScale2; v6[1] += fScale2; v4[0] -= m * bScale4; v4[1] -= bScale1; v5[0] += m * bScale3; v5[1] -= bScale1; v6[0] += m * bScale3; v6[1] += bScale2; v7[0] -= m * bScale4; v7[1] += bScale2; break; case MR_TOP: v1[2] -= fScale1; v2[2] -= fScale1; v5[2] += fScale2; v6[2] += fScale2; v[0] -= m * bScale1; v[2] -= bScale3; v1[0] += m * bScale2; v1[2] -= bScale3; v4[0] -= m * bScale1; v4[2] += bScale4; v5[0] += m * bScale2; v5[2] += bScale4; break; case MR_BOTTOM: v1[2] -= fScale1; v2[2] -= fScale1; v5[2] += fScale2; v6[2] += fScale2; v2[0] += m * bScale2; v2[2] -= bScale3; v3[0] -= m * bScale1; v3[2] -= bScale3; v6[0] += m * bScale2; v6[2] += bScale4; v7[0] -= m * bScale1; v7[2] += bScale4; break; } float[] qValues = new float[]{ Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) }; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a box with float width, height and depth. Who knows what it will do to the texture. * * @param x the starting x-positions * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) */ public void addBox(float x, float y, float z, float w, float h, float d) { int rw = MathHelper.ceil(w); int rh = MathHelper.ceil(h); int rd = MathHelper.ceil(d); w -= rw; h -= rh; d -= rd; addShapeBox(x, y, z, rw, rh, rd, 0F, 0F, 0F, 0F, w, 0F, 0F, w, 0F, d, 0F, 0F, d, 0F, h, 0F, w, h, 0F, w, h, d, 0F, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param x0,y0,z0 - x7,y7,z7 the modifiers of the box corners. each corner can changed seperat by x/y/z values */ public void addShapeBox(float x, float y, float z, int w, int h, int d, float scale, float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7) { float f4 = x + w; float f5 = y + h; float f6 = z + d; x -= scale; y -= scale; z -= scale; f4 += scale; f5 += scale; f6 += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = f4; f4 = x; x = f7; } float[] v = {x - x0, y - y0, z - z0}; float[] v1 = {f4 + x1, y - y1, z - z1}; float[] v2 = {f4 + x5, f5 + y5, z - z5}; float[] v3 = {x - x4, f5 + y4, z - z4}; float[] v4 = {x - x3, y - y3, f6 + z3}; float[] v5 = {f4 + x2, y - y2, f6 + z2}; float[] v6 = {f4 + x6, f5 + y6, f6 + z6}; float[] v7 = {x - x7, f5 + y7, f6 + z7}; float[] qValues = new float[]{ Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) }; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an array of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an array of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an ArrayList of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an ArrayList of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { float rotX = 0; float rotY = 0; float rotZ = 0; switch(direction) { case MR_LEFT: rotY = pi / 2; break; case MR_RIGHT: rotY = -pi / 2; break; case MR_TOP: rotX = pi / 2; break; case MR_BOTTOM: rotX = -pi / 2; break; case MR_FRONT: rotY = pi; break; case MR_BACK: break; } addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, faceLengths); } /** * Creates a shape from a 2D vector shape. * * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param rotX the rotation around the x-axis * @param rotY the rotation around the y-axis * @param rotZ the rotation around the z-axis */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ) { addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, null); } public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ, float[] faceLengths) { Shape3D shape3D = shape.extrude(x, y, z, rotX, rotY, rotZ, depth, textureOffsetX, textureOffsetY, textureWidth, textureHeight, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, faceLengths); if(flip) { for(int idx = 0; idx < shape3D.faces.length; idx++) { shape3D.faces[idx].flipFace(); } } copyTo(shape3D.vertices, shape3D.faces); } /** * Adds a cube the size of one pixel. It will take a pixel from the texture and * uses that as the texture of said cube. The accurate name would actually be * "addVoxel". This method has been added to make it more compatible with Techne, * and allows for easy single-colored boxes. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param width the width of the box * @param height the height of the box * @param length the length of the box */ public void addPixel(float x, float y, float z, float width, float height, float length) { addPixel(x, y, z, new float[]{width, height, length}, textureOffsetX, textureOffsetY); } /** * Adds a cube the size of one pixel. It will take a pixel from the texture and * uses that as the texture of said cube. The accurate name would actually be * "addVoxel". It will not overwrite the model data, but rather, it will add to * the model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param scale the "scale" of the cube, where scale is a float integer consisting of three values * @param w the x-coordinate on the texture * @param h the y-coordinate on the texture */ public void addPixel(float x, float y, float z, float[] scale, int w, int h) { PositionTextureVertex[] verts = new PositionTextureVertex[8]; TexturedPolygon[] poly = new TexturedPolygon[6]; float x1 = x + scale[0]; float y1 = y + scale[1]; float z1 = z + scale[2]; float[] f = {x, y, z}; float[] f1 = {x1, y, z}; float[] f2 = {x1, y1, z}; float[] f3 = {x, y1, z}; float[] f4 = {x, y, z1}; float[] f5 = {x1, y, z1}; float[] f6 = {x1, y1, z1}; float[] f7 = {x, y1, z1}; PositionTextureVertex positionTexturevertex = new PositionTextureVertex(f[0], f[1], f[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(f1[0], f1[1], f1[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(f2[0], f2[1], f2[2], 8F, 8F); PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(f3[0], f3[1], f3[2], 8F, 0.0F); PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(f4[0], f4[1], f4[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(f5[0], f5[1], f5[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(f6[0], f6[1], f6[2], 8F, 8F); PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(f7[0], f7[1], f7[2], 8F, 0.0F); verts[0] = positionTexturevertex; verts[1] = positionTexturevertex1; verts[2] = positionTexturevertex2; verts[3] = positionTexturevertex3; verts[4] = positionTexturevertex4; verts[5] = positionTexturevertex5; verts[6] = positionTexturevertex6; verts[7] = positionTexturevertex7; poly[0] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 }, w, h, w + 1, h + 1); poly[1] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 }, w, h, w + 1, h + 1); poly[2] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 }, w, h, w + 1, h + 1); poly[3] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 }, w, h, w + 1, h + 1); poly[4] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 }, w, h, w + 1, h + 1); poly[5] = addPolygonReturn(new PositionTextureVertex[]{ positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 }, w, h, w + 1, h + 1); copyTo(verts, poly); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, float expansion) { addSprite(x, y, z, w, h, 1, false, false, false, false, false, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { addSprite(x, y, z, w, h, 1, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param d the depth of the shape itself * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, int d, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { addSprite(x, y, z, w, h, d, 1.0F, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param d the depth of the shape itself * @param pixelScale the scale of each individual pixel * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { String[] mask = new String[h]; char[] str = new char[w]; Arrays.fill(str, '1'); Arrays.fill(mask, new String(str)); addSprite(x, y, z, mask, d, pixelScale, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. *

* This method uses a mask string. This way you can reduce the amount of quads used. To * use this, create a String array, where you use a 1 to signify that the pixel will be * drawn. Any other character will cause that pixel to not be drawn. * * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param mask an array with the mask string * @param d the depth of the shape itself * @param pixelScale the scale of each individual pixel * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, String[] mask, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { int w = mask[0].length(); int h = mask.length; float x1 = x - expansion; float y1 = y - expansion; float z1 = z - expansion; int wDir = 0; int hDir = 0; int dDir = 0; float wScale = 1F + (expansion / (w * pixelScale)); float hScale = 1F + (expansion / (h * pixelScale)); if(!rotX) { if(!rotY) { if(!rotZ) { wDir = 0; hDir = 1; dDir = 2; } else { wDir = 1; hDir = 0; dDir = 2; } } else { if(!rotZ) { wDir = 2; hDir = 1; dDir = 0; } else { wDir = 2; hDir = 0; dDir = 1; } } } else { if(!rotY) { if(!rotZ) { wDir = 0; hDir = 2; dDir = 1; } else { wDir = 1; hDir = 2; dDir = 0; } } else { if(!rotZ) { wDir = 2; hDir = 0; dDir = 1; } else { wDir = 2; hDir = 1; dDir = 0; } } } int texStartX = textureOffsetX + (mirrorX ? w - 1 : 0); int texStartY = textureOffsetY + (mirrorY ? h - 1 : 0); int texDirX = (mirrorX ? -1 : 1); int texDirY = (mirrorY ? -1 : 1); float wVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, wDir, 1, 1); float hVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, hDir, 1, 1); float dVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, dDir, 1, 1); for(int i = 0; i < w; i++) { for(int j = 0; j < h; j++) { if(mask[j].charAt(i) == '1') { addPixel(x1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 0, i, j), y1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 1, i, j), z1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 2, i, j), new float[]{wVoxSize, hVoxSize, dVoxSize}, texStartX + texDirX * i, texStartY + texDirY * j); } } } } private float getPixelSize(float wScale, float hScale, float dScale, int wDir, int hDir, int checkDir, int texPosX, int texPosY) { return (wDir == checkDir ? wScale * texPosX : (hDir == checkDir ? hScale * texPosY : dScale)); } /** * Adds a spherical shape. * * @param x * @param y * @param z * @param r * @param segs * @param rings * @param textureW * @param textureH */ public void addSphere(float x, float y, float z, float r, int segs, int rings, int textureW, int textureH) { if(segs < 3) segs = 3; rings++; PositionTextureVertex[] tempVerts = new PositionTextureVertex[segs * (rings - 1) + 2]; TexturedPolygon[] poly = new TexturedPolygon[segs * rings]; tempVerts[0] = new PositionTextureVertex(x, y - r, z, 0, 0); tempVerts[tempVerts.length - 1] = new PositionTextureVertex(x, y + r, z, 0, 0); float uOffs = 1.0F / (textureWidth * 10.0F); float vOffs = 1.0F / (textureHeight * 10.0F); float texW = textureW / textureWidth - 2F * uOffs; float texH = textureH / textureHeight - 2F * vOffs; float segW = texW / segs; float segH = texH / rings; float startU = textureOffsetX / textureWidth; float startV = textureOffsetY / textureHeight; int currentFace = 0; for(int j = 1; j < rings; j++) { for(int i = 0; i < segs; i++) { float yWidth = MathHelper.cos(-pi / 2 + (pi / rings) * j); float yHeight = MathHelper.sin(-pi / 2 + (pi / rings) * j); float xSize = MathHelper.sin((pi / segs) * i * 2F + pi) * yWidth; float zSize = -MathHelper.cos((pi / segs) * i * 2F + pi) * yWidth; int curVert = 1 + i + segs * (j - 1); tempVerts[curVert] = new PositionTextureVertex(x + xSize * r, y + yHeight * r, z + zSize * r, 0, 0); if(i > 0) { PositionTextureVertex[] verts; if(j == 1) { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); verts[2] = tempVerts[0].setTexturePosition(startU + segW * (i - 1), startV); verts[3] = tempVerts[0].setTexturePosition(startU + segW + segW * i, startV); } else { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); verts[2] = tempVerts[curVert - 1 - segs].setTexturePosition(startU + segW * (i - 1), startV + segH * (j - 1)); verts[3] = tempVerts[curVert - segs].setTexturePosition(startU + segW * i, startV + segH * (j - 1)); } poly[currentFace] = new TexturedPolygon(verts); currentFace++; } } PositionTextureVertex[] verts; if(j == 1) { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[1].setTexturePosition(startU + segW * segs, startV + segH * j); verts[1] = tempVerts[segs].setTexturePosition(startU + segW * (segs - 1), startV + segH * j); verts[2] = tempVerts[0].setTexturePosition(startU + segW * (segs - 1), startV); verts[3] = tempVerts[0].setTexturePosition(startU + segW * segs, startV); } else { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[1 + segs * (j - 1)].setTexturePosition(startU + texW, startV + segH * j); verts[1] = tempVerts[segs * (j - 1) + segs].setTexturePosition(startU + texW - segW, startV + segH * j); verts[2] = tempVerts[segs * (j - 1)].setTexturePosition(startU + texW - segW, startV + segH * (j - 1)); verts[3] = tempVerts[1 + segs * (j - 1) - segs].setTexturePosition(startU + texW, startV + segH * (j - 1)); } poly[currentFace] = new TexturedPolygon(verts); currentFace++; } for(int i = 0; i < segs; i++) { PositionTextureVertex[] verts = new PositionTextureVertex[3]; int curVert = tempVerts.length - (segs + 1); verts[0] = tempVerts[tempVerts.length - 1].setTexturePosition(startU + segW * (i + 0.5F), startV + texH); verts[1] = tempVerts[curVert + i].setTexturePosition(startU + segW * i, startV + texH - segH); verts[2] = tempVerts[curVert + ((i + 1) % segs)].setTexturePosition(startU + segW * (i + 1), startV + texH - segH); poly[currentFace] = new TexturedPolygon(verts); currentFace++; } copyTo(tempVerts, poly); } /** * Adds a cone. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of */ public void addCone(float x, float y, float z, float radius, float length, int segments) { addCone(x, y, z, radius, length, segments, 1F); } /** * Adds a cone. *

* baseScale cannot be zero. If it is, it will automatically be set to 1F. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale) { addCone(x, y, z, radius, length, segments, baseScale, MR_TOP); } /** * Adds a cone. *

* baseScale cannot be zero. If it is, it will automatically be set to 1F. *

* Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param baseDirection the direction it faces */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection) { addCone(x, y, z, radius, length, segments, baseScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F)); } /** * Adds a cone. *

* baseScale cannot be zero. If it is, it will automatically be set to 1F. *

* Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). *

* The textures for the sides are placed next to each other. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param baseDirection the direction it faces * @param textureCircleDiameterW the diameter width of the circle on the texture * @param textureCircleDiameterH the diameter height of the circle on the texture */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH) { addCylinder(x, y, z, radius, length, segments, baseScale, 0.0F, baseDirection, textureCircleDiameterW, textureCircleDiameterH, 1); } /** * Adds a cylinder. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of */ public void addCylinder(float x, float y, float z, float radius, float length, int segments) { addCylinder(x, y, z, radius, length, segments, 1F, 1F); } /** * Adds a cylinder. *

* You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale) { addCylinder(x, y, z, radius, length, segments, baseScale, topScale, MR_TOP); } /** * Adds a cylinder. *

* You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. *

* Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. * @param baseDirection the direction it faces */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection) { addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length)); } /** * Adds a cylinder. *

* You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. *

* Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). *

* The textures for the base and top are placed next to each other, while the body * will be placed below the circles. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. * @param baseDirection the direction it faces * @param textureCircleDiameterW the diameter width of the circle on the texture * @param textureCircleDiameterH the diameter height of the circle on the texture * @param textureH the height of the texture of the body */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH) { boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); boolean coneBase = (baseScale == 0); boolean coneTop = (topScale == 0); if(coneBase && coneTop) { baseScale = 1F; coneBase = false; } PositionTextureVertex[] tempVerts = new PositionTextureVertex[segments * (coneBase || coneTop ? 1 : 2) + 2]; TexturedPolygon[] poly = new TexturedPolygon[segments * (coneBase || coneTop ? 2 : 3)]; float xLength = (dirSide ? length : 0); float yLength = (dirTop ? length : 0); float zLength = (dirFront ? length : 0); float xStart = (dirMirror ? x + xLength : x); float yStart = (dirMirror ? y + yLength : y); float zStart = (dirMirror ? z + zLength : z); float xEnd = (!dirMirror ? x + xLength : x); float yEnd = (!dirMirror ? y + yLength : y); float zEnd = (!dirMirror ? z + zLength : z); tempVerts[0] = new PositionTextureVertex(xStart, yStart, zStart, 0, 0); tempVerts[tempVerts.length - 1] = new PositionTextureVertex(xEnd, yEnd, zEnd, 0, 0); float xCur = xStart; float yCur = yStart; float zCur = zStart; float sCur = (coneBase ? topScale : baseScale); for(int repeat = 0; repeat < (coneBase || coneTop ? 1 : 2); repeat++) { for(int index = 0; index < segments; index++) { float xSize = (mirror ^ dirMirror ? -1 : 1) * MathHelper.sin((pi / segments) * index * 2F + pi) * radius * sCur; float zSize = -MathHelper.cos((pi / segments) * index * 2F + pi) * radius * sCur; float xPlace = xCur + (!dirSide ? xSize : 0); float yPlace = yCur + (!dirTop ? zSize : 0); float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); tempVerts[1 + index + repeat * segments] = new PositionTextureVertex(xPlace, yPlace, zPlace, 0, 0); } xCur = xEnd; yCur = yEnd; zCur = zEnd; sCur = topScale; } float uScale = 1.0F / textureWidth; float vScale = 1.0F / textureHeight; float uOffset = uScale / 20.0F; float vOffset = vScale / 20.0F; float uCircle = textureCircleDiameterW * uScale; float vCircle = textureCircleDiameterH * vScale; float uWidth = (uCircle * 2F - uOffset * 2F) / segments; float vHeight = textureH * vScale - uOffset * 2f; float uStart = textureOffsetX * uScale; float vStart = textureOffsetY * vScale; PositionTextureVertex[] vert; for(int index = 0; index < segments; index++) { int index2 = (index + 1) % segments; float uSize = MathHelper.sin((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); float vSize = MathHelper.cos((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); float uSize1 = MathHelper.sin((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); float vSize1 = MathHelper.cos((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); vert = new PositionTextureVertex[3]; vert[0] = tempVerts[0].setTexturePosition(uStart + 0.5F * uCircle, vStart + 0.5F * vCircle); vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + 0.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); vert[2] = tempVerts[1 + index].setTexturePosition(uStart + 0.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); poly[index] = new TexturedPolygon(vert); if(mirror ^ flip) poly[index].flipFace(); if(!coneBase && !coneTop) { vert = new PositionTextureVertex[4]; vert[0] = tempVerts[1 + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle); vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle); vert[2] = tempVerts[1 + segments + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle + vHeight); vert[3] = tempVerts[1 + segments + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle + vHeight); poly[index + segments] = new TexturedPolygon(vert); if(mirror ^ flip) poly[index + segments].flipFace(); } vert = new PositionTextureVertex[3]; vert[0] = tempVerts[tempVerts.length - 1].setTexturePosition(uStart + 1.5F * uCircle, vStart + 0.5F * vCircle); vert[1] = tempVerts[tempVerts.length - 2 - index].setTexturePosition(uStart + 1.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); vert[2] = tempVerts[tempVerts.length - (1 + segments) + ((segments - index) % segments)].setTexturePosition(uStart + 1.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); poly[poly.length - segments + index] = new TexturedPolygon(vert); if(mirror ^ flip) poly[poly.length - segments + index].flipFace(); } copyTo(tempVerts, poly); } /** * Adds a Waveform .obj file as a model. Model files use the entire texture file. * * @param file the location of the .obj file. The location is relative to the base directories, * which are either resources/models or resources/mods/models. */ public void addObj(String file) { addModel(file, ModelPool.OBJ); } /** * Adds model format support. Model files use the entire texture file. * * @param file the location of the model file. The location is relative to the base directories, * which are either resources/models or resources/mods/models. * @param modelFormat the class of the model format interpreter */ public void addModel(String file, Class modelFormat) { ModelPoolEntry entry = ModelPool.addFile(file, modelFormat, transformGroup, textureGroup); if(entry == null) return; PositionTextureVertex[] verts = Arrays.copyOf(entry.vertices, entry.vertices.length); TexturedPolygon[] poly = Arrays.copyOf(entry.faces, entry.faces.length); if(flip) { for(TexturedPolygon face : faces) { face.flipFace(); } } copyTo(verts, poly, false); } /** * Sets a new position for the texture offset. * * @param x the x-coordinate of the texture start * @param y the y-coordinate of the texture start */ @Override public ModelRendererTurbo setTextureOffset(int x, int y) { textureOffsetX = x; textureOffsetY = y; return this; } /** * Sets the position of the shape, relative to the model's origins. Note that changing * the offsets will not change the pivot of the model. * * @param x the x-position of the shape * @param y the y-position of the shape * @param z the z-position of the shape */ public void setPosition(float x, float y, float z) { rotationPointX = x; rotationPointY = y; rotationPointZ = z; } /** * Mirrors the model in any direction. * * @param x whether the model should be mirrored in the x-direction * @param y whether the model should be mirrored in the y-direction * @param z whether the model should be mirrored in the z-direction */ public void doMirror(boolean x, boolean y, boolean z) { for(TexturedPolygon face : faces) { PositionTextureVertex[] verts = face.vertexPositions; for(PositionTextureVertex vert : verts) { vert.vector3D = new Vec3d(vert.vector3D.x * (x ? -1 : 1), vert.vector3D.y * (y ? -1 : 1), vert.vector3D.z * (z ? -1 : 1)); } if(x ^ y ^ z) face.flipFace(); } } /** * Sets whether the shape is mirrored or not. This has effect on the way the textures * get displayed. When working with addSprite, addPixel and addObj, it will be ignored. * * @param isMirrored a boolean to define whether the shape is mirrored */ public void setMirrored(boolean isMirrored) { mirror = isMirrored; } /** * Sets whether the shape's faces are flipped or not. When GL_CULL_FACE is enabled, * it won't render the back faces, effectively giving you the possibility to make * "hollow" shapes. When working with addSprite and addPixel, it will be ignored. * * @param isFlipped a boolean to define whether the shape is flipped */ public void setFlipped(boolean isFlipped) { flip = isFlipped; } /** * Clears the current shape. Since all shapes are stacked into one shape, you can't * just replace a shape by overwriting the shape with another one. In this case you * would need to clear the shape first. */ public void clear() { vertices = new PositionTextureVertex[0]; faces = new TexturedPolygon[0]; transformGroup.clear(); transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); currentGroup = transformGroup.get("0"); } /** * Copies an array of vertices and polygons to the current shape. This mainly is * used to copy each shape to the main class, but you can just use it to copy * your own shapes, for example from other classes, into the current class. * * @param verts the array of vertices you want to copy * @param poly the array of polygons you want to copy */ public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly) { copyTo(verts, poly, true); } public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly, boolean copyGroup) { vertices = Arrays.copyOf(vertices, vertices.length + verts.length); faces = Arrays.copyOf(faces, faces.length + poly.length); for(int idx = 0; idx < verts.length; idx++) { vertices[vertices.length - verts.length + idx] = verts[idx]; if(copyGroup && verts[idx] instanceof PositionTransformVertex) ((PositionTransformVertex)verts[idx]).addGroup(currentGroup); } for(int idx = 0; idx < poly.length; idx++) { faces[faces.length - poly.length + idx] = poly[idx]; if(copyGroup) currentTextureGroup.addPoly(poly[idx]); } } /** * Copies an array of vertices and quads to the current shape. This method * converts quads to polygons and then calls the main copyTo method. * * @param verts the array of vertices you want to copy * @param quad the array of quads you want to copy */ public void copyTo(PositionTextureVertex[] verts, TexturedQuad[] quad) { TexturedPolygon[] poly = new TexturedPolygon[quad.length]; for(int idx = 0; idx < quad.length; idx++) { poly[idx] = new TexturedPolygon((PositionTextureVertex[])quad[idx].vertexPositions); } copyTo(verts, poly); } /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * * @param groupName the name of the transformation group you want to switch to */ public void setGroup(String groupName) { setGroup(groupName, new Bone(0, 0, 0, 0), 1D); } /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * * @param groupName the name of the transformation group you want to switch to * @param bone the Bone this transformation group is attached to * @param weight the weight of the transformation group */ public void setGroup(String groupName, Bone bone, double weight) { if(!transformGroup.containsKey(groupName)) transformGroup.put(groupName, new TransformGroupBone(bone, weight)); currentGroup = transformGroup.get(groupName); } /** * Gets the current transformation group. * * @return the current PositionTransformGroup. */ public TransformGroup getGroup() { return currentGroup; } /** * Gets the transformation group with a given group name. * * @return the current PositionTransformGroup. */ public TransformGroup getGroup(String groupName) { if(!transformGroup.containsKey(groupName)) return null; return transformGroup.get(groupName); } /** * Sets the current texture group, which is used to switch the * textures on a per-model base. Do note that any model that is * rendered afterwards will use the same texture. To counter it, * set a default texture, either at initialization or before * rendering. * * @param groupName The name of the texture group. If the texture * group doesn't exist, it creates a new group automatically. */ public void setTextureGroup(String groupName) { if(!textureGroup.containsKey(groupName)) { textureGroup.put(groupName, new TextureGroup()); } currentTextureGroup = textureGroup.get(groupName); } /** * Gets the current texture group. * * @return a TextureGroup object. */ public TextureGroup getTextureGroup() { return currentTextureGroup; } /** * Gets the texture group with the given name. * * @param groupName the name of the texture group to return * @return a TextureGroup object. */ public TextureGroup getTextureGroup(String groupName) { if(!textureGroup.containsKey(groupName)) return null; return textureGroup.get(groupName); } /** * Sets the texture of the current texture group. * * @param s the filename */ public void setGroupTexture(String s) { currentTextureGroup.texture = s; } /** * Sets the default texture. When left as an empty string, * it will use the texture that has been set previously. * Note that this will also move on to other rendered models * of the same entity. * * @param s the filename */ public void setDefaultTexture(String s) { defaultTexture = s; } /** * Renders the shape. * * @param worldScale the scale of the shape. Usually is 0.0625. */ @Override public void render(float worldScale) { render(worldScale, false); } /** * Renders the shape * * @param worldScale The scale of the shape * @param oldRotateOrder Whether to use the old rotate order (ZYX) instead of the new one (YZX) */ public void render(float worldScale, boolean oldRotateOrder) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled || forcedRecompile) { compileDisplayList(worldScale); } if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { GlStateManager.pushMatrix(); GlStateManager.translate(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); if(!oldRotateOrder && rotateAngleY != 0.0F) { GlStateManager.rotate(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleZ != 0.0F) { GlStateManager.rotate((oldRotateOrder ? -1 : 1) * rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } if(oldRotateOrder && rotateAngleY != 0.0F) { GlStateManager.rotate(-rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GlStateManager.rotate(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } callDisplayList(); if(childModels != null) { for(Object childModel : childModels) { ((ModelRenderer)childModel).render(worldScale); } } GlStateManager.popMatrix(); } else if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { GlStateManager.translate(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); callDisplayList(); if(childModels != null) { for(Object childModel : childModels) { ((ModelRenderer)childModel).render(worldScale); } } GlStateManager.translate(-rotationPointX * worldScale, -rotationPointY * worldScale, -rotationPointZ * worldScale); } else { callDisplayList(); if(childModels != null) { for(Object childModel : childModels) { ((ModelRenderer)childModel).render(worldScale); } } } } @Override public void renderWithRotation(float f) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled) { compileDisplayList(f); } GlStateManager.pushMatrix(); GlStateManager.translate(rotationPointX * f, rotationPointY * f, rotationPointZ * f); if(rotateAngleY != 0.0F) { GlStateManager.rotate(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GlStateManager.rotate(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } if(rotateAngleZ != 0.0F) { GlStateManager.rotate(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } callDisplayList(); GlStateManager.popMatrix(); } @Override public void postRender(float f) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled || forcedRecompile) { compileDisplayList(f); } if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { GlStateManager.translate(rotationPointX * f, rotationPointY * f, rotationPointZ * f); if(rotateAngleZ != 0.0F) { GlStateManager.rotate(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } if(rotateAngleY != 0.0F) { GlStateManager.rotate(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GlStateManager.rotate(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } } else if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { GlStateManager.translate(rotationPointX * f, rotationPointY * f, rotationPointZ * f); } } private void callDisplayList() { if(useLegacyCompiler) GlStateManager.callList(displayList); else { TextureManager renderEngine = Minecraft.getMinecraft().renderEngine; Collection textures = textureGroup.values(); Iterator itr = textures.iterator(); for(int i = 0; itr.hasNext(); i++) { TextureGroup curTexGroup = itr.next(); curTexGroup.loadTexture(); GlStateManager.callList(displayListArray[i]); if(!defaultTexture.equals("")) renderEngine.bindTexture(new ResourceLocation("", defaultTexture)); //TODO : Check. Not sure about this one } } } private void compileDisplayList(float worldScale) { if(useLegacyCompiler) compileLegacyDisplayList(worldScale); else { Collection textures = textureGroup.values(); Iterator itr = textures.iterator(); displayListArray = new int[textureGroup.size()]; for(int i = 0; itr.hasNext(); i++) { displayListArray[i] = GLAllocation.generateDisplayLists(1); GlStateManager.glNewList(displayListArray[i], GL11.GL_COMPILE); TmtTessellator tessellator = TmtTessellator.instance; TextureGroup usedGroup = itr.next(); for(int j = 0; j < usedGroup.poly.size(); j++) { usedGroup.poly.get(j).draw(tessellator, worldScale); } GlStateManager.glEndList(); } } compiled = true; } private void compileLegacyDisplayList(float worldScale) { displayList = GLAllocation.generateDisplayLists(1); GlStateManager.glNewList(displayList, GL11.GL_COMPILE); TmtTessellator tessellator = TmtTessellator.instance; for(TexturedPolygon face : faces) { face.draw(tessellator, worldScale); } GlStateManager.glEndList(); } private PositionTextureVertex vertices[]; private TexturedPolygon faces[]; private int textureOffsetX; private int textureOffsetY; private boolean compiled; private int displayList; private int displayListArray[]; private Map transformGroup; private Map textureGroup; private TransformGroup currentGroup; private TextureGroup currentTextureGroup; public boolean mirror; public boolean flip; public boolean showModel; public boolean field_1402_i; public boolean forcedRecompile; public boolean useLegacyCompiler; public List cubeList; public List childModels; public final String boxName; private String defaultTexture; public static final int MR_FRONT = 0; public static final int MR_BACK = 1; public static final int MR_LEFT = 2; public static final int MR_RIGHT = 3; public static final int MR_TOP = 4; public static final int MR_BOTTOM = 5; private static final float pi = (float)Math.PI; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/PositionTextureVertex.java ================================================ package com.flansmod.client.tmt; import net.minecraft.util.math.Vec3d; public class PositionTextureVertex extends net.minecraft.client.model.PositionTextureVertex { public float texturePositionW = 1F; public PositionTextureVertex(float par1, float par2, float par3, float par4, float par5) { this(par1, par2, par3, par4, par5, 1F); } public PositionTextureVertex(float par1, float par2, float par3, float par4, float par5, float par6) { this(new Vec3d(par1, par2, par3), par4, par5); } @Override public PositionTextureVertex setTexturePosition(float par1, float par2) { return new PositionTextureVertex(this, par1, par2, 1F); } public PositionTextureVertex setTexturePosition(float par1, float par2, float q) { return new PositionTextureVertex(this, par1, par2, q); } public PositionTextureVertex(PositionTextureVertex par1PositionTextureVertex, float par2, float par3) { this(par1PositionTextureVertex, par2, par3, 1F); } public PositionTextureVertex(PositionTextureVertex par1PositionTextureVertex, float par2, float par3, float q) { super(par1PositionTextureVertex, par2, par3); this.texturePositionW = q; } public PositionTextureVertex(Vec3d par1Vec3, float par2, float par3) { this(par1Vec3, par2, par3, 1F); } public PositionTextureVertex(Vec3d par1Vec3, float par2, float par3, float par4) { super(par1Vec3, par2, par3); this.texturePositionW = par4; } } ================================================ FILE: src/main/java/com/flansmod/client/tmt/PositionTransformVertex.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import net.minecraft.util.math.Vec3d; public class PositionTransformVertex extends PositionTextureVertex { public PositionTransformVertex(float x, float y, float z, float u, float v) { this(new Vec3d(x, y, z), u, v); } public PositionTransformVertex(PositionTextureVertex vertex, float u, float v) { super(vertex, u, v); if(vertex instanceof PositionTransformVertex) neutralVector = ((PositionTransformVertex)vertex).neutralVector; else neutralVector = new Vec3d(vertex.vector3D.x, vertex.vector3D.y, vertex.vector3D.z); } public PositionTransformVertex(PositionTextureVertex vertex) { this(vertex, vertex.texturePositionX, vertex.texturePositionY); } public PositionTransformVertex(Vec3d vector, float u, float v) { super(vector, u, v); neutralVector = new Vec3d(vector.x, vector.y, vector.z); } public void setTransformation() { if(transformGroups.isEmpty()) { vector3D = new Vec3d(neutralVector.x, neutralVector.y, neutralVector.z); return; } double weight = 0D; for(TransformGroup transformGroup : transformGroups) { weight += transformGroup.getWeight(); } vector3D = new Vec3d(0, 0, 0); for(TransformGroup group : transformGroups) { double cWeight = group.getWeight() / weight; Vec3d vector = group.doTransformation(this); vector3D = new Vec3d(vector3D.x + cWeight * vector.x, vector3D.y + cWeight * vector.y, vector3D.z + cWeight * vector.z); } } public void addGroup(TransformGroup group) { transformGroups.add(group); } public void removeGroup(TransformGroup group) { transformGroups.remove(group); } public Vec3d neutralVector; public ArrayList transformGroups = new ArrayList<>(); } ================================================ FILE: src/main/java/com/flansmod/client/tmt/Shape2D.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import java.util.Collections; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class Shape2D { public Shape2D() { coords = new ArrayList<>(); } public Shape2D(Coord2D[] coordArray) { coords = new ArrayList<>(); Collections.addAll(coords, coordArray); } public Shape2D(ArrayList coordList) { coords = coordList; } public Coord2D[] getCoordArray() { return (Coord2D[])coords.toArray(); } public Shape3D extrude(float x, float y, float z, float rotX, float rotY, float rotZ, float depth, int u, int v, float textureWidth, float textureHeight, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float[] faceLengths) { PositionTransformVertex[] verts = new PositionTransformVertex[coords.size() * 2]; PositionTransformVertex[] vertsTop = new PositionTransformVertex[coords.size()]; PositionTransformVertex[] vertsBottom = new PositionTransformVertex[coords.size()]; TexturedPolygon[] poly = new TexturedPolygon[coords.size() + 2]; Vec3d extrudeVector = new Vec3d(0, 0, depth); extrudeVector = setVectorRotations(extrudeVector, rotX, rotY, rotZ); if(faceLengths != null && faceLengths.length < coords.size()) faceLengths = null; float totalLength = 0; for(int idx = 0; idx < coords.size(); idx++) { Coord2D curCoord = coords.get(idx); Coord2D nextCoord = coords.get((idx + 1) % coords.size()); float texU1 = ((curCoord.uCoord + u) / textureWidth); float texU2 = ((shapeTextureWidth * 2 - curCoord.uCoord + u) / textureWidth); float texV = ((curCoord.vCoord + v) / textureHeight); Vec3d vecCoord = new Vec3d(curCoord.xCoord, curCoord.yCoord, 0); vecCoord = setVectorRotations(vecCoord, rotX, rotY, rotZ); verts[idx] = new PositionTransformVertex( x + (float)vecCoord.x, y + (float)vecCoord.y, z + (float)vecCoord.z, texU1, texV); verts[idx + coords.size()] = new PositionTransformVertex( x + (float)vecCoord.x - (float)extrudeVector.x, y + (float)vecCoord.y - (float)extrudeVector.y, z + (float)vecCoord.z - (float)extrudeVector.z, texU2, texV); vertsTop[idx] = new PositionTransformVertex(verts[idx]); vertsBottom[coords.size() - idx - 1] = new PositionTransformVertex(verts[idx + coords.size()]); if(faceLengths != null) totalLength += faceLengths[idx]; else totalLength += Math.sqrt(Math.pow(curCoord.xCoord - nextCoord.xCoord, 2) + Math.pow(curCoord.yCoord - nextCoord.yCoord, 2)); } poly[coords.size()] = new TexturedPolygon(vertsTop); poly[coords.size() + 1] = new TexturedPolygon(vertsBottom); float currentLengthPosition = totalLength; for(int idx = 0; idx < coords.size(); idx++) { Coord2D curCoord = coords.get(idx); Coord2D nextCoord = coords.get((idx + 1) % coords.size()); float currentLength = (float)Math.sqrt(Math.pow(curCoord.xCoord - nextCoord.xCoord, 2) + Math.pow(curCoord.yCoord - nextCoord.yCoord, 2)); if(faceLengths != null) currentLength = faceLengths[faceLengths.length - idx - 1]; float ratioPosition = currentLengthPosition / totalLength; float ratioLength = (currentLengthPosition - currentLength) / totalLength; float texU1 = ((ratioLength * sideTextureWidth + u) / textureWidth); float texU2 = ((ratioPosition * sideTextureWidth + u) / textureWidth); float texV1 = (((float)v + (float)shapeTextureHeight) / textureHeight); float texV2 = (((float)v + (float)shapeTextureHeight + sideTextureHeight) / textureHeight); PositionTransformVertex[] polySide = new PositionTransformVertex[4]; polySide[0] = new PositionTransformVertex(verts[idx], texU2, texV1); polySide[1] = new PositionTransformVertex(verts[coords.size() + idx], texU2, texV2); polySide[2] = new PositionTransformVertex(verts[coords.size() + ((idx + 1) % coords.size())], texU1, texV2); polySide[3] = new PositionTransformVertex(verts[(idx + 1) % coords.size()], texU1, texV1); poly[idx] = new TexturedPolygon(polySide); currentLengthPosition -= currentLength; } Shape3D shape3D = new Shape3D(verts, poly); for(TexturedPolygon face : shape3D.faces) { face.setInvertNormal(true); } return shape3D; } protected Vec3d setVectorRotations(Vec3d vector, float xRot, float yRot, float zRot) { float xC = MathHelper.cos(xRot); float xS = MathHelper.sin(xRot); float yC = MathHelper.cos(yRot); float yS = MathHelper.sin(yRot); float zC = MathHelper.cos(zRot); float zS = MathHelper.sin(zRot); double xVec = vector.x; double yVec = vector.y; double zVec = vector.z; // rotation around x double xy = xC * yVec - xS * zVec; double xz = xC * zVec + xS * yVec; // rotation around y double yz = yC * xz - yS * xVec; double yx = yC * xVec + yS * xz; // rotation around z double zx = zC * yx - zS * xy; double zy = zC * xy + zS * yx; xVec = zx; yVec = zy; zVec = yz; return new Vec3d(xVec, yVec, zVec); } public ArrayList coords; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/Shape3D.java ================================================ package com.flansmod.client.tmt; public class Shape3D { public Shape3D(PositionTransformVertex[] verts, TexturedPolygon[] poly) { vertices = verts; faces = poly; } public PositionTransformVertex[] vertices; public TexturedPolygon[] faces; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/TextureGroup.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; public class TextureGroup { public TextureGroup() { poly = new ArrayList<>(); texture = ""; } public void addPoly(TexturedPolygon polygon) { poly.add(polygon); } public void loadTexture() { loadTexture(-1); } public void loadTexture(int defaultTexture) { if(!texture.equals("")) { TextureManager renderengine = Minecraft.getMinecraft().renderEngine; renderengine.bindTexture(new ResourceLocation("", texture)); //TODO : Check. Not sure about this one } else if(defaultTexture > -1) { Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("", "")); } } public ArrayList poly; public String texture; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/TexturedPolygon.java ================================================ package com.flansmod.client.tmt; import java.util.ArrayList; import org.lwjgl.opengl.GL11; import net.minecraft.util.math.Vec3d; public class TexturedPolygon { public TexturedPolygon(PositionTextureVertex[] apositionTexturevertex) { this.invertNormal = false; this.vertexPositions = apositionTexturevertex; this.nVertices = apositionTexturevertex.length; this.iNormals = new ArrayList<>(); this.normals = new float[0]; } public TexturedPolygon(PositionTextureVertex[] apositionTexturevertex, int par2, int par3, int par4, int par5, float par6, float par7) { this(apositionTexturevertex); float var8 = 0.0F / par6; float var9 = 0.0F / par7; apositionTexturevertex[0] = apositionTexturevertex[0].setTexturePosition(par4 / par6 - var8, par3 / par7 + var9); apositionTexturevertex[1] = apositionTexturevertex[1].setTexturePosition(par2 / par6 + var8, par3 / par7 + var9); apositionTexturevertex[2] = apositionTexturevertex[2].setTexturePosition(par2 / par6 + var8, par5 / par7 - var9); apositionTexturevertex[3] = apositionTexturevertex[3].setTexturePosition(par4 / par6 - var8, par5 / par7 - var9); } public void setInvertNormal(boolean isSet) { invertNormal = isSet; } public void setNormals(float x, float y, float z) { normals = new float[]{x, y, z}; } public void flipFace() { PositionTextureVertex[] var1 = new PositionTextureVertex[this.vertexPositions.length]; for(int var2 = 0; var2 < this.vertexPositions.length; ++var2) { var1[var2] = this.vertexPositions[this.vertexPositions.length - var2 - 1]; } this.vertexPositions = var1; } public void setNormals(ArrayList vec) { iNormals = vec; } public void draw(TmtTessellator tessellator, float f) { if(nVertices == 3) tessellator.startDrawing(GL11.GL_TRIANGLES); else if(nVertices == 4) tessellator.startDrawingQuads(); else tessellator.startDrawing(GL11.GL_POLYGON); if(iNormals.isEmpty()) { if(normals.length == 3) { if(invertNormal) { tessellator.setNormal(-normals[0], -normals[1], -normals[2]); } else { tessellator.setNormal(normals[0], normals[1], normals[2]); } } else if(vertexPositions.length >= 3) { Vec3d Vec3d = vertexPositions[1].vector3D.subtract(vertexPositions[0].vector3D); Vec3d Vec31 = vertexPositions[1].vector3D.subtract(vertexPositions[2].vector3D); Vec3d Vec32 = Vec31.crossProduct(Vec3d).normalize(); if(invertNormal) { tessellator.setNormal(-(float)Vec32.x, -(float)Vec32.y, -(float)Vec32.z); } else { tessellator.setNormal((float)Vec32.x, (float)Vec32.y, (float)Vec32.z); } } else { return; } } for(int i = 0; i < nVertices; i++) { PositionTextureVertex positionTexturevertex = vertexPositions[i]; if(positionTexturevertex instanceof PositionTransformVertex) ((PositionTransformVertex)positionTexturevertex).setTransformation(); if(i < iNormals.size()) { if(invertNormal) { tessellator.setNormal(-(float)iNormals.get(i).x, -(float)iNormals.get(i).y, -(float)iNormals.get(i).z); } else { tessellator.setNormal((float)iNormals.get(i).x, (float)iNormals.get(i).y, (float)iNormals.get(i).z); } } tessellator.addVertexWithUVW((float)positionTexturevertex.vector3D.x * f, (float)positionTexturevertex.vector3D.y * f, (float)positionTexturevertex.vector3D.z * f, positionTexturevertex.texturePositionX, positionTexturevertex.texturePositionY, positionTexturevertex.texturePositionW); } tessellator.draw(); } public PositionTextureVertex[] vertexPositions; public int nVertices; private boolean invertNormal; private float[] normals; private ArrayList iNormals; } ================================================ FILE: src/main/java/com/flansmod/client/tmt/TmtTessellator.java ================================================ package com.flansmod.client.tmt; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.Arrays; import net.minecraft.client.renderer.GlStateManager; import org.lwjgl.opengl.ARBBufferObject; import org.lwjgl.opengl.ARBVertexBufferObject; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GLContext; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class TmtTessellator extends Tessellator { private static int nativeBufferSize = 0x200000; private static int trivertsInBuffer = (nativeBufferSize / 48) * 6; public static boolean renderingWorldRenderer = false; public boolean defaultTexture = false; private int rawBufferSize = 0; public int textureID = 0; /** * Boolean used to check whether quads should be drawn as two triangles. Initialized to false and never changed. */ private static boolean convertQuadsToTriangles = false; /** * Boolean used to check if we should use vertex buffers. Initialized to false and never changed. */ private static boolean tryVBO = false; /** * The byte buffer used for GL allocation. */ private static ByteBuffer byteBuffer = GLAllocation.createDirectByteBuffer(nativeBufferSize * 4); /** * The same memory as byteBuffer, but referenced as an integer buffer. */ private static IntBuffer intBuffer = byteBuffer.asIntBuffer(); /** * The same memory as byteBuffer, but referenced as an float buffer. */ private static FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); /** * Short buffer */ private static ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); /** * Raw integer array. */ private int[] rawBuffer; /** * The number of vertices to be drawn in the next draw call. Reset to 0 between draw calls. */ private int vertexCount = 0; /** * The first coordinate to be used for the texture. */ private double textureU; /** * The second coordinate to be used for the texture. */ private double textureV; /** * The fourth coordinate to be used for the texture. */ private double textureW; private int brightness; /** * The color (RGBA) value to be used for the following draw call. */ private int color; /** * Whether the current draw object for this tessellator has color values. */ private boolean hasColor = false; /** * Whether the current draw object for this tessellator has texture coordinates. */ private boolean hasTexture = false; private boolean hasBrightness = false; /** * Whether the current draw object for this tessellator has normal values. */ private boolean hasNormals = false; /** * The index into the raw buffer to be used for the next data. */ private int rawBufferIndex = 0; /** * The number of vertices manually added to the given draw call. This differs from vertexCount because it adds extra * vertices when converting quads to triangles. */ private int addedVertices = 0; /** * Disables all color information for the following draw call. */ private boolean isColorDisabled = false; /** * The draw mode currently being used by the tessellator. */ public int drawMode; /** * An offset to be applied along the x-axis for all vertices in this draw call. */ public double xOffset; /** * An offset to be applied along the y-axis for all vertices in this draw call. */ public double yOffset; /** * An offset to be applied along the z-axis for all vertices in this draw call. */ public double zOffset; /** * The normal to be applied to the face being drawn. */ private int normal; /** * The static instance of the Tessellator. */ public static TmtTessellator instance = new TmtTessellator(2097152); /** * Whether this tessellator is currently in draw mode. */ public boolean isDrawing = false; /** * Whether we are currently using VBO or not. */ private static boolean useVBO = false; /** * An IntBuffer used to store the indices of vertex buffer objects. */ private static IntBuffer vertexBuffers; /** * The index of the last VBO used. This is used in round-robin fashion, sequentially, through the vboCount vertex * buffers. */ private int vboIndex = 0; /** * Number of vertex buffer objects allocated for use. */ private static int vboCount = 10; /** * The size of the buffers used (in integers). */ private int bufferSize; private TmtTessellator(int par1) { super(2097152); } public TmtTessellator() { super(2097152); } static { instance.defaultTexture = true; useVBO = tryVBO && GLContext.getCapabilities().GL_ARB_vertex_buffer_object; if(useVBO) { vertexBuffers = GLAllocation.createDirectIntBuffer(vboCount); ARBBufferObject.glGenBuffersARB(vertexBuffers); } } /** * Draws the data set up in this tessellator and resets the state to prepare for new drawing. */ @Override public void draw() { if(!this.isDrawing) { throw new IllegalStateException("Not tesselating!"); } else { this.isDrawing = false; int offs = 0; while(offs < vertexCount) { int vtc = 0; if(drawMode == 7 && convertQuadsToTriangles) { vtc = Math.min(vertexCount - offs, trivertsInBuffer); } else { vtc = Math.min(vertexCount - offs, nativeBufferSize >> 5); } TmtTessellator.intBuffer.clear(); TmtTessellator.intBuffer.put(this.rawBuffer, offs * 10, vtc * 10); TmtTessellator.byteBuffer.position(0); TmtTessellator.byteBuffer.limit(vtc * 40); offs += vtc; if(TmtTessellator.useVBO) { this.vboIndex = (this.vboIndex + 1) % TmtTessellator.vboCount; ARBBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, TmtTessellator.vertexBuffers.get(this.vboIndex)); ARBBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, TmtTessellator.byteBuffer, ARBBufferObject.GL_STREAM_DRAW_ARB); } if(this.hasTexture) { if(TmtTessellator.useVBO) { GlStateManager.glTexCoordPointer(4, GL11.GL_FLOAT, 40, 12); } else { TmtTessellator.floatBuffer.position(3); GL11.glTexCoordPointer(4, 40, TmtTessellator.floatBuffer); } GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); } if(this.hasBrightness) { OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); if(TmtTessellator.useVBO) { GlStateManager.glTexCoordPointer(2, GL11.GL_SHORT, 40, 36); } else { TmtTessellator.shortBuffer.position(18); GL11.glTexCoordPointer(2, 40, TmtTessellator.shortBuffer); } GlStateManager.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); } if(this.hasColor) { if(TmtTessellator.useVBO) { GlStateManager.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 40, 28); } else { TmtTessellator.byteBuffer.position(28); GL11.glColorPointer(4, true, 40, TmtTessellator.byteBuffer); } GlStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY); } if(this.hasNormals) { if(TmtTessellator.useVBO) { GL11.glNormalPointer(GL11.GL_UNSIGNED_BYTE, 40, 32L); } else { TmtTessellator.byteBuffer.position(32); GL11.glNormalPointer(40, TmtTessellator.byteBuffer); } GlStateManager.glEnableClientState(GL11.GL_NORMAL_ARRAY); } if(TmtTessellator.useVBO) { GlStateManager.glVertexPointer(3, GL11.GL_FLOAT, 40, 0); } else { TmtTessellator.floatBuffer.position(0); GL11.glVertexPointer(3, 40, TmtTessellator.floatBuffer); } GlStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY); if(this.drawMode == 7 && convertQuadsToTriangles) { GlStateManager.glDrawArrays(GL11.GL_TRIANGLES, 0, vtc); } else { GlStateManager.glDrawArrays(this.drawMode, 0, vtc); } GlStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY); if(this.hasTexture) { GlStateManager.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); } if(this.hasBrightness) { OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); GlStateManager.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); } if(this.hasColor) { GlStateManager.glDisableClientState(GL11.GL_COLOR_ARRAY); } if(this.hasNormals) { GlStateManager.glDisableClientState(GL11.GL_NORMAL_ARRAY); } } if(rawBufferSize > 0x20000 && rawBufferIndex < (rawBufferSize << 3)) { rawBufferSize = 0; rawBuffer = null; } int var1 = this.rawBufferIndex * 4; this.reset(); return; } } /** * Clears the tessellator state in preparation for new drawing. */ private void reset() { this.vertexCount = 0; TmtTessellator.byteBuffer.clear(); this.rawBufferIndex = 0; this.addedVertices = 0; } /** * Sets draw mode in the tessellator to draw quads. */ public void startDrawingQuads() { this.startDrawing(7); } /** * Resets tessellator state and prepares for drawing (with the specified draw mode). */ public void startDrawing(int par1) { if(this.isDrawing) { throw new IllegalStateException("Already tesselating!"); } else { this.isDrawing = true; this.reset(); this.drawMode = par1; this.hasNormals = false; this.hasColor = false; this.hasTexture = false; this.hasBrightness = false; this.isColorDisabled = false; } } /** * Sets the texture coordinates. */ public void setTextureUV(double par1, double par3) { this.hasTexture = true; this.textureU = par1; this.textureV = par3; this.textureW = 1.0D; } /** * Sets the texture coordinates. */ public void setTextureUVW(double par1, double par3, double par4) { this.hasTexture = true; this.textureU = par1; this.textureV = par3; this.textureW = par4; } public void setBrightness(int par1) { this.hasBrightness = true; this.brightness = par1; } /** * Sets the RGB values as specified, converting from floats between 0 and 1 to integers from 0-255. */ public void setColorOpaque_F(float par1, float par2, float par3) { this.setColorOpaque((int)(par1 * 255.0F), (int)(par2 * 255.0F), (int)(par3 * 255.0F)); } /** * Sets the RGBA values for the color, converting from floats between 0 and 1 to integers from 0-255. */ public void setColorRGBA_F(float par1, float par2, float par3, float par4) { this.setColorRGBA((int)(par1 * 255.0F), (int)(par2 * 255.0F), (int)(par3 * 255.0F), (int)(par4 * 255.0F)); } /** * Sets the RGB values as specified, and sets alpha to opaque. */ public void setColorOpaque(int par1, int par2, int par3) { this.setColorRGBA(par1, par2, par3, 255); } /** * Sets the RGBA values for the color. Also clamps them to 0-255. */ public void setColorRGBA(int par1, int par2, int par3, int par4) { if(!this.isColorDisabled) { if(par1 > 255) { par1 = 255; } if(par2 > 255) { par2 = 255; } if(par3 > 255) { par3 = 255; } if(par4 > 255) { par4 = 255; } if(par1 < 0) { par1 = 0; } if(par2 < 0) { par2 = 0; } if(par3 < 0) { par3 = 0; } if(par4 < 0) { par4 = 0; } this.hasColor = true; if(ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { this.color = par4 << 24 | par3 << 16 | par2 << 8 | par1; } else { this.color = par1 << 24 | par2 << 16 | par3 << 8 | par4; } } } /** * Adds a vertex specifying both x,y,z and the texture u,v for it. */ public void addVertexWithUV(double par1, double par3, double par5, double par7, double par9) { this.setTextureUV(par7, par9); this.addVertex(par1, par3, par5); } public void addVertexWithUVW(double par1, double par3, double par5, double par7, double par9, double par10) { this.setTextureUVW(par7, par9, par10); this.addVertex(par1, par3, par5); } /** * Adds a vertex with the specified x,y,z to the current draw call. It will trigger a draw() if the buffer gets * full. */ public void addVertex(double par1, double par3, double par5) { if(rawBufferIndex >= rawBufferSize - 40) { if(rawBufferSize == 0) { rawBufferSize = 0x10000; rawBuffer = new int[rawBufferSize]; } else { rawBufferSize *= 2; rawBuffer = Arrays.copyOf(rawBuffer, rawBufferSize); } } ++this.addedVertices; if(this.drawMode == 7 && convertQuadsToTriangles && this.addedVertices % 4 == 0) { for(int var7 = 0; var7 < 2; ++var7) { int var8 = 10 * (3 - var7); if(this.hasTexture) { this.rawBuffer[this.rawBufferIndex + 3] = this.rawBuffer[this.rawBufferIndex - var8 + 3]; this.rawBuffer[this.rawBufferIndex + 4] = this.rawBuffer[this.rawBufferIndex - var8 + 4]; this.rawBuffer[this.rawBufferIndex + 5] = this.rawBuffer[this.rawBufferIndex - var8 + 5]; this.rawBuffer[this.rawBufferIndex + 6] = this.rawBuffer[this.rawBufferIndex - var8 + 6]; } if(this.hasBrightness) { this.rawBuffer[this.rawBufferIndex + 9] = this.rawBuffer[this.rawBufferIndex - var8 + 9]; } if(this.hasColor) { this.rawBuffer[this.rawBufferIndex + 7] = this.rawBuffer[this.rawBufferIndex - var8 + 7]; } this.rawBuffer[this.rawBufferIndex] = this.rawBuffer[(this.rawBufferIndex - var8)]; this.rawBuffer[this.rawBufferIndex + 1] = this.rawBuffer[this.rawBufferIndex - var8 + 1]; this.rawBuffer[this.rawBufferIndex + 2] = this.rawBuffer[this.rawBufferIndex - var8 + 2]; ++this.vertexCount; this.rawBufferIndex += 10; } } if(this.hasTexture) { this.rawBuffer[this.rawBufferIndex + 3] = Float.floatToRawIntBits((float)this.textureU); this.rawBuffer[this.rawBufferIndex + 4] = Float.floatToRawIntBits((float)this.textureV); this.rawBuffer[this.rawBufferIndex + 5] = Float.floatToRawIntBits(0.0F); this.rawBuffer[this.rawBufferIndex + 6] = Float.floatToRawIntBits((float)this.textureW); } if(this.hasBrightness) { this.rawBuffer[this.rawBufferIndex + 9] = this.brightness; } if(this.hasColor) { this.rawBuffer[this.rawBufferIndex + 7] = this.color; } if(this.hasNormals) { this.rawBuffer[this.rawBufferIndex + 8] = this.normal; } this.rawBuffer[this.rawBufferIndex] = Float.floatToRawIntBits((float)(par1 + this.xOffset)); this.rawBuffer[this.rawBufferIndex + 1] = Float.floatToRawIntBits((float)(par3 + this.yOffset)); this.rawBuffer[this.rawBufferIndex + 2] = Float.floatToRawIntBits((float)(par5 + this.zOffset)); this.rawBufferIndex += 10; ++this.vertexCount; } /** * Sets the color to the given opaque value (stored as byte values packed in an integer). */ public void setColorOpaque_I(int par1) { int j = par1 >> 16 & 255; int k = par1 >> 8 & 255; int l = par1 & 255; this.setColorOpaque(j, k, l); } /** * Sets the color to the given color (packed as bytes in integer) and alpha values. */ public void setColorRGBA_I(int par1, int par2) { int k = par1 >> 16 & 255; int l = par1 >> 8 & 255; int i1 = par1 & 255; this.setColorRGBA(k, l, i1, par2); } /** * Disables colors for the current draw call. */ public void disableColor() { this.isColorDisabled = true; } /** * Sets the normal for the current draw call. */ public void setNormal(float par1, float par2, float par3) { this.hasNormals = true; byte b0 = (byte)((int)(par1 * 127.0F)); byte b1 = (byte)((int)(par2 * 127.0F)); byte b2 = (byte)((int)(par3 * 127.0F)); this.normal = b0 & 255 | (b1 & 255) << 8 | (b2 & 255) << 16; } /** * Sets the translation for all vertices in the current draw call. */ public void setTranslation(double par1, double par3, double par5) { this.xOffset = par1; this.yOffset = par3; this.zOffset = par5; } /** * Offsets the translation for all vertices in the current draw call. */ public void addTranslation(float par1, float par2, float par3) { this.xOffset += par1; this.yOffset += par2; this.zOffset += par3; } } ================================================ FILE: src/main/java/com/flansmod/client/tmt/TransformGroup.java ================================================ package com.flansmod.client.tmt; import net.minecraft.util.math.Vec3d; public abstract class TransformGroup { public abstract double getWeight(); public abstract Vec3d doTransformation(PositionTransformVertex vertex); } ================================================ FILE: src/main/java/com/flansmod/client/tmt/TransformGroupBone.java ================================================ package com.flansmod.client.tmt; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; /** * The PositionTransformGroup class adds a class which allows for vertex transformations. * * @author GaryCXJk */ public class TransformGroupBone extends TransformGroup { public TransformGroupBone(Bone bone, double wght) { baseVector = bone.getPosition(); baseAngles = bone.getAbsoluteAngle(); attachedBone = bone; weight = wght; } public Angle3D getBaseAngles() { return baseAngles.copy(); } public Angle3D getTransformAngle() { Angle3D returnAngle = attachedBone.getAbsoluteAngle().copy(); returnAngle.angleX -= baseAngles.angleX; returnAngle.angleY -= baseAngles.angleY; returnAngle.angleZ -= baseAngles.angleZ; return returnAngle; } public Vec3d getBaseVector() { return new Vec3d(baseVector.x, baseVector.y, baseVector.z); } public Vec3d getTransformVector() { return baseVector.subtract(attachedBone.getPosition()); } public Vec3d getCurrentVector() { return attachedBone.getPosition(); } @Override public double getWeight() { return weight; } public void attachBone(Bone bone) { baseVector = bone.getPosition(); baseAngles = bone.getAbsoluteAngle(); attachedBone = bone; } @Override public Vec3d doTransformation(PositionTransformVertex vertex) { Vec3d vector = new Vec3d(vertex.neutralVector.x, vertex.neutralVector.y, vertex.neutralVector.z); vector = getBaseVector().subtract(vector); Angle3D angle = getTransformAngle(); setVectorRotations(vector, angle.angleX, angle.angleY, angle.angleZ); return vector; } protected void setVectorRotations(Vec3d vector, float xRot, float yRot, float zRot) { float xC = MathHelper.cos(xRot); float xS = MathHelper.sin(xRot); float yC = MathHelper.cos(yRot); float yS = MathHelper.sin(yRot); float zC = MathHelper.cos(zRot); float zS = MathHelper.sin(zRot); double xVec = vector.x; double yVec = vector.y; double zVec = vector.z; // rotation around x double xy = xC * yVec - xS * zVec; double xz = xC * zVec + xS * yVec; // rotation around y double yz = yC * xz - yS * xVec; double yx = yC * xVec + yS * xz; // rotation around z double zx = zC * yx - zS * xy; double zy = zC * xy + zS * yx; xVec = zx; yVec = zy; zVec = yz; vector = new Vec3d(xVec, yVec, zVec); } protected Angle3D baseAngles; protected Vec3d baseVector; protected Bone attachedBone; protected double weight; } ================================================ FILE: src/main/java/com/flansmod/client/util/FlansKeyConflictContext.java ================================================ package com.flansmod.client.util; import net.minecraft.client.Minecraft; import net.minecraftforge.client.settings.IKeyConflictContext; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.common.guns.ItemGun; @SideOnly(Side.CLIENT) public enum FlansKeyConflictContext implements IKeyConflictContext { GUN { @Override public boolean isActive() { Minecraft mc = Minecraft.getMinecraft(); return mc.player != null && (mc.player.getHeldItemMainhand().getItem() instanceof ItemGun || mc.player.getHeldItemOffhand().getItem() instanceof ItemGun); } @Override public boolean conflicts(IKeyConflictContext other) { return this == other; } }, VEHICLE { @Override public boolean isActive() { Minecraft mc = Minecraft.getMinecraft(); return mc.player != null && mc.player.getRidingEntity() instanceof IControllable; } @Override public boolean conflicts(IKeyConflictContext other) { return this == other; } } } ================================================ FILE: src/main/java/com/flansmod/client/util/WorldRenderer.java ================================================ package com.flansmod.client.util; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; public class WorldRenderer { public Tessellator tessellator; public WorldRenderer() { } public void startDrawingQuads() { tessellator = Tessellator.getInstance(); tessellator.getBuffer().begin(7, DefaultVertexFormats.POSITION_TEX); } public void addVertexWithUV(double x, double y, double z, double u, double v) { tessellator.getBuffer().pos(x, y, z).tex(u, v).endVertex(); } public void draw() { tessellator.draw(); } } ================================================ FILE: src/main/java/com/flansmod/common/BlockFlansWorkbench.java ================================================ package com.flansmod.common; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyInteger; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class BlockFlansWorkbench extends Block { public static final PropertyInteger TYPE = PropertyInteger.create("type", 0, 2); public BlockFlansWorkbench(int j, int k) { super(Material.IRON); setHardness(3F); setResistance(6F); setRegistryName("flansWorkbench"); setCreativeTab(FlansMod.tabFlanDriveables); setDefaultState(blockState.getBaseState().withProperty(TYPE, 0)); } @Override public void getSubBlocks(CreativeTabs tab, NonNullList items) { if(tab == FlansMod.tabFlanDriveables) items.add(new ItemStack(this, 1, 0)); else if(tab == FlansMod.tabFlanGuns) items.add(new ItemStack(this, 1, 1)); else if(tab == FlansMod.tabFlanParts) items.add(new ItemStack(this, 1, 2)); } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer entityplayer, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { switch(world.getBlockState(pos).getValue(TYPE)) { case 0: if(world.isRemote) entityplayer.openGui(FlansMod.INSTANCE, 0, world, pos.getX(), pos.getY(), pos.getZ()); break; case 1: if(!world.isRemote) entityplayer.openGui(FlansMod.INSTANCE, 2, world, pos.getX(), pos.getY(), pos.getZ()); break; } return true; } @Override protected BlockStateContainer createBlockState() { return new BlockStateContainer(this, TYPE); } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState().withProperty(TYPE, meta); } @Override public int getMetaFromState(IBlockState state) { return state.getValue(TYPE); } @Override public int damageDropped(IBlockState state) { return state.getValue(TYPE); } } ================================================ FILE: src/main/java/com/flansmod/common/BlockItemHolder.java ================================================ package com.flansmod.common; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyDirection; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryHelper; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; public class BlockItemHolder extends BlockContainer { public ItemHolderType type; public static final PropertyDirection FACING = PropertyDirection.create("facing", EnumFacing.Plane.HORIZONTAL); public BlockItemHolder(ItemHolderType type) { super(Material.ROCK); this.type = type; setCreativeTab(FlansMod.tabFlanParts); setHardness(2F); setResistance(4F); setRegistryName(type.shortName); setTranslationKey(type.shortName); setCreativeTab(FlansMod.tabFlanParts); setDefaultState(blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH)); type.block = this; //type.item = Item.getItemFromBlock(this); this.lightOpacity = 0; } @Override public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) { return false; } @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { EnumFacing enumfacing = EnumFacing.fromAngle((double)placer.rotationYaw); worldIn.setBlockState(pos, state.withProperty(FACING, enumfacing), 2); } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState().withProperty(FACING, EnumFacing.byHorizontalIndex(meta)); } @Override public int getMetaFromState(IBlockState state) { byte b0 = 0; return b0 | state.getValue(FACING).getHorizontalIndex(); } @Override protected BlockStateContainer createBlockState() { return new BlockStateContainer(this, FACING); } @Override public boolean canPlaceBlockAt(World par1World, BlockPos pos) { return par1World.getBlockState(pos.add(0, -1, 0)).isSideSolid(par1World, pos.add(0, -1, 0), EnumFacing.UP); } protected static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.5D, 1.0D); @Override public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { return AABB; } @Override public boolean isOpaqueCube(IBlockState state) { return false; } @Override public boolean isFullCube(IBlockState state) { return false; } @Override public TileEntity createNewTileEntity(World var1, int i) { return new TileEntityItemHolder(type); } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float par7, float par8, float par9) { if(world.isRemote) { FlansMod.playerHandler.getPlayerData(player, Side.CLIENT).shootTimeLeft = FlansMod.playerHandler.getPlayerData(player, Side.CLIENT).shootTimeRight = 10; return true; } TileEntityItemHolder holder = (TileEntityItemHolder)world.getTileEntity(pos); ItemStack item = player.getHeldItemMainhand(); if(holder.getStackInSlot(0).isEmpty()) { holder.setInventorySlotContents(0, item); player.inventory.setInventorySlotContents(player.inventory.currentItem, ItemStack.EMPTY.copy()); } else { world.spawnEntity(new EntityItem(world, pos.getX(), pos.getY(), pos.getZ(), holder.getStackInSlot(0))); holder.setInventorySlotContents(0, ItemStack.EMPTY.copy()); FlansMod.playerHandler.getPlayerData(player, Side.SERVER).shootTimeLeft = FlansMod.playerHandler.getPlayerData(player, Side.SERVER).shootTimeRight = 10; } world.scheduleUpdate(pos, this, 0); return true; } @Override public void breakBlock(World worldIn, BlockPos pos, IBlockState state) { TileEntity tileentity = worldIn.getTileEntity(pos); if(tileentity instanceof IInventory) { InventoryHelper.dropInventoryItems(worldIn, pos, (IInventory)tileentity); worldIn.updateComparatorOutputLevel(pos, this); } super.breakBlock(worldIn, pos, state); } } ================================================ FILE: src/main/java/com/flansmod/common/CommonGuiHandler.java ================================================ package com.flansmod.common; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.common.network.IGuiHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.gui.GuiGunBox; import com.flansmod.common.guns.boxes.GunBoxType; public class CommonGuiHandler implements IGuiHandler { @Override public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { return FlansMod.proxy.getServerGui(ID, player, world, x, y, z); } @Override public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { return FlansMod.proxy.getClientGui(ID, player, world, x, y, z); } @SideOnly(Side.CLIENT) public static void openGunBoxGui(EntityPlayer player, GunBoxType type) { EntityPlayerMP playerMP = (EntityPlayerMP)player; FMLClientHandler.instance().displayGuiScreen(player, new GuiGunBox(playerMP.inventory, type)); } } ================================================ FILE: src/main/java/com/flansmod/common/CommonProxy.java ================================================ package com.flansmod.common; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import com.flansmod.common.driveables.ContainerDriveableInventory; import com.flansmod.common.driveables.ContainerDriveableMenu; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.driveables.mechas.ContainerMechaInventory; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.guns.ContainerGunModTable; import com.flansmod.common.guns.boxes.ContainerGunBox; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.network.PacketBreakSound; import com.flansmod.common.paintjob.ContainerPaintjobTable; import com.flansmod.common.paintjob.TileEntityPaintjobTable; import com.flansmod.common.parts.EnumPartCategory; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; import com.google.common.io.Files; public class CommonProxy { protected static Pattern zipJar = Pattern.compile("(.+)\\.(zip|jar)$"); public void LoadAssetsFromFlanFolder() { // No-op, client only } public void addMissingJSONs(HashMap types) { } /** * A ton of client only methods follow */ public void preInit() { } public void init() { } public void forceReload() { } public void registerRenderers() { } public void doTutorialStuff(EntityPlayer player, EntityDriveable entityType) { } public void changeControlMode(EntityPlayer player) { } public boolean mouseControlEnabled() { return false; } public void openDriveableMenu(EntityPlayer player, World world, EntityDriveable driveable) { } public T loadModel(String s, String shortName, Class typeClass) { return null; } public void loadSound(String contentPack, String type, String sound) { } public boolean isThePlayer(EntityPlayer player) { return false; } public void buyGun(GunBoxType type, InfoType gun) { } /** * Gets the client GUI element from ClientProxy */ public Object getClientGui(int ID, EntityPlayer player, World world, int x, int y, int z) { return null; } /** * Gets the container for the specified GUI */ public Container getServerGui(int ID, EntityPlayer player, World world, int x, int y, int z) { switch(ID) { case 0: return null; //Driveable crafting. No server side case 1: return null; //Driveable repair. No server side case 2: return new ContainerGunModTable(player.inventory, world); case 3: return new ContainerDriveableMenu(player.inventory, world); case 4: return new ContainerDriveableMenu(player.inventory, world, true, ((EntitySeat)player.getRidingEntity()).driveable); case 5: return new ContainerGunBox(player.inventory); //Plane inventory screens case 6: return new ContainerDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 0); case 7: return new ContainerDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 1); case 8: return new ContainerDriveableMenu(player.inventory, world, true, ((EntitySeat)player.getRidingEntity()).driveable); case 9: return new ContainerDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 2); case 10: return new ContainerMechaInventory(player.inventory, world, (EntityMecha)((EntitySeat)player.getRidingEntity()).driveable); case 11: return null; //Armour box. No server side case 12: return new ContainerDriveableInventory(player.inventory, world, ((EntitySeat)player.getRidingEntity()).driveable, 3); case 13: return new ContainerPaintjobTable(player.inventory, world, (TileEntityPaintjobTable)world.getTileEntity(new BlockPos(x, y, z))); } return null; } /** * Play a block break sound here */ public void playBlockBreakSound(int x, int y, int z, Block blockHit) { FlansMod.packetHandler.sendToAll(new PacketBreakSound(x, y, z, blockHit)); } public void craftDriveable(EntityPlayer player, DriveableType type) { //Create a temporary copy of the player inventory for backup purposes InventoryPlayer temporaryInventory = new InventoryPlayer(null); temporaryInventory.copyInventory(player.inventory); //This becomes false if some recipe element is not found on the player boolean canCraft = true; //Iterate over rows then columns for(ItemStack recipeStack : type.driveableRecipe) { //The total amount of items found that match this recipe stack int totalAmountFound = 0; //Iterate over the player's inventory for(int n = 0; n < player.inventory.getSizeInventory(); n++) { //Get the stack in each slot ItemStack stackInSlot = player.inventory.getStackInSlot(n).copy(); //If the stack is what we want if(stackInSlot != null && stackInSlot.getItem() == recipeStack.getItem() && stackInSlot.getItemDamage() == recipeStack.getItemDamage()) { //Work out the amount to take from the stack int amountFound = Math.min(stackInSlot.getCount(), recipeStack.getCount() - totalAmountFound); //Take it stackInSlot.setCount(stackInSlot.getCount() - amountFound); //Check for empty stacks if(stackInSlot.getCount() <= 0) stackInSlot = ItemStack.EMPTY.copy(); //Put the modified stack back in the inventory player.inventory.setInventorySlotContents(n, stackInSlot); //Increase the amount found counter totalAmountFound += amountFound; //If we have enough, stop looking if(totalAmountFound == recipeStack.getCount()) break; } } //If we didn't find enough, give the stack a red outline if(totalAmountFound < recipeStack.getCount()) { //For some reason, the player sent a craft packet, despite being unable to canCraft = false; break; } } //Some item was missing. Restore inventory and return if(!canCraft) { player.inventory.copyInventory(temporaryInventory); return; } //Now we no longer need the temporary inventory backup, so we will use it to find the best stack of engines //Collect up all the engines into neat and tidy stacks so we can find if any of them are big enough and which of those stacks are best HashMap engines = new HashMap<>(); //Find some suitable engines for(int n = 0; n < temporaryInventory.getSizeInventory(); n++) { //Get the stack in each slot ItemStack stackInSlot = temporaryInventory.getStackInSlot(n); //Check to see if its a part if(stackInSlot != null && stackInSlot.getItem() instanceof ItemPart) { PartType partType = ((ItemPart)stackInSlot.getItem()).type; //Check its an engine if(partType.category == EnumPartCategory.ENGINE && partType.worksWith.contains(EnumType.getFromObject(type))) { //If we already have engines of this type, add these ones to the stack if(engines.containsKey(partType)) { engines.get(partType).setCount(engines.get(partType).getCount() + stackInSlot.getCount()); } //Else, make this the first stack else engines.put(partType, stackInSlot); } } } //Find the stack of engines that is fastest but which also has enough for this driveable float bestEngineSpeed = -1F; ItemStack bestEngineStack = ItemStack.EMPTY.copy(); for(PartType part : engines.keySet()) { //If this engine outperforms the currently selected best one and there are enough of them, swap if(part.engineSpeed > bestEngineSpeed && engines.get(part).getCount() >= type.numEngines()) { bestEngineSpeed = part.engineSpeed; bestEngineStack = engines.get(part).copy(); } } //If the player doesn't have any suitable engines, return if(bestEngineStack == null || bestEngineStack.isEmpty()) { player.inventory.copyInventory(temporaryInventory); return; } //Remove the engines from the inventory int numEnginesAcquired = 0; for(int n = 0; n < player.inventory.getSizeInventory(); n++) { //Get the stack in each slot ItemStack stackInSlot = player.inventory.getStackInSlot(n); //Check to see if its the engine we want if(stackInSlot != null && !stackInSlot.isEmpty() && stackInSlot.getItem() == bestEngineStack.getItem()) { //Work out the amount to take from the stack int amountFound = Math.min(stackInSlot.getCount(), type.numEngines() - numEnginesAcquired); //Take it stackInSlot.setCount(stackInSlot.getCount() - amountFound); //Check for empty stacks if(stackInSlot.getCount() <= 0) stackInSlot = ItemStack.EMPTY.copy(); //Put the modified stack back in the inventory player.inventory.setInventorySlotContents(n, stackInSlot); //Increase the amount found counter numEnginesAcquired += amountFound; //If we have enough, stop looking if(numEnginesAcquired == type.numEngines()) break; } } //Give them their brand new shiny driveable item :D ItemStack driveableStack = new ItemStack(type.item); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Engine", ((ItemPart)bestEngineStack.getItem()).type.shortName); tags.setString("Type", type.shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } driveableStack.setTagCompound(tags); if(!player.inventory.addItemStackToInventory(driveableStack)) player.dropItem(driveableStack, false); } public void repairDriveable(EntityPlayer driver, EntityDriveable driving, DriveablePart part) { //If any of this parts parent parts are broken, then it cannot be repaired for(EnumDriveablePart parent : part.type.getParents()) { if(!driving.isPartIntact(parent)) return; } //Create a temporary copy of the player inventory for backup purposes InventoryPlayer temporaryInventory = new InventoryPlayer(null); temporaryInventory.copyInventory(driver.inventory); //This becomes false if some recipe element is not found on the player boolean canRepair = true; //Get the array of stacks needed ArrayList stacksNeeded = driving.getDriveableType().getItemsRequired(part, driving.getDriveableData().engine); //Draw the stacks that should be in each slot for(ItemStack stackNeeded : stacksNeeded) { //The total amount of items found that match this recipe stack int totalAmountFound = 0; //Iterate over the temporary inventory for(int m = 0; m < temporaryInventory.getSizeInventory(); m++) { //Get the stack in each slot ItemStack stackInSlot = temporaryInventory.getStackInSlot(m).copy(); //If the stack is what we want if(stackInSlot.getItem() == stackNeeded.getItem() && stackInSlot.getItemDamage() == stackNeeded.getItemDamage()) { //Work out the amount to take from the stack int amountFound = Math.min(stackInSlot.getCount(), stackNeeded.getCount() - totalAmountFound); //Take it stackInSlot.setCount(stackInSlot.getCount() - amountFound); //Check for empty stacks if(stackInSlot.getCount() <= 0) stackInSlot = ItemStack.EMPTY.copy(); //Put the modified stack back in the inventory temporaryInventory.setInventorySlotContents(m, stackInSlot); //Increase the amount found counter totalAmountFound += amountFound; //If we have enough, stop looking if(totalAmountFound == stackNeeded.getCount()) break; } } if(totalAmountFound < stackNeeded.getCount()) canRepair = false; } if(canRepair) { driver.inventory.copyInventory(temporaryInventory); part.health = Math.max(1, part.maxHealth / 10); part.onFire = false; part.dead = false; driving.checkParts(); } } public boolean isScreenOpen() { return false; } public boolean isKeyDown(int key) { return false; } public boolean keyDown(int keycode) { return false; } public void buyArmour(String shortName, int piece, ArmourBoxType type) { } } ================================================ FILE: src/main/java/com/flansmod/common/CommonTickHandler.java ================================================ package com.flansmod.common; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import com.flansmod.common.teams.TeamsManager; public class CommonTickHandler { public CommonTickHandler() { MinecraftForge.EVENT_BUS.register(this); } @SubscribeEvent public void tick(TickEvent.ClientTickEvent event) { switch(event.phase) { case START: { break; } case END: { FlansMod.playerHandler.clientTick(); break; } } } @SubscribeEvent public void tick(TickEvent.ServerTickEvent event) { switch(event.phase) { case START: { //Handle all packets received since last tick FlansMod.getPacketHandler().handleServerPackets(); break; } case END: { if(TeamsManager.getInstance() != null) { TeamsManager.getInstance().tick(); } FlansMod.playerHandler.serverTick(); FlansMod.ticker++; break; } } } } ================================================ FILE: src/main/java/com/flansmod/common/ContentManager.java ================================================ package com.flansmod.common; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import com.flansmod.common.driveables.ItemPlane; import com.flansmod.common.driveables.ItemVehicle; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.VehicleType; import com.flansmod.common.driveables.mechas.ItemMecha; import com.flansmod.common.driveables.mechas.ItemMechaAddon; import com.flansmod.common.driveables.mechas.MechaItemType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.enchantments.GloveType; import com.flansmod.common.enchantments.ItemGlove; import com.flansmod.common.guns.AAGunType; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemAAGun; import com.flansmod.common.guns.ItemAttachment; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGrenade; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.boxes.BlockGunBox; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.teams.ArmourType; import com.flansmod.common.teams.BlockArmourBox; import com.flansmod.common.teams.ItemRewardBox; import com.flansmod.common.teams.ItemTeamArmour; import com.flansmod.common.teams.RewardBox; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.tools.ToolType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.versioning.ArtifactVersion; public class ContentManager { public class ContentPackMod implements IFlansModContentProvider { public ContentPackMod(ModContainer c, IFlansModContentProvider p) { container = c; provider = p; } public IFlansModContentProvider provider; public ModContainer container; @Override public String GetContentFolder() { return provider.GetContentFolder(); } @Override public void RegisterModelRedirects() { provider.RegisterModelRedirects(); } } public class ContentPackFlanFolder implements IFlansModContentProvider { public ContentPackFlanFolder(String n, File f) { folder = f; name = n; } public String name; public File folder; @Override public String GetContentFolder() { return name; } @Override public void RegisterModelRedirects() { try { if(folder.isDirectory()) { File redirectInfo = new File(folder, "/redirect.info"); if(redirectInfo.exists()) { BufferedReader reader = new BufferedReader(new FileReader(redirectInfo)); String src = reader.readLine(); String dst = reader.readLine(); if(src != null && dst != null) { FlansMod.log.info("Registered Flan folder model redirect from " + src + " to " + dst); FlansMod.RegisterModelRedirect(src, dst); } reader.close(); } } else if(zipJar.matcher(folder.getName()).matches()) { ZipFile zip = new ZipFile(folder); ZipEntry entry = zip.getEntry("redirect.info"); if(entry != null && !entry.isDirectory()) { BufferedReader reader = new BufferedReader(new InputStreamReader(zip.getInputStream(entry))); String src = reader.readLine(); String dst = reader.readLine(); if(src != null && dst != null) { FlansMod.log.info("Registered Flan folder model redirect from " + src + " to " + dst); FlansMod.RegisterModelRedirect(src, dst); } reader.close(); } zip.close(); } } catch(Exception e) { } } } private HashMap packs = new HashMap(); protected Pattern zipJar = Pattern.compile("(.+)\\.(zip|jar)$"); private boolean wasAnythingInFlanFolder = false; public boolean LoadedAnyContentFromFlanFolder() { return wasAnythingInFlanFolder; } public void FindContentInFlanFolder() { for(File file : FlansMod.flanDir.listFiles()) { //Load folders and valid zip files if(file.isDirectory() || zipJar.matcher(file.getName()).matches()) { //Add the directory to the content pack list if(packs.containsKey(file.getName())) { FlansMod.log.info("Skipping loading content pack from Flan folder as it is duplicated: " + file.getName()); } else { FlansMod.log.info("Loaded content pack from Flan folder : " + file.getName()); packs.put(file.getName(), new ContentPackFlanFolder(file.getName(), file)); wasAnythingInFlanFolder = true; } } } FlansMod.log.info("Loaded content pack list from Flan folder"); } public void LoadAssetsFromFlanFolder() { FlansMod.proxy.LoadAssetsFromFlanFolder(); } public void RegisterModelRedirects() { for(IFlansModContentProvider provider : packs.values()) provider.RegisterModelRedirects(); } public void FindContentInModsFolder() { // Search for content packs in the mods folder for(ModContainer container : Loader.instance().getActiveModList()) { for(ArtifactVersion requirement : container.getRequirements()) { if(requirement.getLabel().equals(FlansMod.MODID)) { if(container.getMod() instanceof IFlansModContentProvider) { IFlansModContentProvider mod = ((IFlansModContentProvider)container.getMod()); String folder = mod.GetContentFolder(); // This is a Flan's Mod dependency. Register it as a content pack File source = container.getSource(); if(source.getName().endsWith("bin")) { FlansMod.log.info("Found .java content pack" + source.getName() + " We must be in MCP. Loading from folder using IFlansModContentProvider"); packs.put(folder, new ContentPackMod(container, mod)); } else if(zipJar.matcher(source.getName()).matches()) { FlansMod.log.info("Found .jar content pack " + source.getName() + " in mods folder. Loading from jar"); packs.put(folder, new ContentPackMod(container, mod)); } } else { FlansMod.log.error("Found Flan's Mod content pack on the classpath which did not implement IFlansModContentProvider"); } } } } } private void LoadTypesFromDirectory(String contentPackName, File contentPack) { for(EnumType typeToCheckFor : EnumType.values()) { File typesDir = new File(contentPack, "/" + typeToCheckFor.folderName + "/"); if(!typesDir.exists()) continue; for(File file : FileUtils.listFiles(typesDir, new String[] {"txt" }, true)) { if(!file.isDirectory()) { try { BufferedReader reader = new BufferedReader(new FileReader(file)); String[] splitName = file.getName().split("/"); TypeFile typeFile = new TypeFile(contentPackName, typeToCheckFor, splitName[splitName.length - 1].split("\\.")[0]); for(; ; ) { String line = null; try { line = reader.readLine(); } catch(Exception e) { break; } if(line == null) break; typeFile.parseLine(line); } reader.close(); } catch(IOException e) { FlansMod.log.throwing(e); } } } } } private void LoadTypesFromArchive(String contentPackName, File contentPack) { try { ZipFile zip = new ZipFile(contentPack); ZipInputStream zipStream = new ZipInputStream(new FileInputStream(contentPack)); BufferedReader reader = new BufferedReader(new InputStreamReader(zipStream)); ZipEntry zipEntry = zipStream.getNextEntry(); do { zipEntry = zipStream.getNextEntry(); if(zipEntry == null) continue; if(zipEntry.isDirectory()) continue; TypeFile typeFile = null; for(EnumType type : EnumType.values()) { if(zipEntry.getName().startsWith(type.folderName + "/") && zipEntry.getName().split(type.folderName + "/").length > 1 && zipEntry.getName().split(type.folderName + "/")[1].length() > 0) { String[] splitName = zipEntry.getName().split("/"); typeFile = new TypeFile(zip.getName(), type, splitName[splitName.length - 1].split("\\.")[0]); } } if(typeFile == null) { continue; } for(; ; ) { String line = null; try { line = reader.readLine(); } catch(Exception e) { break; } if(line == null) break; typeFile.parseLine(line); } } while(zipEntry != null); reader.close(); zip.close(); zipStream.close(); } catch(IOException e) { FlansMod.log.throwing(e); } } public void LoadTypes() { for(HashMap.Entry entry : packs.entrySet()) { String contentPackName = entry.getKey(); IFlansModContentProvider provider = entry.getValue(); if(provider instanceof ContentPackFlanFolder) { ContentPackFlanFolder contentPack = (ContentPackFlanFolder)provider; if(contentPack.folder.isDirectory()) { LoadTypesFromDirectory(contentPackName, contentPack.folder); } else // Let's hope its a zip / jar { LoadTypesFromArchive(contentPackName, contentPack.folder); } } else if(provider instanceof ContentPackMod)// Must be a mod in the classpath { ContentPackMod mod = (ContentPackMod)provider; if(mod.container.getSource().getName().endsWith("bin")) { // If loading from inside MCP, use the content name to find content in run directory LoadTypesFromDirectory(contentPackName, new File(FlansMod.flanDir + "/" + contentPackName)); } else if(zipJar.matcher(mod.container.getSource().getName()).matches()) { // Else must be a mod loading from a jar in the mods folder LoadTypesFromArchive(contentPackName, mod.container.getSource()); } } } } public void CreateItems() { for(EnumType type : EnumType.values()) { Class typeClass = type.getTypeClass(); for(TypeFile typeFile : TypeFile.files.get(type)) { try { InfoType infoType = (typeClass.getConstructor(TypeFile.class).newInstance(typeFile)); infoType.read(typeFile); switch(type) { case bullet: new ItemBullet((BulletType)infoType).setTranslationKey(infoType.shortName); break; case attachment: new ItemAttachment((AttachmentType)infoType).setTranslationKey(infoType.shortName); break; case gun: new ItemGun((GunType)infoType).setTranslationKey(infoType.shortName); break; case grenade: new ItemGrenade((GrenadeType)infoType).setTranslationKey(infoType.shortName); break; case part: FlansMod.partItems.add((ItemPart)new ItemPart((PartType)infoType).setTranslationKey(infoType.shortName)); break; case plane: new ItemPlane((PlaneType)infoType).setTranslationKey(infoType.shortName); break; case vehicle: new ItemVehicle((VehicleType)infoType).setTranslationKey(infoType.shortName); break; case aa: new ItemAAGun((AAGunType)infoType).setTranslationKey(infoType.shortName); break; case mechaItem: new ItemMechaAddon((MechaItemType)infoType).setTranslationKey(infoType.shortName); break; case mecha: FlansMod.mechaItems.add((ItemMecha)new ItemMecha((MechaType)infoType).setTranslationKey(infoType.shortName)); break; case tool: FlansMod.toolItems.add((ItemTool)new ItemTool((ToolType)infoType).setTranslationKey(infoType.shortName)); break; case box: new BlockGunBox((GunBoxType)infoType).setTranslationKey(infoType.shortName); break; case armour: FlansMod.armourItems.add((ItemTeamArmour)new ItemTeamArmour((ArmourType)infoType).setTranslationKey(infoType.shortName)); break; case armourBox: new BlockArmourBox((ArmourBoxType)infoType).setTranslationKey(infoType.shortName); break; case playerClass: break; case team: break; case itemHolder: new BlockItemHolder((ItemHolderType)infoType); break; case rewardBox: new ItemRewardBox((RewardBox)infoType).setTranslationKey(infoType.shortName); break; case loadout: break; case glove: new ItemGlove((GloveType)infoType); break; default: FlansMod.log.warn("Unrecognised type for " + infoType.shortName); break; } } catch(Exception e) { FlansMod.log.error("Failed to add " + type.name() + " : " + typeFile.name); FlansMod.log.throwing(e); } } FlansMod.log.info("Loaded " + type.name() + "."); } } public List GetFolderContentPacks() { List result = new ArrayList(); for(HashMap.Entry entry : packs.entrySet()) { String contentPackName = entry.getKey(); IFlansModContentProvider provider = entry.getValue(); if(provider instanceof ContentPackFlanFolder) { ContentPackFlanFolder contentPack = (ContentPackFlanFolder)provider; if(contentPack.folder.isDirectory()) { result.add(contentPack.folder); } } else if(provider instanceof ContentPackMod) { ContentPackMod mod = (ContentPackMod)provider; if(mod.container.getSource().getName().endsWith("bin")) { // If loading from inside MCP, use the content name to find content in run directory result.add(new File(FlansMod.flanDir + "/" + contentPackName)); } } } return result; } } ================================================ FILE: src/main/java/com/flansmod/common/CraftingInstance.java ================================================ package com.flansmod.common; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; public class CraftingInstance { //Input fields public IInventory inventory; public List requiredStacks; public List outputStacks; //Output fields public boolean craftingSuccessful; /** * The second IInventory is an empty one to copy into */ public CraftingInstance(IInventory i, List in, List out) { inventory = i; requiredStacks = in; outputStacks = out; } public CraftingInstance(IInventory i, ArrayList in, ItemStack out) { this(i, in, Arrays.asList(out)); } public boolean canCraft() { craftingSuccessful = true; for(ItemStack check : requiredStacks) { int numMatchingStuff = 0; for(int j = 0; j < inventory.getSizeInventory(); j++) { ItemStack stack = inventory.getStackInSlot(j); if(stack != null && !stack.isEmpty() && stack.getItem() == check.getItem() && stack.getItemDamage() == check.getItemDamage()) { numMatchingStuff += stack.getCount(); } } if(numMatchingStuff < check.getCount()) { craftingSuccessful = false; } } return craftingSuccessful; } public void craft(EntityPlayer player) { if(!craftingSuccessful) return; for(ItemStack remove : requiredStacks) { int amountLeft = remove.getCount(); for(int j = 0; j < inventory.getSizeInventory(); j++) { ItemStack stack = inventory.getStackInSlot(j); if(amountLeft > 0 && stack != null && !stack.isEmpty() && stack.getItem() == remove.getItem() && stack.getItemDamage() == remove.getItemDamage()) { amountLeft -= inventory.decrStackSize(j, amountLeft).getCount(); } } } for(ItemStack stack : outputStacks) if(!player.inventory.addItemStackToInventory(stack)) player.dropItem(stack, false); } } ================================================ FILE: src/main/java/com/flansmod/common/CreativeTabFlan.java ================================================ package com.flansmod.common; import java.util.Comparator; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.guns.GunType; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class CreativeTabFlan extends CreativeTabs { public int type; //0 = Guns, 1 = Vehicles + Planes, 2 = Teams, 3 = Parts, 4 = Mechas public int icon; public int time = 0; public CreativeTabFlan(int i) { super("tabFlan" + i); type = i; } @Override public ItemStack createIcon() { icon = FlansMod.ticker / 20; switch(type) { case 0: return GunType.gunList.isEmpty() ? new ItemStack(Blocks.WOOL, 1, 4) : new ItemStack(GunType.gunList.get(icon % GunType.gunList.size()).item); case 1: return DriveableType.types.isEmpty() ? new ItemStack(Blocks.WOOL, 1, 14) : new ItemStack(DriveableType.types.get(icon % DriveableType.types.size()).item); case 2: return FlansMod.partItems.isEmpty() ? new ItemStack(Blocks.WOOL, 1, 5) : new ItemStack(FlansMod.partItems.get(icon % FlansMod.partItems.size())); case 3: return FlansMod.armourItems.isEmpty() ? new ItemStack(Blocks.WOOL, 1, 11) : new ItemStack(FlansMod.armourItems.get(icon % FlansMod.armourItems.size())); case 4: return FlansMod.mechaItems.isEmpty() ? new ItemStack(Blocks.WOOL, 1, 10) : new ItemStack(FlansMod.mechaItems.get(icon % FlansMod.mechaItems.size())); case 5: return new ItemStack(Blocks.SAND, 1, 1); } return new ItemStack(FlansMod.workbench); } @Override @SideOnly(Side.CLIENT) public void displayAllRelevantItems(NonNullList list) { super.displayAllRelevantItems(list); list.sort(new ItemSorter()); } private static class ItemSorter implements Comparator { @Override public int compare(ItemStack stackA, ItemStack stackB) { Item itemA = stackA.getItem(); Item itemB = stackB.getItem(); boolean invalidA = !(itemA instanceof IFlanItem); boolean invalidB = !(itemB instanceof IFlanItem); if(invalidA) { return invalidB ? 0 : -1; } else if(invalidB) { return 1; } InfoType typeA = ((IFlanItem)itemA).getInfoType(); InfoType typeB = ((IFlanItem)itemB).getInfoType(); if(typeA == null) { return typeB == null ? 0 : -1; } else if(typeB == null) { return 1; } int contentPackComparison = typeA.contentPack.compareTo(typeB.contentPack); if(contentPackComparison != 0) { return contentPackComparison; } int classComparison = typeA.getClass().getSimpleName().compareTo(typeB.getClass().getSimpleName()); if(classComparison != 0) { return classComparison; } return typeA.name.compareTo(typeB.name); } } } ================================================ FILE: src/main/java/com/flansmod/common/EntityItemCustomRender.java ================================================ package com.flansmod.common; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class EntityItemCustomRender extends EntityItem { public EntityItemCustomRender(Entity entity, ItemStack itemStack) { super(entity.world, entity.posX, entity.posY, entity.posZ, itemStack); this.motionX = entity.motionX; this.motionY = entity.motionY; this.motionZ = entity.motionZ; this.setPickupDelay(40); } public EntityItemCustomRender(World world, double posX, double posY, double posZ, ItemStack stack) { super(world, posX, posY, posZ, stack); } public EntityItemCustomRender(World world) { super(world); } public EntityItemCustomRender(World w, double x, double y, double z) { super(w, x, y, z); } } ================================================ FILE: src/main/java/com/flansmod/common/FlansHooks.java ================================================ package com.flansmod.common; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.common.Loader; public class FlansHooks { public Class BuildCraftEnergy; public ItemStack BuildCraftFuelBucket; public ItemStack BuildCraftOilBucket; public boolean BuildCraftLoaded; public void hook() { if(Loader.isModLoaded("BuildCraft|Energy")) { BuildCraftFuelBucket = getBuildCraftItem("bucketFuel"); BuildCraftOilBucket = getBuildCraftItem("bucketOil"); FlansMod.log.info("BuildCraft integration loaded."); BuildCraftLoaded = true; } } public ItemStack getBuildCraftItem(String name) { try { if(BuildCraftEnergy == null) BuildCraftEnergy = Class.forName("buildcraft.BuildCraftEnergy"); if(BuildCraftEnergy == null) BuildCraftEnergy = Class.forName("net.minecraft.src.buildcraft.BuildCraftEnergy"); Object ret = BuildCraftEnergy.getField(name).get(null); if(ret instanceof Item) { return new ItemStack((Item)ret); } else { throw new Exception(); } } catch(Exception e) { FlansMod.log.error("Unable to retrieve BuildCraft item " + name + "."); return ItemStack.EMPTY.copy(); } } } ================================================ FILE: src/main/java/com/flansmod/common/FlansMod.java ================================================ package com.flansmod.common; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import org.apache.logging.log4j.Logger; import net.minecraft.block.Block; import net.minecraft.block.BlockTNT; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.command.CommandHandler; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.item.crafting.ShapelessRecipes; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.LootEntry; import net.minecraft.world.storage.loot.LootEntryItem; import net.minecraft.world.storage.loot.LootPool; import net.minecraft.world.storage.loot.LootTableList; import net.minecraft.world.storage.loot.RandomValueRange; import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraft.world.storage.loot.functions.LootFunction; import net.minecraft.world.storage.loot.functions.SetCount; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.entity.player.PlayerDropsEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.Mod.Instance; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLServerStartedEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.common.versioning.ArtifactVersion; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.EntityWheel; import com.flansmod.common.driveables.ItemPlane; import com.flansmod.common.driveables.ItemVehicle; import com.flansmod.common.driveables.PlaneType; import com.flansmod.common.driveables.VehicleType; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.ItemMecha; import com.flansmod.common.driveables.mechas.ItemMechaAddon; import com.flansmod.common.driveables.mechas.MechaItemType; import com.flansmod.common.driveables.mechas.MechaType; import com.flansmod.common.enchantments.EnchantmentModule; import com.flansmod.common.eventhandlers.PlayerDeathEventListener; import com.flansmod.common.guns.AAGunType; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EntityAAGun; import com.flansmod.common.guns.EntityBullet; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.EntityMG; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemAAGun; import com.flansmod.common.guns.ItemAttachment; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGrenade; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.boxes.BlockGunBox; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.network.PacketHandler; import com.flansmod.common.paintjob.BlockPaintjobTable; import com.flansmod.common.paintjob.TileEntityPaintjobTable; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.ArmourBoxType; import com.flansmod.common.teams.ArmourType; import com.flansmod.common.teams.BlockArmourBox; import com.flansmod.common.teams.BlockSpawner; import com.flansmod.common.teams.CommandTeams; import com.flansmod.common.teams.EntityFlag; import com.flansmod.common.teams.EntityFlagpole; import com.flansmod.common.teams.EntityGunItem; import com.flansmod.common.teams.EntityTeamItem; import com.flansmod.common.teams.ItemFlagpole; import com.flansmod.common.teams.ItemOpStick; import com.flansmod.common.teams.ItemRewardBox; import com.flansmod.common.teams.ItemTeamArmour; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerClass; import com.flansmod.common.teams.RewardBox; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.teams.TeamsManagerRanked; import com.flansmod.common.teams.TileEntitySpawner; import com.flansmod.common.tools.EntityParachute; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.tools.ToolType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; @Mod(modid = FlansMod.MODID, name = "Flan's Mod", version = FlansMod.VERSION, acceptableRemoteVersions = "@ALLOWED_VERSIONS@", guiFactory = "com.flansmod.client.gui.config.ModGuiFactory") public class FlansMod { //Core mod stuff public static Logger log; public static boolean DEBUG = false; public static Configuration configFile; public static final String MODID = "flansmod"; public static final String VERSION = "@VERSION@"; @Instance(MODID) public static FlansMod INSTANCE; @SidedProxy(clientSide = "com.flansmod.client.ClientProxy", serverSide = "com.flansmod.common.CommonProxy") public static CommonProxy proxy; //A standardised ticker for all bits of the mod to call upon if they need one public static int ticker = 0; public static long lastTime; public static File flanDir, modDir; public static final float soundRange = 50F; public static final float driveableUpdateRange = 200F; public static final int numPlayerSnapshots = 20; public static boolean isApocalypseLoaded = false; public static boolean addAllPaintjobsToCreative = false; public static boolean addGunpowderRecipe = true; public static boolean shootOnRightClick = false; public static boolean forceUpdateJSONs = false; public static boolean enchantmentModuleEnabled = true; public static float armourSpawnRate = 0.25F; public static int dungeonLootChance = 500; /** * The spectator team. Moved here to avoid a concurrent modification error */ public static Team spectators = new Team("spectators", "Spectators", 0x404040, '7'); //Handlers public static final PacketHandler packetHandler = new PacketHandler(); public static final PlayerHandler playerHandler = new PlayerHandler(); public static final TeamsManager teamsManager = new TeamsManagerRanked(); public static final CommonTickHandler tickHandler = new CommonTickHandler(); public static FlansHooks hooks = new FlansHooks(); public static final ContentManager contentManager = new ContentManager(); public static final EnchantmentModule enchantmentModule = new EnchantmentModule(); public static HashMap modelDirectories = new HashMap(); //Items and creative tabs public static BlockFlansWorkbench workbench; public static ItemBlockManyNames workbenchItem; public static Item gunpowderBlockItem; public static BlockSpawner spawner; public static Block gunpowderBlock; public static ItemBlockManyNames spawnerItem; public static ItemOpStick opStick; public static ItemFlagpole flag; public static Item crosshairsymbol; public static ArrayList partItems = new ArrayList<>(); public static ArrayList mechaItems = new ArrayList<>(); public static ArrayList toolItems = new ArrayList<>(); public static ArrayList armourItems = new ArrayList<>(); public static CreativeTabFlan tabFlanGuns = new CreativeTabFlan(0), tabFlanDriveables = new CreativeTabFlan(1), tabFlanParts = new CreativeTabFlan(2), tabFlanTeams = new CreativeTabFlan(3), tabFlanMechas = new CreativeTabFlan(4); /** * Custom paintjob item */ public static Item rainbowPaintcan; public static BlockPaintjobTable paintjobTable; private static Random rewardsRandom = new Random(); public static float Pick(float totalWeight) { return rewardsRandom.nextFloat() * totalWeight; } // Register an old-new package redirect. // Previously models were in "com.flansmod.client.model." // But now that official packs are mods, different structures may make more sense // So for example the Modern pack has model keys like "mw.MP5" // Now we want these in "com.flansmod.modernweapons.client.model" // So we call this with ("mw", "com.flansmod.modernweapons.client.model") public static void RegisterModelRedirect(String key, String redirect) { modelDirectories.put(key, redirect); } /** * The mod pre-initialiser method */ @EventHandler public void preInit(FMLPreInitializationEvent event) { log = event.getModLog(); log.debug("Preinitialising Flan's mod."); MinecraftForge.EVENT_BUS.register(INSTANCE); proxy.preInit(); proxy.registerRenderers(); configFile = new Configuration(event.getSuggestedConfigurationFile()); syncConfig(); if(enchantmentModuleEnabled) enchantmentModule.PreInit(); //TODO : Load properties //configuration = new Configuration(event.getSuggestedConfigurationFile()); //loadProperties(); try { isApocalypseLoaded = true; Class.forName("com.flansmod.apocalypse.common.FlansModApocalypse"); } catch(Exception e) { isApocalypseLoaded = false; } modDir = new File(event.getModConfigurationDirectory().getParentFile(), "/mods/"); flanDir = new File(event.getModConfigurationDirectory().getParentFile(), "/Flan/"); if(!flanDir.exists()) { log.info("Flan folder not found. Creating empty folder.%n" + "You should get some content packs and put them in the Flan folder."); flanDir.mkdirs(); flanDir.mkdir(); } //Set up mod blocks and items workbench = (BlockFlansWorkbench)(new BlockFlansWorkbench(1, 0).setTranslationKey("flansWorkbench")); opStick = new ItemOpStick(); flag = (ItemFlagpole)(new ItemFlagpole().setTranslationKey("flagpole")); spawner = (BlockSpawner)(new BlockSpawner(Material.CARPET).setTranslationKey("teamsSpawner").setBlockUnbreakable().setResistance(1000000F)); rainbowPaintcan = new Item().setTranslationKey("rainbowPaintcan").setRegistryName("rainbowPaintcan").setCreativeTab(tabFlanGuns); paintjobTable = new BlockPaintjobTable(); workbenchItem = new ItemBlockManyNames(workbench); spawnerItem = new ItemBlockManyNames(spawner); crosshairsymbol = new Item().setTranslationKey("crosshairsymbol").setRegistryName("crosshairsymbol"); gunpowderBlock = new Block(Material.TNT).setHardness(0.0F).setTranslationKey("gunpowderblock").setRegistryName("gunpowderblock"); gunpowderBlockItem = new ItemBlock(gunpowderBlock).setTranslationKey("gunpowderblock").setRegistryName("gunpowderblock"); GameRegistry.registerTileEntity(TileEntitySpawner.class, new ResourceLocation("flansmod:teamsSpawner")); GameRegistry.registerTileEntity(TileEntityPaintjobTable.class, new ResourceLocation("flansmod:paintjobTable")); GameRegistry.registerTileEntity(TileEntityItemHolder.class, new ResourceLocation("flansmod:itemHolder")); //Read content packs contentManager.FindContentInModsFolder(); contentManager.FindContentInFlanFolder(); contentManager.LoadAssetsFromFlanFolder(); contentManager.RegisterModelRedirects(); contentManager.LoadTypes(); contentManager.CreateItems(); Team.spectators = spectators; //Automates JSON adding for old content packs proxy.addMissingJSONs(InfoType.infoTypes); //Force Minecraft to reload all resources in order to load content pack resources. if(contentManager.LoadedAnyContentFromFlanFolder()) proxy.forceReload(); log.debug("Preinitializing complete."); } /** * The mod initialiser method */ @EventHandler public void init(FMLInitializationEvent event) { log.info("Initialising Flan's Mod."); //Do proxy loading proxy.init(); if(enchantmentModuleEnabled) enchantmentModule.Init(); //Initialising handlers packetHandler.initialise(); NetworkRegistry.INSTANCE.registerGuiHandler(this, new CommonGuiHandler()); // Really randomise the rewards generator rewardsRandom = new Random(); rewardsRandom.setSeed(System.currentTimeMillis() ^ 0x5AB49DE08DE3B1DFL); for(int i = 0; i < 10; i++) { for(int j = 0; j < rewardsRandom.nextInt(10); j++) { rewardsRandom.nextGaussian(); } } //Config //Starting the EventListener new PlayerDeathEventListener(); log.info("Loading complete."); } @SubscribeEvent public void registerRecipes(RegistryEvent.Register event) { log.info("Registering Recipes."); InfoType.InitializeSpecialIngredients(); // Recipes for(InfoType type : InfoType.infoTypes.values()) { type.addRecipe(event.getRegistry()); } if(addGunpowderRecipe) { NonNullList ingredients = NonNullList.create(); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.GLOWSTONE_DUST))); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.COAL, 1, 1))); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.COAL, 1, 1))); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.COAL, 1, 1))); event.getRegistry().register(new ShapelessRecipes(MODID, new ItemStack(Items.GUNPOWDER), ingredients).setRegistryName("FM_Gunpowder")); } // Gunpowder block -> 9 gunpowder { NonNullList ingredients = NonNullList.create(); ingredients.add(Ingredient.fromStacks(new ItemStack(gunpowderBlock))); event.getRegistry().register(new ShapelessRecipes(MODID, new ItemStack(Items.GUNPOWDER, 9), ingredients).setRegistryName("GunpowderBlockToDust")); } // 9 gunpowder -> gunpowder block { NonNullList ingredients = NonNullList.create(); for(int i = 0; i < 9; i++) ingredients.add(Ingredient.fromStacks(new ItemStack(Items.GUNPOWDER))); event.getRegistry().register(new ShapelessRecipes(MODID, new ItemStack(gunpowderBlock), ingredients).setRegistryName("GunpowderDustToBlock")); } // Add the two workbench recipes { // ICI C = Cauldron // III I = Iron ingot NonNullList ingredients = NonNullList.create(); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.IRON_INGOT))); ingredients.add(Ingredient.fromStacks(new ItemStack(Items.CAULDRON))); for(int i = 0; i < 4; i++) ingredients.add(Ingredient.fromStacks(new ItemStack(Items.IRON_INGOT))); event.getRegistry().register(new ShapedRecipes("FlansMod", 3, 2, ingredients, new ItemStack(workbench, 1, 1)).setRegistryName("FM_Workbench")); } { // BBB B = Bowl // III I = Iron ingot // III NonNullList ingredients = NonNullList.create(); for(int i = 0; i < 3; i++) ingredients.add(Ingredient.fromStacks(new ItemStack(Items.BOWL))); for(int i = 0; i < 6; i++) ingredients.add(Ingredient.fromStacks(new ItemStack(Items.IRON_INGOT))); event.getRegistry().register(new ShapedRecipes("FlansMod", 3, 3, ingredients, new ItemStack(workbench, 1, 0)).setRegistryName("FM_Workbench2")); } } @SubscribeEvent public void registerItems(RegistryEvent.Register event) { log.info("Registering Items"); for(InfoType type : InfoType.infoTypes.values()) { type.registerItem(event.getRegistry()); } event.getRegistry().register(rainbowPaintcan); //, "rainbowPaintcan", MODID); event.getRegistry().register(opStick); //, "opStick", MODID); event.getRegistry().register(flag); //, "flagpole", MODID); event.getRegistry().register(workbenchItem); event.getRegistry().register(spawnerItem); event.getRegistry().register(crosshairsymbol); event.getRegistry().register(gunpowderBlockItem); } @SubscribeEvent public void registerBlocks(RegistryEvent.Register event) { log.info("Registering Blocks"); for(InfoType type : InfoType.infoTypes.values()) { type.registerBlock(event.getRegistry()); } event.getRegistry().register(workbench);//, ItemBlockManyNames.class, "flansWorkbench"); event.getRegistry().register(spawner); // ItemBlockManyNames.class, "teamsSpawner"); event.getRegistry().register(paintjobTable); //, "paintjobTable"); event.getRegistry().register(gunpowderBlock); } @SubscribeEvent public void registerEntities(RegistryEvent.Register event) { log.info("Registering Entities"); event.getRegistry().register(new EntityEntry(EntityFlagpole.class, "Flagpole").setRegistryName("Flagpole")); event.getRegistry().register(new EntityEntry(EntityFlag.class, "Flag").setRegistryName("Flag")); event.getRegistry().register(new EntityEntry(EntityTeamItem.class, "TeamsItem").setRegistryName("TeamsItem")); event.getRegistry().register(new EntityEntry(EntityGunItem.class, "GunItem").setRegistryName("GunItem")); event.getRegistry().register(new EntityEntry(EntityItemCustomRender.class, "CustomItem").setRegistryName("CustomItem")); event.getRegistry().register(new EntityEntry(EntityPlane.class, "Plane").setRegistryName("Plane")); event.getRegistry().register(new EntityEntry(EntityVehicle.class, "Vehicle").setRegistryName("Vehicle")); event.getRegistry().register(new EntityEntry(EntitySeat.class, "Seat").setRegistryName("Seat")); event.getRegistry().register(new EntityEntry(EntityWheel.class, "Wheel").setRegistryName("Wheel")); event.getRegistry().register(new EntityEntry(EntityParachute.class, "Parachute").setRegistryName("Parachute")); event.getRegistry().register(new EntityEntry(EntityMecha.class, "Mecha").setRegistryName("Mecha")); event.getRegistry().register(new EntityEntry(EntityBullet.class, "Bullet").setRegistryName("Bullet")); event.getRegistry().register(new EntityEntry(EntityGrenade.class, "Grenade").setRegistryName("Grenade")); event.getRegistry().register(new EntityEntry(EntityMG.class, "MG").setRegistryName("MG")); event.getRegistry().register(new EntityEntry(EntityAAGun.class, "AAGun").setRegistryName("AAGun")); event.getRegistry().register(new EntityEntry(EntityDebugVector.class, "DebugVector").setRegistryName("DebugVector")); event.getRegistry().register(new EntityEntry(EntityDebugDot.class, "DebugDot").setRegistryName("DebugDot")); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:CustomItem"), EntityItemCustomRender.class, "CustomItem", 89, this, 100, 20, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Plane"), EntityPlane.class, "Plane", 90, this, 250, 3, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:MG"), EntityMG.class, "MG", 91, this, 40, 5, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:AAGun"), EntityAAGun.class, "AAGun", 92, this, 40, 500, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Flagpole"), EntityFlagpole.class, "Flagpole", 93, this, 40, 5, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Flag"), EntityFlag.class, "Flag", 94, this, 40, 5, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Vehicle"), EntityVehicle.class, "Vehicle", 95, this, 250, 10, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Bullet"), EntityBullet.class, "Bullet", 96, this, 100, 50, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:TeamsItem"), EntityTeamItem.class, "TeamsItem", 97, this, 100, 10000, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:GunItem"), EntityGunItem.class, "GunItem", 98, this, 100, 20, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Seat"), EntitySeat.class, "Seat", 99, this, 250, 3, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Grenade"), EntityGrenade.class, "Grenade", 100, this, 40, 100, true); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Parachute"), EntityParachute.class, "Parachute", 101, this, 40, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Mecha"), EntityMecha.class, "Mecha", 102, this, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:Wheel"), EntityWheel.class, "Wheel", 103, this, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:DebugVector"), EntityDebugVector.class, "DebugVector", 104, this, 250, 20, false); EntityRegistry.registerModEntity(new ResourceLocation("flansmod:DebugDot"), EntityDebugDot.class, "DebugDot", 105, this, 250, 20, false); } private static ResourceLocation lostCitiesChest = new ResourceLocation("lostcities", "chests/lostcitychest"); private static ResourceLocation lostCitiesRailChest = new ResourceLocation("lostcities", "chests/raildungeonchest"); @SubscribeEvent public void registerLoot(LootTableLoadEvent event) { // Add default Flan's loot - extra gunpowder, iron etc if(event.getName().equals(LootTableList.CHESTS_ABANDONED_MINESHAFT) || event.getName().equals(LootTableList.CHESTS_VILLAGE_BLACKSMITH) || event.getName().equals(LootTableList.CHESTS_END_CITY_TREASURE) || event.getName().equals(LootTableList.CHESTS_NETHER_BRIDGE) || event.getName().equals(LootTableList.CHESTS_DESERT_PYRAMID) ) { for(InfoType type : InfoType.infoTypes.values()) { type.addLoot(event); } LootPool pool = event.getTable().getPool("FlansModBasicLoot"); if(pool == null) { event.getTable().addPool(new LootPool(new LootEntry[0], new LootCondition[0], new RandomValueRange(1, 3), new RandomValueRange(1, 2), "FlansModBasicLoot")); pool = event.getTable().getPool("FlansModBasicLoot"); } pool.addEntry(new LootEntryItem(gunpowderBlockItem, 8, 1, new LootFunction[] { new SetCount(new LootCondition[0], new RandomValueRange(1, 6)) }, new LootCondition[0], "gpowderblocks")); pool.addEntry(new LootEntryItem(workbenchItem, 1, 1, new LootFunction[0], new LootCondition[0], "workbenches")); pool.addEntry(new LootEntryItem(ItemBlock.getItemFromBlock(Blocks.IRON_BLOCK), 4, 1, new LootFunction[] { new SetCount(new LootCondition[0], new RandomValueRange(2, 4)) }, new LootCondition[0], "extrairon")); } // If LostCities is installed, add tons of extra loot else if(event.getName().equals(lostCitiesRailChest) || event.getName().equals(lostCitiesChest) ) { for(InfoType type : InfoType.infoTypes.values()) { type.addLoot(event); } LootPool pool = event.getTable().getPool("FlansModBasicLoot"); if(pool == null) { event.getTable().addPool(new LootPool(new LootEntry[0], new LootCondition[0], new RandomValueRange(1, 7), new RandomValueRange(1, 3), "FlansModBasicLoot")); pool = event.getTable().getPool("FlansModBasicLoot"); } pool.addEntry(new LootEntryItem(gunpowderBlockItem, 32, 1, new LootFunction[] { new SetCount(new LootCondition[0], new RandomValueRange(1, 6)) }, new LootCondition[0], "gpowderblocks")); pool.addEntry(new LootEntryItem(workbenchItem, 8, 1, new LootFunction[0], new LootCondition[0], "workbenches")); pool.addEntry(new LootEntryItem(ItemBlock.getItemFromBlock(Blocks.DIAMOND_BLOCK), 1, 1, new LootFunction[0], new LootCondition[0], "diamonde")); pool.addEntry(new LootEntryItem(ItemBlock.getItemFromBlock(Blocks.GOLD_BLOCK), 4, 1, new LootFunction[0], new LootCondition[0], "golds")); pool.addEntry(new LootEntryItem(ItemBlock.getItemFromBlock(Blocks.IRON_BLOCK), 16, 1, new LootFunction[] { new SetCount(new LootCondition[0], new RandomValueRange(2, 4)) }, new LootCondition[0], "extrairon")); } } private class FMLootFunction extends LootFunction { private int min, max; protected FMLootFunction(LootCondition[] conditionsIn) { super(conditionsIn); } @Override public ItemStack apply(ItemStack stack, Random rand, LootContext context) { return null; } } /** * The mod post-initialisation method */ @EventHandler public void postInit(FMLPostInitializationEvent event) { packetHandler.postInitialise(); if(enchantmentModuleEnabled) enchantmentModule.PostInit(); hooks.hook(); } @SubscribeEvent public void playerDrops(PlayerDropsEvent event) { for(int i = event.getDrops().size() - 1; i >= 0; i--) { EntityItem ent = event.getDrops().get(i); InfoType type = InfoType.getType(ent.getItem()); if(type != null && !type.canDrop) event.getDrops().remove(i); } } @SubscribeEvent public void playerDrops(ItemTossEvent event) { InfoType type = InfoType.getType(event.getEntityItem().getItem()); if(type != null && !type.canDrop) event.setCanceled(true); } /** * Teams command register method */ @EventHandler public void registerCommand(FMLServerStartedEvent e) { CommandHandler handler = ((CommandHandler)FMLCommonHandler.instance().getSidedDelegate().getServer().getCommandManager()); handler.registerCommand(new CommandTeams()); } @SubscribeEvent public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent eventArgs) { if(eventArgs.getModID().equals(MODID)) syncConfig(); } @SubscribeEvent public void onLivingSpecialSpawn(EntityJoinWorldEvent event) { double chance = event.getWorld().rand.nextDouble(); if(chance < armourSpawnRate && event.getEntity() instanceof EntityZombie || event.getEntity() instanceof EntitySkeleton) { if(event.getWorld().rand.nextBoolean() && ArmourType.armours.size() > 0) { //Give a completely random piece of armour ArmourType armour = ArmourType.armours.get(event.getWorld().rand.nextInt(ArmourType.armours.size())); if(armour != null && armour.type != 2) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.values()[armour.type + 1], new ItemStack(armour.item)); } else if(Team.teams.size() > 0) { //Give a random set of armour Team team = Team.teams.get(event.getWorld().rand.nextInt(Team.teams.size())); if(team.hat != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.HEAD, team.hat.copy()); if(team.chest != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.CHEST, team.chest.copy()); if(team.legs != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.LEGS, team.legs.copy()); if(team.shoes != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.FEET, team.shoes.copy()); if(team.classes.size() > 0) { PlayerClass playerClass = team.classes.get(event.getWorld().rand.nextInt(team.classes.size())); if(playerClass.hat != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.HEAD, playerClass.hat.copy()); if(playerClass.chest != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.CHEST, playerClass.chest.copy()); if(playerClass.legs != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.LEGS, playerClass.legs.copy()); if(playerClass.shoes != null) event.getEntity().setItemStackToSlot(EntityEquipmentSlot.FEET, playerClass.shoes.copy()); } } } } @SubscribeEvent public void onAttackEntity(AttackEntityEvent event) { if(event.getEntity() instanceof EntityGunItem) { event.setCanceled(true); } } /** * Reads type files from all content packs */ private void getTypeFiles(List contentPacks) { for(File contentPack : contentPacks) { if(contentPack.isDirectory()) { for(EnumType typeToCheckFor : EnumType.values()) { File typesDir = new File(contentPack, "/" + typeToCheckFor.folderName + "/"); if(!typesDir.exists()) continue; for(File file : typesDir.listFiles()) { try { BufferedReader reader = new BufferedReader(new FileReader(file)); String[] splitName = file.getName().split("/"); TypeFile typeFile = new TypeFile(contentPack.getName(), typeToCheckFor, splitName[splitName.length - 1].split("\\.")[0]); for(; ; ) { String line = null; try { line = reader.readLine(); } catch(Exception e) { break; } if(line == null) break; typeFile.parseLine(line); } reader.close(); } catch(IOException e) { FlansMod.log.throwing(e); } } } } else { try { ZipFile zip = new ZipFile(contentPack); ZipInputStream zipStream = new ZipInputStream(new FileInputStream(contentPack)); BufferedReader reader = new BufferedReader(new InputStreamReader(zipStream)); ZipEntry zipEntry = zipStream.getNextEntry(); do { zipEntry = zipStream.getNextEntry(); if(zipEntry == null) continue; TypeFile typeFile = null; for(EnumType type : EnumType.values()) { if(zipEntry.getName().startsWith(type.folderName + "/") && zipEntry.getName().split(type.folderName + "/").length > 1 && zipEntry.getName().split(type.folderName + "/")[1].length() > 0) { String[] splitName = zipEntry.getName().split("/"); typeFile = new TypeFile(zip.getName(), type, splitName[splitName.length - 1].split("\\.")[0]); } } if(typeFile == null) { continue; } for(; ; ) { String line = null; try { line = reader.readLine(); } catch(Exception e) { break; } if(line == null) break; typeFile.parseLine(line); } } while(zipEntry != null); reader.close(); zip.close(); zipStream.close(); } catch(IOException e) { FlansMod.log.throwing(e); } } } } public static PacketHandler getPacketHandler() { return INSTANCE.packetHandler; } public static void syncConfig() { addGunpowderRecipe = configFile.getBoolean("Gunpowder Recipe", Configuration.CATEGORY_GENERAL, addGunpowderRecipe, "Whether or not to add the extra gunpowder recipe (3 charcoal + 1 lightstone)"); shootOnRightClick = configFile.getBoolean("ShootOnRightClick", Configuration.CATEGORY_GENERAL, shootOnRightClick, "If true, then shoot will be on right click"); addAllPaintjobsToCreative = configFile.getBoolean("Add All Paintjobs to Creative", Configuration.CATEGORY_GENERAL, addAllPaintjobsToCreative, "Whether all paintjobs should appear in creative"); forceUpdateJSONs = configFile.getBoolean("ForceUpdateJSONs", Configuration.CATEGORY_GENERAL, forceUpdateJSONs, "Turn this on to force re-create all JSON files. Should only be used in dev environment"); enchantmentModuleEnabled = configFile.getBoolean("EnchantmentModuleEnabled", Configuration.CATEGORY_GENERAL, enchantmentModuleEnabled, "Enable gun-related enchantments"); if(configFile.hasChanged()) configFile.save(); } public static void Assert(boolean b, String string) { if(!b) { log.warn(string); } } public static EnumParticleTypes getParticleType(String s) { if(s.equals("hugeexplosion")) return EnumParticleTypes.EXPLOSION_HUGE; else if(s.equals("largeexplode")) return EnumParticleTypes.EXPLOSION_LARGE; else if(s.equals("explode")) return EnumParticleTypes.EXPLOSION_NORMAL; else if(s.equals("fireworksSpark")) return EnumParticleTypes.FIREWORKS_SPARK; else if(s.equals("bubble")) return EnumParticleTypes.WATER_BUBBLE; else if(s.equals("splash")) return EnumParticleTypes.WATER_SPLASH; else if(s.equals("wake")) return EnumParticleTypes.WATER_WAKE; else if(s.equals("drop")) return EnumParticleTypes.WATER_DROP; else if(s.equals("suspended")) return EnumParticleTypes.SUSPENDED; else if(s.equals("depthsuspend")) return EnumParticleTypes.SUSPENDED_DEPTH; else if(s.equals("townaura")) return EnumParticleTypes.TOWN_AURA; else if(s.equals("crit")) return EnumParticleTypes.CRIT; else if(s.equals("magicCrit")) return EnumParticleTypes.CRIT_MAGIC; else if(s.equals("smoke")) return EnumParticleTypes.SMOKE_NORMAL; else if(s.equals("largesmoke")) return EnumParticleTypes.SMOKE_LARGE; else if(s.equals("spell")) return EnumParticleTypes.SPELL; else if(s.equals("instantSpell")) return EnumParticleTypes.SPELL_INSTANT; else if(s.equals("mobSpell")) return EnumParticleTypes.SPELL_MOB; else if(s.equals("mobSpellAmbient")) return EnumParticleTypes.SPELL_MOB_AMBIENT; else if(s.equals("witchMagic")) return EnumParticleTypes.SPELL_WITCH; else if(s.equals("dripWater")) return EnumParticleTypes.DRIP_WATER; else if(s.equals("dripLava")) return EnumParticleTypes.DRIP_LAVA; else if(s.equals("angryVillager")) return EnumParticleTypes.VILLAGER_ANGRY; else if(s.equals("happyVillager")) return EnumParticleTypes.VILLAGER_HAPPY; else if(s.equals("note")) return EnumParticleTypes.NOTE; else if(s.equals("portal")) return EnumParticleTypes.PORTAL; else if(s.equals("enchantmenttable")) return EnumParticleTypes.ENCHANTMENT_TABLE; else if(s.equals("flame")) return EnumParticleTypes.FLAME; else if(s.equals("lava")) return EnumParticleTypes.LAVA; else if(s.equals("footstep")) return EnumParticleTypes.FOOTSTEP; else if(s.equals("cloud")) return EnumParticleTypes.CLOUD; else if(s.equals("reddust")) return EnumParticleTypes.REDSTONE; else if(s.equals("snowballpoof")) return EnumParticleTypes.SNOWBALL; else if(s.equals("snowshovel")) return EnumParticleTypes.SNOW_SHOVEL; else if(s.equals("slime")) return EnumParticleTypes.SLIME; else if(s.equals("heart")) return EnumParticleTypes.HEART; else if(s.equals("barrier")) return EnumParticleTypes.BARRIER; return EnumParticleTypes.WATER_BUBBLE; } } ================================================ FILE: src/main/java/com/flansmod/common/FlansModExplosion.java ================================================ package com.flansmod.common; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Random; import java.util.Set; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.EnchantmentProtection; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.SoundEvents; import net.minecraft.network.play.server.SPacketExplosion; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.Explosion; import net.minecraft.world.World; import net.minecraftforge.event.ForgeEventFactory; import com.flansmod.common.guns.EntityDamageSourceFlan; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.types.InfoType; public class FlansModExplosion extends Explosion { private final boolean causesFire; private final boolean breaksBlocks; private final Random random; private final World world; private final double x, y, z; private final Optional player; private final Entity explosive; private final float size; private final List affectedBlockPositions; private final Map playerKnockbackMap; private final Vec3d position; private final InfoType type; // type of Flan's Mod weapon causing explosion public FlansModExplosion(World world, Entity entity, Optional player, InfoType type, double x, double y, double z, float size, boolean causesFire, boolean smoking, boolean breaksBlocks) { super(world, entity, x, y, z, size, causesFire, smoking); this.random = new Random(); this.affectedBlockPositions = Lists.newArrayList(); this.playerKnockbackMap = Maps.newHashMap(); this.world = world; this.player = player; this.size = size; this.x = x; this.y = y; this.z = z; this.causesFire = causesFire; this.breaksBlocks = breaksBlocks && TeamsManager.explosions; this.position = new Vec3d(this.x, this.y, this.z); this.type = type; this.explosive = entity; if(!ForgeEventFactory.onExplosionStart(world, this)) { this.doExplosionA(); this.doExplosionB(smoking); for(EntityPlayer obj : world.playerEntities) { FlansMod.getPacketHandler().sendTo(new SPacketExplosion(x, y, z, size, affectedBlockPositions, getPlayerKnockbackMap().get(obj)), (EntityPlayerMP)obj); } } } /** * Does the first part of the explosion (destroy blocks) */ @Override public void doExplosionA() { Set set = Sets.newHashSet(); if(breaksBlocks) { for(int j = 0; j < 16; ++j) { for(int k = 0; k < 16; ++k) { for(int l = 0; l < 16; ++l) { if(j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15) { double d0 = (double)((float)j / 15.0F * 2.0F - 1.0F); double d1 = (double)((float)k / 15.0F * 2.0F - 1.0F); double d2 = (double)((float)l / 15.0F * 2.0F - 1.0F); double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); d0 /= d3; d1 /= d3; d2 /= d3; float f = this.size * (0.7F + this.world.rand.nextFloat() * 0.6F); double d4 = this.x; double d6 = this.y; double d8 = this.z; for(; f > 0.0F; f -= 0.22500001F) { BlockPos blockpos = new BlockPos(d4, d6, d8); IBlockState iblockstate = this.world.getBlockState(blockpos); if(iblockstate.getMaterial() != Material.AIR) { float f2 = this.explosive != null ? this.explosive.getExplosionResistance(this, this.world, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance(world, blockpos, null, this); f -= (f2 + 0.3F) * 0.3F; } if(f > 0.0F && (this.explosive == null || this.explosive.canExplosionDestroyBlock(this, this.world, blockpos, iblockstate, f))) { set.add(blockpos); } d4 += d0 * 0.30000001192092896D; d6 += d1 * 0.30000001192092896D; d8 += d2 * 0.30000001192092896D; } } } } } } this.affectedBlockPositions.addAll(set); float f3 = this.size * 2.0F; int k1 = MathHelper.floor(this.x - (double)f3 - 1.0D); int l1 = MathHelper.floor(this.x + (double)f3 + 1.0D); int i2 = MathHelper.floor(this.y - (double)f3 - 1.0D); int i1 = MathHelper.floor(this.y + (double)f3 + 1.0D); int j2 = MathHelper.floor(this.z - (double)f3 - 1.0D); int j1 = MathHelper.floor(this.z + (double)f3 + 1.0D); List list = this.world.getEntitiesWithinAABBExcludingEntity(this.explosive, new AxisAlignedBB((double)k1, (double)i2, (double)j2, (double)l1, (double)i1, (double)j1)); net.minecraftforge.event.ForgeEventFactory.onExplosionDetonate(this.world, this, list, f3); Vec3d vec3d = new Vec3d(this.x, this.y, this.z); for(Entity entity : list) { if(!entity.isImmuneToExplosions()) { double d12 = entity.getDistance(this.x, this.y, this.z) / (double)f3; if(d12 <= 1.0D) { double d5 = entity.posX - this.x; double d7 = entity.posY + (double)entity.getEyeHeight() - this.y; double d9 = entity.posZ - this.z; double d13 = (double)MathHelper.sqrt(d5 * d5 + d7 * d7 + d9 * d9); if(d13 != 0.0D) { d5 /= d13; d7 /= d13; d9 /= d13; double d14 = (double)this.world.getBlockDensity(vec3d, entity.getEntityBoundingBox()); double d10 = (1.0D - d12) * d14; if(player.isPresent()) { entity.attackEntityFrom(new EntityDamageSourceFlan(type.shortName, explosive, player.get(), type).setExplosion(), (float)((int)((d10 * d10 + d10) / 2.0D * 7.0D * (double)f3 + 1.0D))); } else { entity.attackEntityFrom(DamageSource.causeExplosionDamage(this), (float)((int)((d10 * d10 + d10) / 2.0D * 7.0D * (double)f3 + 1.0D))); } double d11 = d10; if(entity instanceof EntityLivingBase) { d11 = EnchantmentProtection.getBlastDamageReduction((EntityLivingBase)entity, d10); } entity.motionX += d5 * d11; entity.motionY += d7 * d11; entity.motionZ += d9 * d11; if(entity instanceof EntityPlayer) { EntityPlayer entityplayer = (EntityPlayer)entity; if(!entityplayer.isSpectator() && (!entityplayer.isCreative() || !entityplayer.capabilities.isFlying)) { this.playerKnockbackMap.put(entityplayer, new Vec3d(d5 * d10, d7 * d10, d9 * d10)); } } } } } } } /** * Does the second part of the explosion (sound, particles, drop spawn) */ public void doExplosionB(boolean spawnParticles) { this.world.playSound(null, this.x, this.y, this.z, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.world.rand.nextFloat() - this.world.rand.nextFloat()) * 0.2F) * 0.7F); if(this.size >= 2.0F && this.breaksBlocks) { this.world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D); } else { this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D); } if(this.breaksBlocks) { for(BlockPos blockpos : this.affectedBlockPositions) { IBlockState iblockstate = this.world.getBlockState(blockpos); Block block = iblockstate.getBlock(); if(spawnParticles) { double d0 = (double)((float)blockpos.getX() + this.world.rand.nextFloat()); double d1 = (double)((float)blockpos.getY() + this.world.rand.nextFloat()); double d2 = (double)((float)blockpos.getZ() + this.world.rand.nextFloat()); double d3 = d0 - this.x; double d4 = d1 - this.y; double d5 = d2 - this.z; double d6 = (double)MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5); d3 /= d6; d4 /= d6; d5 /= d6; double d7 = 0.5D / (d6 / (double)this.size + 0.1D); d7 *= (double)(this.world.rand.nextFloat() * this.world.rand.nextFloat() + 0.3F); d3 *= d7; d4 *= d7; d5 *= d7; this.world.spawnParticle(EnumParticleTypes.EXPLOSION_NORMAL, (d0 + this.x) / 2.0D, (d1 + this.y) / 2.0D, (d2 + this.z) / 2.0D, d3, d4, d5); this.world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5); } if(iblockstate.getMaterial() != Material.AIR) { if(block.canDropFromExplosion(this)) { block.dropBlockAsItemWithChance(this.world, blockpos, this.world.getBlockState(blockpos), 1.0F / this.size, 0); } block.onBlockExploded(this.world, blockpos, this); } } } if(this.causesFire) { for(BlockPos blockpos1 : this.affectedBlockPositions) { if(this.world.getBlockState(blockpos1).getMaterial() == Material.AIR && this.world.getBlockState(blockpos1.down()).isFullBlock() && this.random.nextInt(3) == 0) { this.world.setBlockState(blockpos1, Blocks.FIRE.getDefaultState()); } } } } @Override public Map getPlayerKnockbackMap() { return this.playerKnockbackMap; } @Override public void clearAffectedBlockPositions() { this.affectedBlockPositions.clear(); } @Override public List getAffectedBlockPositions() { return this.affectedBlockPositions; } @Override public Vec3d getPosition() { return this.position; } } ================================================ FILE: src/main/java/com/flansmod/common/IFlansModContentProvider.java ================================================ package com.flansmod.common; public interface IFlansModContentProvider { // This is generally just used for running from MCP public String GetContentFolder(); public void RegisterModelRedirects(); } ================================================ FILE: src/main/java/com/flansmod/common/ItemBlockManyNames.java ================================================ package com.flansmod.common; import net.minecraft.block.Block; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; public class ItemBlockManyNames extends ItemBlock { public ItemBlockManyNames(Block b) { super(b); setHasSubtypes(true); setRegistryName(b.getRegistryName() + "_item"); } @Override public String getTranslationKey(ItemStack stack) { return super.getTranslationKey() + "." + stack.getItemDamage(); } @Override public int getMetadata(int par1) { return par1; } @Override public CreativeTabs[] getCreativeTabs() { return new CreativeTabs[]{FlansMod.tabFlanDriveables, FlansMod.tabFlanGuns, FlansMod.tabFlanTeams, FlansMod.tabFlanParts}; } } ================================================ FILE: src/main/java/com/flansmod/common/ItemHolderType.java ================================================ package com.flansmod.common; import java.util.HashMap; import net.minecraft.block.Block; import net.minecraft.client.model.ModelBase; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.registries.IForgeRegistry; import com.flansmod.client.model.ModelItemHolder; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class ItemHolderType extends InfoType { @SideOnly(Side.CLIENT) public ModelItemHolder model; public BlockItemHolder block; private static HashMap itemHolders = new HashMap<>(); public ItemHolderType(TypeFile file) { super(file); } @Override protected void preRead(TypeFile file) { } @Override public void postRead(TypeFile file) { itemHolders.put(this.shortName, this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) model = FlansMod.proxy.loadModel(split[1], shortName, ModelItemHolder.class); } catch(Exception e) { FlansMod.log.error("Reading item holder file failed : " + shortName); FlansMod.log.throwing(e); } } @Override public void registerItem(IForgeRegistry registry) { item = new ItemBlock(block).setRegistryName(shortName + "_item"); registry.register(item); } @Override public void registerBlock(IForgeRegistry registry) { registry.register(block); } public static ItemHolderType getItemHolder(String string) { return itemHolders.get(string); } /** * To be overriden by subtypes for model reloading */ @Override public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelItemHolder.class); } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } } ================================================ FILE: src/main/java/com/flansmod/common/ModuloHelper.java ================================================ package com.flansmod.common; public class ModuloHelper { public static int divide(int x, int y) { int z = x / y; return z < 0 ? z - 1 : z; } public static int modulo(int x, int y) { int z = x % y; return z < 0 ? z + y : z; } public static double modulo(double x, double y) { double z = x % y; return z < 0 ? z + y : z; } } ================================================ FILE: src/main/java/com/flansmod/common/PlayerData.java ================================================ package com.flansmod.common; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.EntityMG; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.raytracing.PlayerSnapshot; import com.flansmod.common.teams.IPlayerClass; import com.flansmod.common.teams.Team; import com.flansmod.common.vector.Vector3f; public class PlayerData { /** * Their username */ public String username; //Movement related fields /** * Roll variables */ public float prevRotationRoll, rotationRoll; /** * Snapshots for bullet hit detection. Array size is set to number of snapshots required. When a new one is taken, * each snapshot is moved along one place and new one is added at the start, so that when the array fills up, the oldest one is lost */ public PlayerSnapshot[] snapshots; //Gun related fields /** * The MG this player is using */ public EntityMG mountingGun; /** * Stops player shooting immediately after swapping weapons */ public int shootClickDelay; /** * The speed of the minigun the player is using */ public float minigunSpeed = 0F; /** * When remote explosives are thrown they are added to this list. When the player uses a remote, the first one from this list detonates */ public ArrayList remoteExplosives = new ArrayList<>(); /** * Sound delay parameters */ public int loopedSoundDelay; /** * Sound delay parameters */ public boolean isSpinning; /** * Melee weapon custom hit simulation */ public int meleeProgress, meleeLength; /** * Tickers to stop shooting too fast */ public float shootTimeRight, shootTimeLeft; /** * True if this player is shooting */ public boolean isShootingRight, isShootingLeft; /** * Reloading booleans */ public boolean reloadingRight, reloadingLeft; /** * When the player shoots a burst fire weapon, one shot is fired immediately and this counter keeps track of how many more should be fired */ public int burstRoundsRemainingLeft = 0, burstRoundsRemainingRight = 0; // Handed getters and setters public float GetShootTime(EnumHand hand) { return hand == EnumHand.OFF_HAND ? shootTimeLeft : shootTimeRight; } public void SetShootTime(EnumHand hand, float set) { if(hand == EnumHand.OFF_HAND) shootTimeLeft = set; else shootTimeRight = set; } public int GetBurstRoundsRemaining(EnumHand hand) { return hand == EnumHand.OFF_HAND ? burstRoundsRemainingLeft : burstRoundsRemainingRight; } public void SetBurstRoundsRemaining(EnumHand hand, int set) { if(hand == EnumHand.OFF_HAND) burstRoundsRemainingLeft = set; else burstRoundsRemainingRight = set; } public Vector3f[] lastMeleePositions; //Teams related fields /** * Gametype variables */ public int score, kills, deaths; /** * Zombies variables */ public int zombieScore; /** * Gametype variable for Nerf */ public boolean out; /** * The player's vote for the next round from 1 ~ 5. 0 is not yet voted */ public int vote; /** * The team this player is currently on */ public Team team; /** * The team this player will switch to upon respawning */ public Team newTeam; /** * The class the player is currently using */ public IPlayerClass playerClass; /** * The class the player will switch to upon respawning */ public IPlayerClass newPlayerClass; /** * Keeps the player out of having to rechose their team each round */ public boolean builder; /** * Save the player's skin here, to replace after having done a swap for a certain class override */ @SideOnly(Side.CLIENT) public ResourceLocation skin; public PlayerData(String name) { username = name; snapshots = new PlayerSnapshot[FlansMod.numPlayerSnapshots]; } public void tick(EntityPlayer player) { if(player.world.isRemote) clientTick(player); if(shootTimeRight > 0) shootTimeRight--; if(shootTimeRight == 0) reloadingRight = false; if(shootTimeLeft > 0) shootTimeLeft--; if(shootTimeLeft == 0) reloadingLeft = false; if(shootClickDelay > 0) shootClickDelay--; if(loopedSoundDelay > 0) { loopedSoundDelay--; //if(loopedSoundDelay == 0 && !isShootingRight) //shouldPlayCooldownSound = true; } //Move all snapshots along one place System.arraycopy(snapshots, 0, snapshots, 1, snapshots.length - 2 + 1); //Take new snapshot snapshots[0] = new PlayerSnapshot(player); } public void clientTick(EntityPlayer player) { } public IPlayerClass getPlayerClass() { if(playerClass != newPlayerClass) playerClass = newPlayerClass; return playerClass; } public void resetScore() { score = zombieScore = kills = deaths = 0; team = newTeam = null; playerClass = newPlayerClass = null; } public void playerKilled() { mountingGun = null; isShootingRight = isShootingLeft = false; snapshots = new PlayerSnapshot[FlansMod.numPlayerSnapshots]; } public boolean isValidOffHandWeapon(EntityPlayer player, int slot) { if(slot == 0) return true; if(slot - 1 == player.inventory.currentItem) return false; ItemStack stackInSlot = player.inventory.getStackInSlot(slot - 1); if(stackInSlot == null) return false; if(stackInSlot.getItem() instanceof ItemGun) { ItemGun item = ((ItemGun)stackInSlot.getItem()); if(item.GetType().oneHanded) return true; } return false; } public void doMelee(EntityPlayer player, int meleeTime, GunType type) { meleeLength = meleeTime; lastMeleePositions = new Vector3f[type.meleePath.size()]; for(int k = 0; k < type.meleeDamagePoints.size(); k++) { Vector3f meleeDamagePoint = type.meleeDamagePoints.get(k); //Do a raytrace from the prev pos to the current pos and attack anything in the way Vector3f nextPos = type.meleePath.get(0); Vector3f nextAngles = type.meleePathAngles.get(0); RotatedAxes nextAxes = new RotatedAxes(-nextAngles.y, -nextAngles.z, nextAngles.x); Vector3f nextPosInPlayerCoords = new RotatedAxes(player.rotationYaw + 90F, player.rotationPitch, 0F).findLocalVectorGlobally(nextAxes.findLocalVectorGlobally(meleeDamagePoint)); Vector3f.add(nextPos, nextPosInPlayerCoords, nextPosInPlayerCoords); if(!FlansMod.proxy.isThePlayer(player)) nextPosInPlayerCoords.y += 1.6F; lastMeleePositions[k] = new Vector3f(player.posX + nextPosInPlayerCoords.x, player.posY + nextPosInPlayerCoords.y, player.posZ + nextPosInPlayerCoords.z); } } public void WriteToFile() { } public void ReadFromFile() { } } ================================================ FILE: src/main/java/com/flansmod/common/PlayerHandler.java ================================================ package com.flansmod.common; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.world.WorldServer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent; import net.minecraftforge.fml.relauncher.ReflectionHelper; import net.minecraftforge.fml.relauncher.Side; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.teams.TeamsManager; public class PlayerHandler { public static Map serverSideData = new HashMap<>(); public static Map clientSideData = new HashMap<>(); public static ArrayList clientsToRemoveAfterThisRound = new ArrayList<>(); public static Field floatingTickCount = null; public PlayerHandler() { MinecraftForge.EVENT_BUS.register(this); try { floatingTickCount = ReflectionHelper.findField(NetHandlerPlayServer.class, "floatingTickCount", "field_147365_f"); } catch(Exception e) { FlansMod.log.error("Couldn't find floatingTickCount field.", e); } } @SubscribeEvent public void onEntityHurt(LivingAttackEvent event) { EntityLivingBase entity = event.getEntityLiving(); if(event instanceof LivingAttackEvent && (entity.getRidingEntity() instanceof EntityDriveable || entity.getRidingEntity() instanceof EntitySeat)) { //TODO Set Drivable damage event.setCanceled(true); } } @SubscribeEvent public void onEntityKilled(LivingDeathEvent event) { EntityLivingBase entity = event.getEntityLiving(); if(entity instanceof EntityPlayer) { getPlayerData((EntityPlayer)entity).playerKilled(); } } public void serverTick() { if(FMLCommonHandler.instance().getMinecraftServerInstance() == null) { FlansMod.log.warn("Receiving server ticks when server is null"); return; } for(WorldServer world : FMLCommonHandler.instance().getMinecraftServerInstance().worlds) { for(Object player : world.playerEntities) { getPlayerData((EntityPlayer)player).tick((EntityPlayer)player); } } } public void clientTick() { if(Minecraft.getMinecraft().world != null) { for(Object player : Minecraft.getMinecraft().world.playerEntities) { getPlayerData((EntityPlayer)player).tick((EntityPlayer)player); } } } public static PlayerData getPlayerData(EntityPlayer player) { if(player == null) return null; return getPlayerData(player.getName(), player.world.isRemote ? Side.CLIENT : Side.SERVER); } public static PlayerData getPlayerData(String username) { return getPlayerData(username, Side.SERVER); } public static PlayerData getPlayerData(EntityPlayer player, Side side) { if(player == null) return null; return getPlayerData(player.getName(), side); } public static PlayerData getPlayerData(String username, Side side) { if(side.isClient()) { if(!clientSideData.containsKey(username)) clientSideData.put(username, new PlayerData(username)); } else { if(!serverSideData.containsKey(username)) serverSideData.put(username, new PlayerData(username)); } return side.isClient() ? clientSideData.get(username) : serverSideData.get(username); } @SubscribeEvent public void onPlayerEvent(PlayerEvent event) { if(event instanceof PlayerLoggedInEvent) { EntityPlayer player = event.player; String username = player.getName(); PlayerData data = new PlayerData(username); data.ReadFromFile(); if(!serverSideData.containsKey(username)) serverSideData.put(username, data); clientsToRemoveAfterThisRound.remove(username); } else if(event instanceof PlayerLoggedOutEvent) { EntityPlayer player = event.player; String username = player.getName(); clientsToRemoveAfterThisRound.add(username); if(TeamsManager.getInstance().currentRound == null) { roundEnded(); } } else if(event instanceof PlayerRespawnEvent) { EntityPlayer player = event.player; String username = player.getName(); if(!serverSideData.containsKey(username)) serverSideData.put(username, new PlayerData(username)); } } /** * Called by teams manager to remove lingering player data */ public static void roundEnded() { for(String username : clientsToRemoveAfterThisRound) { PlayerData data = serverSideData.get(username); if(data != null) { data.WriteToFile(); } serverSideData.remove(username); } } } ================================================ FILE: src/main/java/com/flansmod/common/RotatedAxes.java ================================================ package com.flansmod.common; import com.flansmod.common.vector.Matrix4f; import com.flansmod.common.vector.Vector3f; public class RotatedAxes { public RotatedAxes() { //Load identity rotationMatrix = new Matrix4f(); } public RotatedAxes(Matrix4f mat) { rotationMatrix = mat; convertMatrixToAngles(); } public RotatedAxes(float yaw, float pitch, float roll) { setAngles(yaw, pitch, roll); } @Override public RotatedAxes clone() { RotatedAxes newAxes = new RotatedAxes(); newAxes.rotationMatrix.load(getMatrix()); newAxes.convertMatrixToAngles(); return newAxes; } public boolean isValid() { if(rotationMatrix.determinant() == 0f) return false; if(Float.isNaN(rotationMatrix.determinant())) return false; return true; } public void setAngles(float yaw, float pitch, float roll) { rotationYaw = yaw; rotationPitch = pitch; rotationRoll = roll; convertAnglesToMatrix(); } public float getYaw() { return rotationYaw; } public float getPitch() { return rotationPitch; } public float getRoll() { return rotationRoll; } public Vector3f getXAxis() { return new Vector3f(rotationMatrix.m00, rotationMatrix.m10, rotationMatrix.m20); } public Vector3f getYAxis() { return new Vector3f(rotationMatrix.m01, rotationMatrix.m11, rotationMatrix.m21); } public Vector3f getZAxis() { return new Vector3f(-rotationMatrix.m02, -rotationMatrix.m12, -rotationMatrix.m22); } public Matrix4f getMatrix() { return rotationMatrix; } //Rotate locally by some angle about the yaw axis public void rotateLocalYaw(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, getYAxis().normalise(null)); convertMatrixToAngles(); } //Rotate locally by some angle about the pitch axis public void rotateLocalPitch(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, getZAxis().normalise(null)); convertMatrixToAngles(); } //Rotate locally by some angle about the roll axis public void rotateLocalRoll(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, getXAxis().normalise(null)); convertMatrixToAngles(); } //Rotate globally by some angle about the yaw axis public RotatedAxes rotateGlobalYaw(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F)); convertMatrixToAngles(); return this; } //Rotate globally by some angle about the pitch axis public RotatedAxes rotateGlobalPitch(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, new Vector3f(0F, 0F, 1F)); convertMatrixToAngles(); return this; } //Rotate globally by some angle about the roll axis public RotatedAxes rotateGlobalRoll(float rotateBy) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); convertMatrixToAngles(); return this; } //Rotate globally by some angle about the yaw axis public RotatedAxes rotateGlobalYawInRads(float rotateBy) { rotationMatrix.rotate(rotateBy, new Vector3f(0F, 1F, 0F)); convertMatrixToAngles(); return this; } //Rotate globally by some angle about the pitch axis public RotatedAxes rotateGlobalPitchInRads(float rotateBy) { rotationMatrix.rotate(rotateBy, new Vector3f(0F, 0F, 1F)); convertMatrixToAngles(); return this; } //Rotate globally by some angle about the roll axis public RotatedAxes rotateGlobalRollInRads(float rotateBy) { rotationMatrix.rotate(rotateBy, new Vector3f(1F, 0F, 0F)); convertMatrixToAngles(); return this; } //Rotate by some angle around some axis public void rotateLocal(float rotateBy, Vector3f rotateAround) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, findLocalVectorGlobally(rotateAround)); convertMatrixToAngles(); } //Rotate by some angle around some axis public void rotateGlobal(float rotateBy, Vector3f rotateAround) { rotationMatrix.rotate(rotateBy * 3.14159265F / 180F, rotateAround); convertMatrixToAngles(); } //Find a global vector in terms of this basis. public Vector3f findGlobalVectorLocally(Vector3f in) { //Create a new matrix and use the first column to store the vector we are rotating Matrix4f mat = new Matrix4f(); mat.m00 = in.x; mat.m10 = in.y; mat.m20 = in.z; //Do the rotations used to obtain this basis in reverse mat.rotate(-rotationYaw * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F)); mat.rotate(-rotationPitch * 3.14159265F / 180F, new Vector3f(0F, 0F, 1F)); mat.rotate(-rotationRoll * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); return new Vector3f(mat.m00, mat.m10, mat.m20); } //Find a local vector in terms of the global axes. public Vector3f findLocalVectorGlobally(Vector3f in) { //Create a new matrix and use the first column to store the vector we are rotating Matrix4f mat = new Matrix4f(); mat.m00 = in.x; mat.m10 = in.y; mat.m20 = in.z; //Do the rotations used to obtain this basis mat.rotate(rotationRoll * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); mat.rotate(rotationPitch * 3.14159265F / 180F, new Vector3f(0F, 0F, 1F)); mat.rotate(rotationYaw * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F)); return new Vector3f(mat.m00, mat.m10, mat.m20); } private void convertAnglesToMatrix() { //Re-load the identity rotationMatrix = new Matrix4f(); rotationMatrix.rotate(rotationRoll * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); rotationMatrix.rotate(rotationPitch * 3.14159265F / 180F, new Vector3f(0F, 0F, 1F)); rotationMatrix.rotate(rotationYaw * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F)); convertMatrixToAngles(); } private void convertMatrixToAngles() { /*rotationPitch = (float)Math.acos(getXAxis().z) * 180F / 3.14159265F; if(rotationPitch == 0F || rotationPitch == 180F) { //You've hit a pole. Exactly. With a float. Well done. } else { rotationYaw = (float)Math.atan2(-getXAxis().y, -getXAxis().x) * 180F / 3.14159265F; Matrix4f unyawedMatrix; rotationRoll = (float)Math.atan2(-getYAxis().z, getZAxis().z) * 180F / 3.14159265F; }*/ rotationYaw = (float)Math.atan2(rotationMatrix.m20, rotationMatrix.m00) * 180F / 3.14159265F; rotationPitch = (float)Math.atan2(-rotationMatrix.m10, Math.sqrt(rotationMatrix.m12 * rotationMatrix.m12 + rotationMatrix.m11 * rotationMatrix.m11)) * 180F / 3.14159265F; rotationRoll = (float)Math.atan2(rotationMatrix.m12, rotationMatrix.m11) * 180F / 3.14159265F; /* double xx = rotationMatrix.m00; double xy = rotationMatrix.m10; double xz = rotationMatrix.m20; double zx = rotationMatrix.m02; double zy = rotationMatrix.m12; double zz = rotationMatrix.m22; double sqrtX = Math.sqrt(xx * xx + xz * xz); sqrtX = (sqrtX < 1 ? sqrtX : 1); double sqrtZ = Math.sqrt(zx * zx + zz * zz); sqrtZ = (sqrtZ < 1 ? sqrtZ : 1); rotationYaw = (float)Math.atan2(zx, zz) * 180F / 3.14159265F; rotationPitch = -(float)Math.atan2(zy, sqrtZ) * 180F / 3.14159265F; Matrix4f rollOnlyMatrix = rotationMatrix.rotate(rotationYaw * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F), null).rotate(rotationPitch * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); rotationRoll = (float)Math.atan2(rollOnlyMatrix.m10, rollOnlyMatrix.m00) * 180F / 3.14159265F; */ } public RotatedAxes findLocalAxesGlobally(RotatedAxes in) { //Take the input matrix Matrix4f mat = new Matrix4f(); mat.load(in.getMatrix()); //Perform the rotations to convert from this local set of axes to the global axes mat.rotate(rotationRoll * 3.14159265F / 180F, new Vector3f(1F, 0F, 0F)); mat.rotate(rotationPitch * 3.14159265F / 180F, new Vector3f(0F, 0F, 1F)); mat.rotate(rotationYaw * 3.14159265F / 180F, new Vector3f(0F, 1F, 0F)); //Return the globalised matrix return new RotatedAxes(mat); } @Override public String toString() { return "RotatedAxes[Yaw = " + getYaw() + ", Pitch = " + getPitch() + ", Roll = " + getRoll() + "]"; } private float rotationYaw; private float rotationPitch; private float rotationRoll; private Matrix4f rotationMatrix; } ================================================ FILE: src/main/java/com/flansmod/common/TileEntityItemHolder.java ================================================ package com.flansmod.common; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.text.ITextComponent; public class TileEntityItemHolder extends TileEntity implements IInventory { private ItemStack stack = ItemStack.EMPTY.copy(); public ItemHolderType type; public TileEntityItemHolder() { } public TileEntityItemHolder(ItemHolderType type) { this.type = type; } @Override public String getName() { return "ItemHolder"; } @Override public boolean hasCustomName() { return false; } @Override public ITextComponent getDisplayName() { return null; } @Override public int getSizeInventory() { return 1; } @Override public ItemStack getStackInSlot(int index) { return getStack(); } @Override public ItemStack decrStackSize(int index, int count) { if(getStack() != null && !getStack().isEmpty()) { getStack().setCount(getStack().getCount() - count); if(getStack().getCount() <= 0) setStack(ItemStack.EMPTY.copy()); } updateToClients(); return getStack(); } @Override public void setInventorySlotContents(int index, ItemStack stack) { this.setStack(stack); } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUsableByPlayer(EntityPlayer player) { return true; } @Override public void openInventory(EntityPlayer player) { } @Override public void closeInventory(EntityPlayer player) { } @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return true; } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); NBTTagCompound stackNBT = new NBTTagCompound(); getStack().writeToNBT(stackNBT); nbt.setTag("stack", stackNBT); nbt.setString("type", type.shortName); return nbt; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); stack = new ItemStack(nbt.getCompoundTag("stack")); if(type == null) type = ItemHolderType.getItemHolder(nbt.getString("type")); } @Override public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound nbt = new NBTTagCompound(); writeToNBT(nbt); return new SPacketUpdateTileEntity(getPos(), getBlockMetadata(), nbt); } @Override public void onDataPacket(net.minecraft.network.NetworkManager net, SPacketUpdateTileEntity packet) { readFromNBT(packet.getNbtCompound()); } @Override public NBTTagCompound getUpdateTag() { return writeToNBT(new NBTTagCompound()); } public ItemStack getStack() { return stack; } public void setStack(ItemStack stack) { this.stack = stack; updateToClients(); } @Override public boolean isEmpty() { return stack == null || stack.isEmpty(); } @Override public ItemStack removeStackFromSlot(int index) { ItemStack temp = stack; stack = ItemStack.EMPTY.copy(); updateToClients(); return temp; } private void updateToClients() { world.markBlockRangeForRenderUpdate(pos, pos); world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); world.scheduleBlockUpdate(pos, this.getBlockType(), 0, 0); markDirty(); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/CollisionBox.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.vector.Vector3f; public class CollisionBox { /** * The origin in model co-ordinates */ public float x, y, z; /** * The dimensions in model co-ordinates */ public float w, h, d; /** * The health of the part this box is attached to */ public int health; /** * The part this box is attached to */ public EnumDriveablePart part; public CollisionBox(int health, int x, int y, int z, int w, int h, int d) { this.health = health; this.x = x / 16F; this.y = y / 16F; this.z = z / 16F; this.w = w / 16F; this.h = h / 16F; this.d = d / 16F; } public double Max() { double xMax = Math.max(x, x + w); double yMax = Math.max(y, y + h); double zMax = Math.max(z, z + d); return Math.sqrt(xMax * xMax + yMax * yMax + zMax * zMax); } /** * @return The centre (in global co-ordinates) */ public Vector3f getCentre() { return new Vector3f(x + w / 2F, y + h / 2F, z + d / 2F); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/CollisionSurface.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.vector.Vector3f; public class CollisionSurface { /** * The origin of this surface, relative to the current position of the driveable rounded down */ public Vector3f localisedOrigin; /** * The edge vectors of this surface such that the plane = localisedOrigin + m * u + n * v for m, n in [0,1] */ public Vector3f u, v; public CollisionSurface(Vector3f o, Vector3f u1, Vector3f v1) { localisedOrigin = o; u = u1; v = v1; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/ContainerDriveableInventory.java ================================================ package com.flansmod.common.driveables; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class ContainerDriveableInventory extends Container { public InventoryPlayer inventory; public World world; public EntityDriveable plane; public int numItems; public int screen; public int maxScroll; public int scroll; public ContainerDriveableInventory(InventoryPlayer inventoryplayer, World worldy, EntityDriveable entPlane, int i) { inventory = inventoryplayer; world = worldy; plane = entPlane; screen = i; //Find the number of items in the inventory numItems = 0; switch(i) { case 0: { numItems = plane.driveableData.numGuns; maxScroll = (numItems > 3 ? numItems - 3 : 0); break; } case 1: { numItems = plane.getDriveableType().numBombSlots; maxScroll = (((numItems + 7) / 8) > 3 ? ((numItems + 7) / 8) - 3 : 0); break; } case 2: { numItems = plane.getDriveableType().numCargoSlots; maxScroll = (((numItems + 7) / 8) > 3 ? ((numItems + 7) / 8) - 3 : 0); break; } case 3: { numItems = plane.getDriveableType().numMissileSlots; maxScroll = (((numItems + 7) / 8) > 3 ? ((numItems + 7) / 8) - 3 : 0); break; } } //Add screen specific slots switch(screen) { case 0: //Guns { int slotsDone = 0; for(int j = 0; j < plane.driveableData.numGuns; j++) { int yPos = -1000; if(slotsDone < 3 + scroll && slotsDone >= scroll) yPos = 25 + 19 * slotsDone; addSlotToContainer(new Slot(plane.driveableData, j, 29, yPos)); slotsDone++; } break; } case 1: //Bombs case 2: //Cargo case 3: //Missiles { int startSlot = plane.driveableData.getBombInventoryStart(); if(screen == 2) startSlot = plane.driveableData.getCargoInventoryStart(); if(screen == 3) startSlot = plane.driveableData.getMissileInventoryStart(); int m = ((numItems + 7) / 8); for(int row = 0; row < m; row++) { int yPos = -1000; if(row < 3 + scroll && row >= scroll) yPos = 25 + 19 * (row - scroll); for(int col = 0; col < ((row + scroll + 1) * 8 <= numItems ? 8 : numItems % 8); col++) { addSlotToContainer(new Slot(plane.driveableData, startSlot + row * 8 + col, 10 + 18 * col, yPos)); } } break; } } //Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col + row * 9 + 9, 8 + col * 18, 98 + row * 18)); } } //Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col, 8 + col * 18, 156)); } } public void updateScroll(int scrololol) { scroll = scrololol; switch(screen) { case 0: { int slotsDone = 0; for(int i = 0; i < plane.driveableData.numGuns; i++) { int yPos = -1000; if(slotsDone < 3 + scroll && slotsDone >= scroll) yPos = 25 + 19 * (slotsDone - scroll); inventorySlots.get(slotsDone).yPos = yPos; slotsDone++; } break; } case 1: case 2: case 3: { int m = ((numItems + 7) / 8); for(int row = 0; row < m; row++) { int yPos = -1000; if(row < 3 + scroll && row >= scroll) yPos = 25 + 19 * (row - scroll); for(int col = 0; col < ((row + 1) * 8 <= numItems ? 8 : numItems % 8); col++) { inventorySlots.get(row * 8 + col).yPos = yPos; } } break; } } } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); if(slotID >= numItems) { if(!mergeItemStack(slotStack, 0, numItems, false)) { return ItemStack.EMPTY.copy(); } } else { if(!mergeItemStack(slotStack, numItems, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return ItemStack.EMPTY.copy(); } currentSlot.onTake(player, slotStack); } return stack; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/ContainerDriveableMenu.java ================================================ package com.flansmod.common.driveables; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class ContainerDriveableMenu extends Container { //Fuel Container is combined with this because they are so similar public ContainerDriveableMenu(InventoryPlayer inventoryplayer, World worldy) { this(inventoryplayer, worldy, false, null); } public ContainerDriveableMenu(InventoryPlayer inventoryplayer, World worldy, boolean fuel, EntityDriveable planey) { inventory = inventoryplayer; world = worldy; plane = planey; isFuel = fuel; //Fuel slot if(isFuel) { addSlotToContainer(new Slot(plane.driveableData, plane.driveableData.getFuelSlot(), 35, 44)); } //Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col + row * 9 + 9, 8 + col * 18, 79 + (isFuel ? 0 : 19) + row * 18)); } } //Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col, 8 + col * 18, 137 + (isFuel ? 0 : 19))); } } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); if(slotID != 0) { if(!mergeItemStack(slotStack, 0, 1, false)) { return ItemStack.EMPTY.copy(); } } else { if(!mergeItemStack(slotStack, 1, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return ItemStack.EMPTY.copy(); } currentSlot.onTake(player, slotStack); } return stack; } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } public EntityDriveable plane; public boolean isFuel; public InventoryPlayer inventory; public World world; } ================================================ FILE: src/main/java/com/flansmod/common/driveables/DriveableData.java ================================================ package com.flansmod.common.driveables; import java.util.HashMap; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.text.ITextComponent; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.parts.EnumPartCategory; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; public class DriveableData implements IInventory { /** * The name of this driveable's type */ public String type; /** * The sizes of each inventory (guns, bombs / mines, missiles / shells, cargo) */ public int numGuns, numBombs, numMissiles, numCargo; /** * The inventory stacks */ public ItemStack[] ammo, bombs, missiles, cargo; /** * The engine in this driveable */ public PartType engine; /** * The stack in the fuel slot */ public ItemStack fuel; /** * The amount of fuel in the tank */ public float fuelInTank; /** * Each driveable part has a small class that holds its current status */ public HashMap parts; /** * Paintjob index */ public int paintjobID; public DriveableData(NBTTagCompound tags, int paintjobID) { this(tags); this.paintjobID = paintjobID; } public DriveableData(NBTTagCompound tags) { parts = new HashMap<>(); readFromNBT(tags); } public void readFromNBT(NBTTagCompound tag) { if(tag == null) return; if(!tag.hasKey("Type")) return; type = tag.getString("Type"); DriveableType dType = DriveableType.getDriveable(type); numBombs = dType.numBombSlots; numCargo = dType.numCargoSlots; numMissiles = dType.numMissileSlots; numGuns = dType.ammoSlots(); engine = PartType.getPart(tag.getString("Engine")); paintjobID = tag.getInteger("Paint"); ammo = new ItemStack[numGuns]; bombs = new ItemStack[numBombs]; missiles = new ItemStack[numMissiles]; cargo = new ItemStack[numCargo]; for(int i = 0; i < numGuns; i++) ammo[i] = new ItemStack(tag.getCompoundTag("Ammo " + i)); for(int i = 0; i < numBombs; i++) bombs[i] = new ItemStack(tag.getCompoundTag("Bombs " + i)); for(int i = 0; i < numMissiles; i++) missiles[i] = new ItemStack(tag.getCompoundTag("Missiles " + i)); for(int i = 0; i < numCargo; i++) cargo[i] = new ItemStack(tag.getCompoundTag("Cargo " + i)); fuel = new ItemStack(tag.getCompoundTag("Fuel")); fuelInTank = tag.getInteger("FuelInTank"); for(EnumDriveablePart part : EnumDriveablePart.values()) { parts.put(part, new DriveablePart(part, dType.health.get(part))); } for(DriveablePart part : parts.values()) { part.readFromNBT(tag); } } public void writeToNBT(NBTTagCompound tag) { tag.setString("Type", type); tag.setString("Engine", engine.shortName); tag.setInteger("Paint", paintjobID); for(int i = 0; i < ammo.length; i++) { if(ammo[i] != null) tag.setTag("Ammo " + i, ammo[i].writeToNBT(new NBTTagCompound())); } for(int i = 0; i < bombs.length; i++) { if(bombs[i] != null) tag.setTag("Bombs " + i, bombs[i].writeToNBT(new NBTTagCompound())); } for(int i = 0; i < missiles.length; i++) { if(missiles[i] != null) tag.setTag("Missiles " + i, missiles[i].writeToNBT(new NBTTagCompound())); } for(int i = 0; i < cargo.length; i++) { if(cargo[i] != null) tag.setTag("Cargo " + i, cargo[i].writeToNBT(new NBTTagCompound())); } if(fuel != null) tag.setTag("Fuel", fuel.writeToNBT(new NBTTagCompound())); tag.setInteger("FuelInTank", (int)fuelInTank); for(DriveablePart part : parts.values()) { part.writeToNBT(tag); } } @Override public int getSizeInventory() { return getFuelSlot() + 1; } @Override public ItemStack getStackInSlot(int i) { //Find the correct inventory ItemStack[] inv = ammo; if(i >= ammo.length) { i -= ammo.length; inv = bombs; if(i >= bombs.length) { i -= bombs.length; inv = missiles; if(i >= missiles.length) { i -= missiles.length; inv = cargo; if(i >= cargo.length) { return fuel; } } } } //Return the stack in the slot return inv[i]; } @Override public ItemStack decrStackSize(int i, int j) { //Find the correct inventory ItemStack[] inv = ammo; if(i >= ammo.length) { i -= ammo.length; inv = bombs; if(i >= bombs.length) { i -= bombs.length; inv = missiles; if(i >= missiles.length) { i -= missiles.length; inv = cargo; if(i >= cargo.length) { //Put the fuel stack in a stack array just to simplify the code i -= cargo.length; inv = new ItemStack[1]; inv[0] = fuel; setInventorySlotContents(getFuelSlot(), ItemStack.EMPTY.copy()); } } } } //Decrease the stack size if(inv[i] != null) { if(inv[i].getCount() <= j) { ItemStack itemstack = inv[i]; inv[i] = ItemStack.EMPTY.copy(); return itemstack; } ItemStack itemstack1 = inv[i].splitStack(j); if(inv[i].getCount() <= 0) { inv[i] = ItemStack.EMPTY.copy(); } return itemstack1; } else { return ItemStack.EMPTY.copy(); } } @Override public void setInventorySlotContents(int i, ItemStack stack) { //Find the correct inventory ItemStack[] inv = ammo; if(i >= ammo.length) { i -= ammo.length; inv = bombs; if(i >= bombs.length) { i -= bombs.length; inv = missiles; if(i >= missiles.length) { i -= missiles.length; inv = cargo; if(i >= cargo.length) { fuel = stack; return; } } } } //Set the stack inv[i] = stack; } @Override public int getInventoryStackLimit() { return 64; } @Override public void markDirty() { } @Override public boolean isUsableByPlayer(EntityPlayer player) { return true; } public int getAmmoInventoryStart() { return 0; } public int getBombInventoryStart() { return ammo.length; } public int getMissileInventoryStart() { return ammo.length + bombs.length; } public int getCargoInventoryStart() { return ammo.length + bombs.length + missiles.length; } public int getFuelSlot() { return ammo.length + bombs.length + missiles.length + cargo.length; } @Override public boolean isItemValidForSlot(int i, ItemStack itemstack) { if(i < getBombInventoryStart() && itemstack != null && itemstack.getItem() instanceof ItemBullet) //Ammo { return true; } if(i >= getBombInventoryStart() && i < getMissileInventoryStart() && itemstack != null && itemstack.getItem() instanceof ItemBullet) //Ammo { return true; } if(i >= getMissileInventoryStart() && i < getCargoInventoryStart() && itemstack != null && itemstack.getItem() instanceof ItemBullet) { return true; } if(i >= getCargoInventoryStart() && i < getFuelSlot()) { return true; } if(i == getFuelSlot() && itemstack != null && itemstack.getItem() instanceof ItemPart && ((ItemPart)itemstack.getItem()).type.category == EnumPartCategory.FUEL) //Fuel { return true; } return false; } @Override public String getName() { return "Flan's Secret Data"; } @Override public boolean hasCustomName() { return false; } @Override public ITextComponent getDisplayName() { return null; } @Override public void openInventory(EntityPlayer player) { } @Override public void closeInventory(EntityPlayer player) { } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { } @Override public boolean isEmpty() { return false; } @Override public ItemStack removeStackFromSlot(int index) { return ItemStack.EMPTY.copy(); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/DriveablePart.java ================================================ package com.flansmod.common.driveables; import net.minecraft.nbt.NBTTagCompound; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.raytracing.FlansModRaytracer.DriveableHit; import com.flansmod.common.vector.Vector3f; public class DriveablePart { public EnumDriveablePart type; public CollisionBox box; public int maxHealth; public int health; public int fireTime; public boolean onFire; /** * Keeps track of whether death code has been called or not */ public boolean dead; public DriveablePart(EnumDriveablePart e, CollisionBox b) { type = e; box = b; health = maxHealth = b == null ? 0 : b.health; } public void update(EntityDriveable driveable) { if(fireTime > 0) fireTime--; if(fireTime == 0) onFire = false; if(onFire) health--; if(health <= 0 && maxHealth > 0) { health = 0; dead = true; } } public void writeToNBT(NBTTagCompound tags) { tags.setInteger(type.getShortName() + "_Health", health); tags.setBoolean(type.getShortName() + "_Fire", onFire); } public void readFromNBT(NBTTagCompound tags) { if(!tags.hasKey(type.getShortName() + "_Health")) { health = maxHealth; onFire = false; return; } health = tags.getInteger(type.getShortName() + "_Health"); onFire = tags.getBoolean(type.getShortName() + "_Fire"); } /** * Called when a corner of this part hits the ground. * * @return The amount of damage to do to the block */ public float smashIntoGround(EntityDriveable driveable, float damage) { //In these cases, there was no collision, so don't damage this or the block if(box == null || dead) return 0; if(!driveable.canHitPart(type)) return 0; //This part is immortal. Smash that block into oblivion if(maxHealth == 0) return damage; //As standard, take half damage and return the other half health -= (int)(damage / 2F); return damage / 2F; } /** * Called by bullets that may have hit the plane * * @return A bullet hit if it hit. Otherwise null */ public DriveableHit rayTrace(EntityDriveable driveable, Vector3f origin, Vector3f motion) { if(box == null || health <= 0 || dead) return null; if(!driveable.canHitPart(type)) return null; //Complicated. Will explain later. Someone remind me. /* boolean enteringX = coordIsEntering(origin.x, origin.x + motion.x, box.x / 16F, (box.x + box.w) / 16F); boolean enteringY = coordIsEntering(origin.y, origin.y + motion.y, box.y / 16F, (box.y + box.h) / 16F); boolean enteringZ = coordIsEntering(origin.z, origin.z + motion.z, box.z / 16F, (box.z + box.d) / 16F); boolean inX = coordIsIn(origin.x, origin.x + motion.x, box.x / 16F, (box.x + box.w) / 16F); boolean inY = coordIsIn(origin.y, origin.y + motion.y, box.y / 16F, (box.y + box.h) / 16F); boolean inZ = coordIsIn(origin.z, origin.z + motion.z, box.z / 16F, (box.z + box.d) / 16F); boolean hit = (enteringX && inY && inZ) || (inX && enteringY && inZ) || (inX && inY && enteringZ); */ //We now have an AABB starting at box(x, y, z) and with dimensions box(w, h, d) and our ray in the same coordinate system //We are looking for a point at which the ray enters the box, so we need only consider faces that the ray can see. Partition the space into 3 areas in each axis //X - axis and faces x = box.x and x = box.x + box.w if(motion.x != 0F) { if(origin.x < box.x) //Check face x = o.x { float intersectTime = (box.x - origin.x) / motion.x; float intersectY = origin.y + motion.y * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectY >= box.y && intersectY <= box.y + box.h && intersectZ >= box.z && intersectZ <= box.z + box.d) return new DriveableHit(driveable, type, intersectTime); } else if(origin.x > box.x + box.w) //Check face x = o.x + d.x { float intersectTime = (box.x + box.w - origin.x) / motion.x; float intersectY = origin.y + motion.y * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectY >= box.y && intersectY <= box.y + box.h && intersectZ >= box.z && intersectZ <= box.z + box.d) return new DriveableHit(driveable, type, intersectTime); } } //Z - axis and faces z = box.z and z = box.z + box.d if(motion.z != 0F) { if(origin.z < box.z) //Check face z = box.z { float intersectTime = (box.z - origin.z) / motion.z; float intersectX = origin.x + motion.x * intersectTime; float intersectY = origin.y + motion.y * intersectTime; if(intersectX >= box.x && intersectX <= box.x + box.w && intersectY >= box.y && intersectY <= box.y + box.h) return new DriveableHit(driveable, type, intersectTime); } else if(origin.z > box.z + box.d) //Check face z = box.z + box.d { float intersectTime = (box.z + box.d - origin.z) / motion.z; float intersectX = origin.x + motion.x * intersectTime; float intersectY = origin.y + motion.y * intersectTime; if(intersectX >= box.x && intersectX <= box.x + box.w && intersectY >= box.y && intersectY <= box.y + box.h) return new DriveableHit(driveable, type, intersectTime); } } //Y - axis and faces y = box.y and y = box.y + box.h if(motion.y != 0F) { if(origin.y < box.y) //Check face y = o.y { float intersectTime = (box.y - origin.y) / motion.y; float intersectX = origin.x + motion.x * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectX >= box.x && intersectX <= box.x + box.w && intersectZ >= box.z && intersectZ <= box.z + box.d) return new DriveableHit(driveable, type, intersectTime); } else if(origin.y > box.y + box.h) //Check face x = box.y + box.h { float intersectTime = (box.y + box.h - origin.y) / motion.y; float intersectX = origin.x + motion.x * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectX >= box.x && intersectX <= box.x + box.w && intersectZ >= box.z && intersectZ <= box.z + box.d) return new DriveableHit(driveable, type, intersectTime); } } return null; } /** * Called when the bullet decided that it hit this driveable part */ public void hitByBullet(BulletType type, float damage) { //Perform damage code health -= damage * type.damageVsDriveable; if(type.setEntitiesOnFire) { fireTime = 20; onFire = true; } } /** * Ray traces a single co-ordinate * But only returns true once upon entering the box, and not while in or exiting * * @param start The start of the ray in this co-ordinate * @param end The end of the ray in this co-ordinate * @param min The start of the box in this co-ordinate * @param max The end of the box in this co-ordinate * @return true if the ray hits in this co-ordinate */ private boolean coordIsEntering(float start, float end, float min, float max) { //Check to see if ray entered from the left hand side if(start < min && end >= min) return true; //Check to see if ray entered from the right hand side if(start > max && end <= max) return true; return false; } /** * Ray traces a single co-ordinate * Returns true if the ray is in the bounds at some point along its length * * @param start The start of the ray in this co-ordinate * @param end The end of the ray in this co-ordinate * @param min The start of the box in this co-ordinate * @param max The end of the box in this co-ordinate * @return true if the ray hits in this co-ordinate */ private boolean coordIsIn(float start, float end, float min, float max) { //Check to see if the start point is in if(start >= min && start <= max) return true; //Check to see if the end point is in if(end >= min && end <= max) return true; //Check to see if the start and end points are either side of the interval if(start < min && end > max) return true; if(end < min && start > max) return true; return false; } public boolean attack(float damage, boolean fireDamage) { health -= damage; if(fireDamage) { fireTime = 20; onFire = true; } return health <= 0; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/DriveablePosition.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.vector.Vector3f; /** * Defines a position on a driveable in local co-ordinates, with a note of the part this is attached to for damage handling */ public class DriveablePosition { /** * The position */ public Vector3f position; /** * The part this is attached to */ public EnumDriveablePart part; public DriveablePosition(Vector3f v, EnumDriveablePart p) { position = v; part = p; } public DriveablePosition(String[] split) { this(new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F), EnumDriveablePart.getPart(split[4])); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/DriveableType.java ================================================ package com.flansmod.common.driveables; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import net.minecraft.block.material.Material; import net.minecraft.client.model.ModelBase; import net.minecraft.init.Items; import net.minecraft.item.EnumDyeColor; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelDriveable; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.collisions.CollisionShapeBox; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.vector.Vector3f; public abstract class DriveableType extends PaintableType { @SideOnly(value = Side.CLIENT) /** The plane model */ public ModelDriveable model; //Health and recipe /** Health of each driveable part */ public HashMap health = new HashMap<>(); /** Recipe parts associated to each driveable part */ public HashMap partwiseRecipe = new HashMap<>(); /** Recipe parts as one complete list */ public ArrayList driveableRecipe = new ArrayList<>(); //Ammo /** If true, then all ammo is accepted. Default is true to minimise backwards compatibility issues */ public boolean acceptAllAmmo = true; /** The list of bullet types that can be used in this driveable for the main gun (tank shells, plane bombs etc) */ public List ammo = new ArrayList<>(); //Harvesting variables /** If true, then this vehicle harvests blocks from the harvester hitbox and places them in the inventory */ public boolean harvestBlocks = false; /** What materials this harvester eats */ public ArrayList materialsHarvested = new ArrayList<>(); public boolean collectHarvest = false; public boolean dropHarvest = false; public Vector3f harvestBoxSize = new Vector3f(0, 0, 0); public Vector3f harvestBoxPos = new Vector3f(0, 0, 0); public int reloadSoundTick = 15214541; public float fallDamageFactor = 1.0F; //Weapon variables /** The weapon type assigned to left mouse */ public EnumWeaponType primary = EnumWeaponType.NONE, secondary = EnumWeaponType.NONE; /** Whether to alternate weapons or fire all at once */ public boolean alternatePrimary = false, alternateSecondary = false; /** Delays. Can override gun delays */ public int shootDelayPrimary = 1, shootDelaySecondary = 1; /** Firing modes for primary and secondary guns. Minigun also an option */ public EnumFireMode modePrimary = EnumFireMode.FULLAUTO, modeSecondary = EnumFireMode.FULLAUTO; /** Damage modifiers, so that different vehicles firing the same weapons can do different damage */ public int damageModifierPrimary = 1, damageModifierSecondary = 1; /** Positions of primary and secondary weapons */ public ArrayList shootPointsPrimary = new ArrayList<>(); public ArrayList shootPointsSecondary = new ArrayList<>(); /** Pilot guns also have their own separate array so ammo handling can be done */ public ArrayList pilotGuns = new ArrayList<>(); /** Sounds */ public String shootSoundPrimary, shootSoundSecondary; public int reloadTimePrimary = 0, reloadTimeSecondary = 0; public String reloadSoundPrimary = "", reloadSoundSecondary = ""; public int placeTimePrimary = 5, placeTimeSecondary = 5; public String placeSoundPrimary = "", placeSoundSecondary = ""; //Passengers /** The number of passengers, not including the pilot */ public int numPassengers = 0; /** Seat objects for holding information about the position and gun setup of each seat */ public Seat[] seats; /** Automatic counter used to setup ammo inventory for gunners */ public int numPassengerGunners = 0; //Rendering variables /** Inventory sizes */ public int numCargoSlots, numBombSlots, numMissileSlots; /** The fuel tank size */ public int fuelTankSize = 100; //Rendering variables /** The yOffset of the model. Shouldn't be needed if you made your model properly */ public float yOffset = 10F / 16F; /** Third person render distance */ public float cameraDistance = 5F; //Particle system /** A list of ambient particle emitters on this vehicle */ public ArrayList emitters = new ArrayList<>(); // Shoot particles public float vehicleGunModelScale = 1f; public double hitboxRadius = 0d; public static class ShootParticle { public ShootParticle(String s, float x1, float y1, float z1) { x = x1; y = y1; z = z1; name = s; } float x = 0, y = 0, z = 0; String name; } public ArrayList shootParticlesPrimary = new ArrayList<>(); public ArrayList shootParticlesSecondary = new ArrayList<>(); //Movement variables /** Generic movement modifiers, no longer repeated for plane and vehicle */ public float maxThrottle = 1F, maxNegativeThrottle = 0F; public float ClutchBrake = 0F; /** The origin of the tank turret */ public Vector3f turretOrigin = new Vector3f(); public Vector3f turretOriginOffset = new Vector3f(); /** Wheel positions */ public DriveablePosition[] wheelPositions = new DriveablePosition[0]; /** Strength of springs connecting car to wheels */ public float wheelSpringStrength = 0.5F; /** The wheel radius for onGround checks */ public float wheelStepHeight = 1.0F; /** Whether or not the vehicle rolls */ public boolean canRoll = true; /** * */ public float turretRotationSpeed = 2.5F; /** Collision points for block based collisions */ public ArrayList collisionPoints = new ArrayList<>(); /** Coefficient of drag */ public float drag = 1F; //Boat Stuff /** If true, then the vehicles wheels float on water */ public boolean floatOnWater = false; /** Defines where you can place this vehicle */ public boolean placeableOnLand = true, placeableOnWater = false, placeableOnSponge = false; /** The upwards force to apply to the vehicle per wheel when on water */ public float buoyancy = 0.0165F; public float floatOffset = 0; /** The radius within which to check for bullets */ public float bulletDetectionRadius = 5F; /** Plane is shown on ICBM Radar and engaged by AA Guns */ public boolean onRadar = false; /** Track animation frames */ public int animFrames = 2; /** Sounds */ public String startSound = ""; public int startSoundLength; public String engineSound = ""; public int engineSoundLength; public boolean collisionDamageEnable = false; public float collisionDamageThrottle = 0; public float collisionDamageTimes = 0; public boolean enableReloadTime = false; public boolean canMountEntity = false; public float bulletSpread = 0F; public float bulletSpeed = 3F; public boolean rangingGun = false; public boolean isExplosionWhenDestroyed = false; public String lockedOnSound = ""; public int canLockOnAngle = 10; public int lockOnSoundTime = 60; public int lockedOnSoundRange = 5; public String lockingOnSound = ""; public boolean lockOnToPlanes = false, lockOnToVehicles = false, lockOnToMechas = false, lockOnToPlayers = false, lockOnToLivings = false; //flares public boolean hasFlare = false; public int flareDelay = 20 * 10; public String flareSound = ""; public int timeFlareUsing = 1; // radar (for mapwriter) /** * The height of the entity that can be detected by radar.
-1 = It does not detect.
*/ public int radarDetectableAltitude = -1; public boolean stealth = false; /** Barrel Recoil stuff */ public float recoilDist = 5F; public float recoilTime = 5F; /** more nonsense */ public boolean fixedPrimaryFire = false; public Vector3f primaryFireAngle = new Vector3f(0, 0, 0); /** backwards compatibility attempt */ public float gunLength = 0; public boolean setPlayerInvisible = false; public float maxThrottleInWater = 0.5F; public ArrayList leftTrackPoints = new ArrayList<>(); public ArrayList rightTrackPoints = new ArrayList<>(); public float trackLinkLength = 0; /** activator boolean for IT-1 reloads */ public boolean IT1 = false; public ArrayList collisionBox = new ArrayList<>(); public boolean fancyCollision = false; public static ArrayList types = new ArrayList<>(); private static HashMap> parsers = new HashMap<>(); static { // BASICS ///////////////////////////////////////////////////////////////////////////// parsers.put("MaxThrottle", (split, d) -> d.maxThrottle = Float.parseFloat(split[1])); parsers.put("MaxNegativeThrottle", (split, d) -> d.maxNegativeThrottle = Float.parseFloat(split[1])); parsers.put("Drag", (split, d) -> d.drag = Float.parseFloat(split[1])); parsers.put("TurretOrigin", (split, d) -> d.turretOrigin = new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F)); parsers.put("TurretRotationSpeed", (split, d) -> d.turretRotationSpeed = Float.parseFloat(split[1])); parsers.put("CanRoll", (split, d) -> d.canRoll = Boolean.parseBoolean(split[1])); parsers.put("YOffset", (split, d) -> d.yOffset = Float.parseFloat(split[1])); parsers.put("CameraDistance", (split, d) -> d.cameraDistance = Float.parseFloat(split[1])); // BOATS //////////////////////////////////////////////////////////////////////////// parsers.put("PlaceableOnLand", (split, d) -> d.placeableOnLand = Boolean.parseBoolean(split[1])); parsers.put("PlaceableOnWater", (split, d) -> d.placeableOnWater = Boolean.parseBoolean(split[1])); parsers.put("FloatOnWater", (split, d) -> d.floatOnWater = Boolean.parseBoolean(split[1])); parsers.put("Boat", (split, d) -> { d.placeableOnLand = false; d.placeableOnWater = true; d.floatOnWater = true; d.wheelStepHeight = 0F; }); parsers.put("Buoyancy", (split, d) -> d.buoyancy = Float.parseFloat(split[1])); // WHEELS //////////////////////////////////////////////////////////////////////////////// parsers.put("Wheel", (split, d) -> d.wheelPositions[Integer.parseInt(split[1])] = new DriveablePosition(new Vector3f( Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F, Float.parseFloat(split[4]) / 16F), split.length > 5 ? EnumDriveablePart.getPart(split[5]) : EnumDriveablePart.coreWheel)); parsers.put("WheelPosition", parsers.get("Wheel")); // Alt name parsers.put("WheelRadius", (split, d) -> d.wheelStepHeight = Float.parseFloat(split[1])); parsers.put("WheelStepHeight", parsers.get("WheelRadius")); // Alt name parsers.put("WheelSpringStrength", (split, d) -> d.wheelSpringStrength = Float.parseFloat(split[1])); parsers.put("SpringStrength", parsers.get("WheelSpringStrength")); // Alt name // HARVESTERS ////////////////////////////////////////////////////////////////////////////// parsers.put("Harvester", (split, d) -> d.harvestBlocks = Boolean.parseBoolean(split[1])); parsers.put("HarvestMaterial", (split, d) -> d.materialsHarvested.add(getMaterial(split[1]))); parsers.put("HarvestToolType", (split, d) -> { switch(split[1]) { case "Axe": d.materialsHarvested.add(Material.WOOD); d.materialsHarvested.add(Material.PLANTS); d.materialsHarvested.add(Material.VINE); break; case "Pickaxe": case "Drill": d.materialsHarvested.add(Material.IRON); d.materialsHarvested.add(Material.ANVIL); d.materialsHarvested.add(Material.ROCK); break; case "Spade": case "Shovel": case "Excavator": d.materialsHarvested.add(Material.GROUND); d.materialsHarvested.add(Material.GRASS); d.materialsHarvested.add(Material.SAND); d.materialsHarvested.add(Material.SNOW); d.materialsHarvested.add(Material.CLAY); break; case "Hoe": case "Combine": d.materialsHarvested.add(Material.PLANTS); d.materialsHarvested.add(Material.LEAVES); d.materialsHarvested.add(Material.VINE); d.materialsHarvested.add(Material.CACTUS); d.materialsHarvested.add(Material.GOURD); break; } }); // CARGO //////////////////////////////////////////////////////////////////////////////////////// parsers.put("CargoSlots", (split, d) -> d.numCargoSlots = Integer.parseInt(split[1])); parsers.put("BombSlots", (split, d) -> d.numBombSlots = Integer.parseInt(split[1])); parsers.put("MineSlots", parsers.get("BombSlots")); // Alt name parsers.put("MissileSlots", (split, d) -> d.numMissileSlots = Integer.parseInt(split[1])); parsers.put("ShellSlots", parsers.get("MissileSlots")); // Alt name parsers.put("FuelTankSize", (split, d) -> d.fuelTankSize = Integer.parseInt(split[1])); parsers.put("TrackFrames", (split, d) -> d.animFrames = Integer.parseInt(split[1]) - 1); parsers.put("BulletDetection", (split, d) -> d.bulletDetectionRadius = Integer.parseInt(split[1])); // AMMO //////////////////////////////////////////////////////////////////////////////////////// parsers.put("AddAmmo", (split, d) -> d.ammo.add(BulletType.getBullet(split[1]))); parsers.put("AllowAllAmmo", (split, d) -> d.acceptAllAmmo = Boolean.parseBoolean(split[1])); parsers.put("AcceptAllAmmo", parsers.get("AllowAllAmmo")); // Alt name parsers.put("Primary", (split, d) -> d.primary = EnumWeaponType.valueOf(split[1].toUpperCase())); parsers.put("Secondary", (split, d) -> d.secondary = EnumWeaponType.valueOf(split[1].toUpperCase())); parsers.put("ShootDelayPrimary", (split, d) -> d.shootDelayPrimary = Integer.parseInt(split[1])); parsers.put("ShootDelaySecondary", (split, d) -> d.shootDelaySecondary = Integer.parseInt(split[1])); parsers.put("DamageModifierPrimary", (split, d) -> d.damageModifierPrimary = Integer.parseInt(split[1])); parsers.put("DamageModifierSecondary", (split, d) -> d.damageModifierSecondary = Integer.parseInt(split[1])); parsers.put("AlternatePrimary", (split, d) -> d.alternatePrimary = Boolean.parseBoolean(split[1])); parsers.put("AlternateSecondary", (split, d) -> d.alternateSecondary = Boolean.parseBoolean(split[1])); parsers.put("ModePrimary", (split, d) -> d.modePrimary = EnumFireMode.valueOf(split[1].toUpperCase())); parsers.put("ModeSecondary", (split, d) -> d.modeSecondary = EnumFireMode.valueOf(split[1].toUpperCase())); parsers.put("ShootPointPrimary", (split, d) -> { DriveablePosition rootPos; Vector3f offPos; String[] gun; if(split.length == 9) { gun = new String[]{split[0], split[1], split[2], split[3], split[4], split[5]}; offPos = new Vector3f(Float.parseFloat(split[6]) / 16F, Float.parseFloat(split[7]) / 16F, Float.parseFloat(split[8]) / 16F); } else if(split.length == 8) { gun = new String[]{split[0], split[1], split[2], split[3], split[4]}; offPos = new Vector3f(Float.parseFloat(split[5]) / 16F, Float.parseFloat(split[6]) / 16F, Float.parseFloat(split[7]) / 16F); } else { gun = split; offPos = new Vector3f(0, 0, 0); } rootPos = d.getShootPoint(gun); ShootPoint sPoint = new ShootPoint(rootPos, offPos); d.shootPointsPrimary.add(sPoint); if(rootPos instanceof PilotGun) d.pilotGuns.add((PilotGun)sPoint.rootPos); }); parsers.put("ShootPointSecondary", (split, d) -> { DriveablePosition rootPos; Vector3f offPos; String[] gun; if(split.length == 9) { gun = new String[]{split[0], split[1], split[2], split[3], split[4], split[5]}; offPos = new Vector3f(Float.parseFloat(split[6]) / 16F, Float.parseFloat(split[7]) / 16F, Float.parseFloat(split[8]) / 16F); } else if(split.length == 8) { gun = new String[]{split[0], split[1], split[2], split[3], split[4]}; offPos = new Vector3f(Float.parseFloat(split[5]) / 16F, Float.parseFloat(split[6]) / 16F, Float.parseFloat(split[7]) / 16F); } else { gun = split; offPos = new Vector3f(0, 0, 0); } rootPos = d.getShootPoint(gun); ShootPoint sPoint = new ShootPoint(rootPos, offPos); d.shootPointsSecondary.add(sPoint); if(rootPos instanceof PilotGun) d.pilotGuns.add((PilotGun)sPoint.rootPos); }); // BACKWARDS COMPATIBILITY //////////////////////////////////////////////////////////// parsers.put("AddGun", (split, d) -> { d.secondary = EnumWeaponType.GUN; PilotGun pilotGun = (PilotGun)d.getShootPoint(split); d.shootPointsSecondary.add(new ShootPoint(pilotGun, new Vector3f(0, 0, 0))); d.pilotGuns.add(pilotGun); d.driveableRecipe.add(new ItemStack(pilotGun.type.item)); }); parsers.put("BombPosition", (split, d) -> { d.primary = EnumWeaponType.BOMB; DriveablePosition pos = new DriveablePosition(new Vector3f( Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F), EnumDriveablePart.core); d.shootPointsPrimary.add(new ShootPoint(pos, new Vector3f(0, 0, 0))); }); parsers.put("BarrelPosition", (split, d) -> { d.primary = EnumWeaponType.SHELL; DriveablePosition pos = new DriveablePosition(new Vector3f( Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F), EnumDriveablePart.turret); d.shootPointsPrimary.add(new ShootPoint(pos, new Vector3f(0, 0, 0))); }); parsers.put("ShootDelay", (split, d) -> d.shootDelaySecondary = Integer.parseInt(split[1])); parsers.put("ShellDelay", (split, d) -> d.shootDelayPrimary = Integer.parseInt(split[1])); parsers.put("BombDelay", parsers.get("ShellDelay")); // Alt name // RECIPE //////////////////////////////////////////////////////////////////////////////// parsers.put("AddRecipeParts", (split, d) -> { EnumDriveablePart part = EnumDriveablePart.getPart(split[1]); ItemStack[] stacks = new ItemStack[(split.length - 2) / 2]; for(int i = 0; i < (split.length - 2) / 2; i++) { int amount = Integer.parseInt(split[2 * i + 2]); boolean damaged = split[2 * i + 3].contains("."); String itemName = damaged ? split[2 * i + 3].split("\\.")[0] : split[2 * i + 3]; int damage = damaged ? Integer.parseInt(split[2 * i + 3].split("\\.")[1]) : 0; stacks[i] = getRecipeElement(itemName, amount, damage); d.driveableRecipe.add(stacks[i]); } d.partwiseRecipe.put(part, stacks); }); parsers.put("AddDye", (split, d) -> { int amount = Integer.parseInt(split[1]); int damage = -1; for(int i = 0; i < EnumDyeColor.values().length; i++) { if(EnumDyeColor.byDyeDamage(i).getTranslationKey().equals(split[2])) damage = i; } if(damage == -1) { FlansMod.log.warn("Failed to find dye colour : " + split[2] + " while adding " + d.shortName); return; } d.driveableRecipe.add(new ItemStack(Items.DYE, amount, damage)); }); // HEALTH & COLLISION ////////////////////////////////////////////////////// parsers.put("SetupPart", (split, d) -> { EnumDriveablePart part = EnumDriveablePart.getPart(split[1]); CollisionBox box = new CollisionBox(Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]), Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8])); d.health.put(part, box); double max = box.Max(); if(max > d.hitboxRadius) d.hitboxRadius = max; }); parsers.put("CollisionPoint", (split, d) -> d.collisionPoints.add(new DriveablePosition(split))); parsers.put("AddCollisionPoint", parsers.get("CollisionPoint")); // Alt name // PASSENGERS ///////////////////////////////////////////////////////////// parsers.put("Driver", (split, d) -> { if(split.length > 4) d.seats[0] = new Seat(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Float.parseFloat(split[4]), Float.parseFloat(split[5]), Float.parseFloat(split[6]), Float.parseFloat(split[7])); else d.seats[0] = new Seat(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3])); }); parsers.put("Pilot", parsers.get("Driver")); // Alt name parsers.put("Passenger", (split, d) -> { Seat seat = new Seat(split); d.seats[seat.id] = seat; if(seat.gunType != null) { seat.gunnerID = d.numPassengerGunners++; d.driveableRecipe.add(new ItemStack(seat.gunType.item)); } }); parsers.put("GunOrigin", (split, d) -> { if(d.seats[Integer.parseInt(split[1])] == null) FlansMod.log.error( "GunOrigin line found in vehicle / mecha / plane file before Passenger line [" + d.shortName + "]"); d.seats[Integer.parseInt(split[1])].gunOrigin = new Vector3f(Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F, Float.parseFloat(split[4]) / 16F); }); parsers.put("RotatedDriverOffset", (split, d) -> d.seats[0].rotatedOffset = new Vector3f(Integer.parseInt(split[1]) / 16F, Integer.parseInt(split[2]) / 16F, Integer.parseInt(split[3]) / 16F)); parsers.put("DriverAimSpeed", (split, d) -> d.seats[0].aimingSpeed = new Vector3f(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3]))); parsers.put("RotatedPassengerOffset", (split, d) -> d.seats[Integer.parseInt(split[1])].rotatedOffset = new Vector3f(Integer.parseInt(split[2]) / 16F, Integer.parseInt(split[3]) / 16F, Integer.parseInt(split[4]) / 16F)); parsers.put("PassengerAimSpeed", (split, d) -> d.seats[Integer.parseInt(split[1])].aimingSpeed = new Vector3f(Float.parseFloat(split[2]), Float.parseFloat(split[3]), Float.parseFloat(split[4]))); parsers.put("DriverLegacyAiming", (split, d) -> d.seats[0].legacyAiming = Boolean.parseBoolean(split[1])); parsers.put("PassengerLegacyAiming", (split, d) -> d.seats[Integer.parseInt(split[1])].legacyAiming = Boolean.parseBoolean(split[2])); parsers.put("DriverYawBeforePitch", (split, d) -> d.seats[0].yawBeforePitch = Boolean.parseBoolean(split[1])); parsers.put("PassengerYawBeforePitch", (split, d) -> d.seats[Integer.parseInt(split[1])].yawBeforePitch = Boolean.parseBoolean(split[2])); parsers.put("DriverLatePitch", (split, d) -> d.seats[0].latePitch = Boolean.parseBoolean(split[1])); parsers.put("PassengerLatePitch", (split, d) -> d.seats[Integer.parseInt(split[1])].latePitch = Boolean.parseBoolean(split[2])); // SOUNDS ///////////////////////////////////////////////////////////////////// parsers.put("DriverTraverseSounds", (split, d) -> d.seats[0].traverseSounds = Boolean.parseBoolean(split[1])); parsers.put("PassengerTraverseSounds", (split, d) -> d.seats[Integer.parseInt(split[1])].traverseSounds = Boolean.parseBoolean(split[2])); parsers.put("StartSoundLength", (split, d) -> d.startSoundLength = Integer.parseInt(split[1])); parsers.put("EngineSoundLength", (split, d) -> d.engineSoundLength = Integer.parseInt(split[1])); parsers.put("YawSoundLength", (split, d) -> d.seats[0].yawSoundLength = Integer.parseInt(split[1])); parsers.put("PitchSoundLength", (split, d) -> d.seats[0].pitchSoundLength = Integer.parseInt(split[1])); parsers.put("PassengerYawSoundLength", (split, d) -> d.seats[Integer.parseInt(split[1])].yawSoundLength = Integer.parseInt(split[2])); parsers.put("PassengerPitchSoundLength", (split, d) -> d.seats[Integer.parseInt(split[1])].pitchSoundLength = Integer.parseInt(split[2])); parsers.put("StartSound", (split, d) -> { d.startSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("EngineSound", (split, d) -> { d.engineSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("YawSound", (split, d) -> { d.seats[0].yawSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("PitchSound", (split, d) -> { d.seats[0].pitchSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("PassengerYawSound", (split, d) -> { d.seats[Integer.parseInt(split[1])].yawSound = split[2]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("PassengerPitchSound", (split, d) -> { d.seats[Integer.parseInt(split[1])].pitchSound = split[2]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ShootMainSound", (split, d) -> { d.shootSoundPrimary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ShootSoundPrimary", parsers.get("ShootMainSound")); // Alt name parsers.put("ShellSound", parsers.get("ShootMainSound")); // Alt name parsers.put("BombSound", parsers.get("ShootMainSound")); // Alt name parsers.put("ShootSecondarySound", (split, d) -> { d.shootSoundSecondary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ShootSoundSecondary", parsers.get("ShootSecondarySound")); // Alt name // ICBM Mod Integration parsers.put("OnRadar", (split, d) -> d.onRadar = split[1].equals("True")); // PARTICLES & GRAPHICS ///////////////////////////////////////////////////////////// parsers.put("AddParticle", (split, d) -> { ParticleEmitter emitter = d.new ParticleEmitter(); emitter.effectType = FlansMod.getParticleType(split[1]); emitter.emitRate = Integer.parseInt(split[2]); emitter.origin = new Vector3f(split[3], d.shortName); emitter.extents = new Vector3f(split[4], d.shortName); emitter.velocity = new Vector3f(split[5], d.shortName); emitter.minThrottle = Float.parseFloat(split[6]); emitter.maxThrottle = Float.parseFloat(split[7]); emitter.minHealth = Float.parseFloat(split[8]); emitter.maxHealth = Float.parseFloat(split[9]); emitter.part = split[10]; //Scale from model coords to world coords emitter.origin.scale(1.0f / 16.0f); emitter.extents.scale(1.0f / 16.0f); emitter.velocity.scale(1.0f / 16.0f); d.emitters.add(emitter); }); parsers.put("Model", (split, d) -> { if(FMLCommonHandler.instance().getSide().isClient()) d.model = FlansMod.proxy.loadModel(split[1], d.shortName, ModelDriveable.class); }); // FM+ TODO parsers.put("IsExplosionWhenDestroyed", (split, d) -> d.isExplosionWhenDestroyed = Boolean.parseBoolean(split[1])); parsers.put("VehicleGunModelScale", (split, d) -> d.vehicleGunModelScale = Float.parseFloat(split[1])); parsers.put("VehicleGunReloadTick", (split, d) -> d.reloadSoundTick = Integer.parseInt(split[1])); parsers.put("FallDamageFactor", (split, d) -> d.fallDamageFactor = Float.parseFloat(split[1])); parsers.put("ClutchBrake", (split, d) -> d.ClutchBrake = Float.parseFloat(split[1])); parsers.put("MaxThrottleInWater", (split, d) -> d.maxThrottleInWater = Float.parseFloat(split[1])); parsers.put("TurretOriginOffset", (split, d) -> d.turretOriginOffset = new Vector3f( Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F)); parsers.put("CollisionDamageEnable", (split, d) -> d.collisionDamageEnable = Boolean.parseBoolean(split[1])); parsers.put("CollisionDamageThrottle", (split, d) -> d.collisionDamageThrottle = Float.parseFloat(split[1])); parsers.put("CollisionDamageTimes", (split, d) -> d.collisionDamageTimes = Float.parseFloat(split[1])); parsers.put("CanLockAngle", (split, d) -> d.canLockOnAngle = Integer.parseInt(split[1])); parsers.put("LockOnSoundTime", (split, d) -> d.lockOnSoundTime = Integer.parseInt(split[1])); parsers.put("LockOnToDriveables", (split, d) -> d.lockOnToPlanes = d.lockOnToVehicles = d.lockOnToMechas = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockOnToVehicles", (split, d) -> d.lockOnToVehicles = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockOnToPlanes", (split, d) -> d.lockOnToPlanes = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockOnToMechas", (split, d) -> d.lockOnToMechas = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockOnToPlayers", (split, d) -> d.lockOnToPlayers = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockOnToLivings", (split, d) -> d.lockOnToLivings = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("LockedOnSoundRange", (split, d) -> d.lockedOnSoundRange = Integer.parseInt(split[1])); parsers.put("HasFlare", (split, d) -> d.hasFlare = Boolean.parseBoolean(split[1])); parsers.put("FlareDelay", (split, d) -> { d.flareDelay = Integer.parseInt(split[1]); if(d.flareDelay <= 0) d.flareDelay = 1; }); parsers.put("TimeFlareUsing", (split, d) -> { d.timeFlareUsing = Integer.parseInt(split[1]); if(d.timeFlareUsing <= 0) d.timeFlareUsing = 1; }); parsers.put("PlaceableOnSponge", (split, d) -> d.placeableOnSponge = Boolean.parseBoolean(split[1])); parsers.put("FloatOffset", (split, d) -> d.floatOffset = Float.parseFloat(split[1])); parsers.put("CanMountEntity", (split, d) -> d.canMountEntity = Boolean.parseBoolean(split[1])); parsers.put("CollectHarvest", (split, d) -> d.collectHarvest = Boolean.parseBoolean(split[1])); parsers.put("DropHarvest", (split, d) -> d.dropHarvest = Boolean.parseBoolean(split[1])); parsers.put("HarvestBox", (split, d) -> { d.harvestBoxSize = new Vector3f(split[1], d.shortName); d.harvestBoxPos = new Vector3f(split[2], d.shortName); }); parsers.put("PlaceTimePrimary", (split, d) -> d.placeTimePrimary = Integer.parseInt(split[1])); parsers.put("PlaceTimeSecondary", (split, d) -> d.placeTimeSecondary = Integer.parseInt(split[1])); parsers.put("ReloadTimePrimary", (split, d) -> d.reloadTimePrimary = Integer.parseInt(split[1])); parsers.put("ReloadTimeSecondary", (split, d) -> d.reloadTimeSecondary = Integer.parseInt(split[1])); parsers.put("BulletSpeed", (split, d) -> d.bulletSpeed = Float.parseFloat(split[1])); parsers.put("BulletSpread", (split, d) -> d.bulletSpread = Float.parseFloat(split[1])); parsers.put("RangingGun", (split, d) -> d.rangingGun = Boolean.parseBoolean(split[1])); parsers.put("GunLength", (split, d) -> d.gunLength = Float.parseFloat(split[1])); parsers.put("RecoilDistance", (split, d) -> d.recoilDist = Float.parseFloat(split[1])); parsers.put("RecoilTime", (split, d) -> d.recoilTime = Float.parseFloat(split[1])); parsers.put("EnableReloadTime", (split, d) -> d.enableReloadTime = Boolean.parseBoolean(split[1])); parsers.put("ShootParticlesPrimary", (split, d) -> d.shootParticlesPrimary.add(new ShootParticle( split[1], Float.valueOf(split[2]), Float.valueOf(split[3]), Float.valueOf(split[4])))); parsers.put("ShootParticlesSecondary", (split, d) -> d.shootParticlesSecondary.add(new ShootParticle( split[1], Float.valueOf(split[2]), Float.valueOf(split[3]), Float.valueOf(split[4])))); parsers.put("SetPlayerInvisible", (split, d) -> d.setPlayerInvisible = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("IT1", (split, d) -> d.IT1 = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("FixedPrimary", (split, d) -> d.fixedPrimaryFire = Boolean.parseBoolean(split[1].toLowerCase())); parsers.put("PrimaryAngle", (split, d) -> d.primaryFireAngle = new Vector3f(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3]))); parsers.put("PlaceSoundPrimary", (split, d) -> { d.placeSoundPrimary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("PlaceSoundSecondary", (split, d) -> { d.placeSoundSecondary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ReloadSoundPrimary", (split, d) -> { d.reloadSoundPrimary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ReloadSoundSecondary", (split, d) -> { d.reloadSoundSecondary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("LockedOnSound", (split, d) -> { d.lockedOnSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("LockingOnSound", (split, d) -> { d.lockingOnSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "guns", split[1]); }); parsers.put("FlareSound", (split, d) -> { d.flareSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("FancyCollision", (split, d) -> d.fancyCollision = Boolean.parseBoolean(split[1])); parsers.put("AddCollisionMesh", (split, d) -> { CollisionShapeBox box = new CollisionShapeBox(new Vector3f(split[1], d.shortName), new Vector3f(split[2], d.shortName), new Vector3f(split[3], d.shortName), new Vector3f(split[4], d.shortName), new Vector3f(split[5], d.shortName), new Vector3f(split[6], d.shortName), new Vector3f(split[7], d.shortName), new Vector3f(split[8], d.shortName), new Vector3f(split[9], d.shortName), new Vector3f(split[10], d.shortName), "core"); d.collisionBox.add(box); }); parsers.put("AddCollisionMeshRaw", (split, d) -> { Vector3f pos = new Vector3f(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3])); Vector3f size = new Vector3f(Float.parseFloat(split[4]), Float.parseFloat(split[5]), Float.parseFloat(split[6])); Vector3f p1 = new Vector3f(Float.parseFloat(split[8]), Float.parseFloat(split[9]), Float.parseFloat(split[10])); Vector3f p2 = new Vector3f(Float.parseFloat(split[11]), Float.parseFloat(split[12]), Float.parseFloat(split[13])); Vector3f p3 = new Vector3f(Float.parseFloat(split[14]), Float.parseFloat(split[15]), Float.parseFloat(split[16])); Vector3f p4 = new Vector3f(Float.parseFloat(split[17]), Float.parseFloat(split[18]), Float.parseFloat(split[19])); Vector3f p5 = new Vector3f(Float.parseFloat(split[20]), Float.parseFloat(split[21]), Float.parseFloat(split[22])); Vector3f p6 = new Vector3f(Float.parseFloat(split[23]), Float.parseFloat(split[24]), Float.parseFloat(split[25])); Vector3f p7 = new Vector3f(Float.parseFloat(split[26]), Float.parseFloat(split[27]), Float.parseFloat(split[28])); Vector3f p8 = new Vector3f(Float.parseFloat(split[29]), Float.parseFloat(split[30]), Float.parseFloat(split[31])); CollisionShapeBox box = new CollisionShapeBox(pos, size, p1, p2, p3, p4, p5, p6, p7, p8, "core"); d.collisionBox.add(box); }); parsers.put("AddTurretCollisionMesh", (split, d) -> { CollisionShapeBox box = new CollisionShapeBox(new Vector3f(split[1], d.shortName), new Vector3f(split[2], d.shortName), new Vector3f(split[3], d.shortName), new Vector3f(split[4], d.shortName), new Vector3f(split[5], d.shortName), new Vector3f(split[6], d.shortName), new Vector3f(split[7], d.shortName), new Vector3f(split[8], d.shortName), new Vector3f(split[9], d.shortName), new Vector3f(split[10], d.shortName), "core"); d.collisionBox.add(box); }); parsers.put("AddTurretCollisionMeshRaw", (split, d) -> { Vector3f pos = new Vector3f(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3])); Vector3f size = new Vector3f(Float.parseFloat(split[4]), Float.parseFloat(split[5]), Float.parseFloat(split[6])); Vector3f p1 = new Vector3f(Float.parseFloat(split[8]), Float.parseFloat(split[9]), Float.parseFloat(split[10])); Vector3f p2 = new Vector3f(Float.parseFloat(split[11]), Float.parseFloat(split[12]), Float.parseFloat(split[13])); Vector3f p3 = new Vector3f(Float.parseFloat(split[14]), Float.parseFloat(split[15]), Float.parseFloat(split[16])); Vector3f p4 = new Vector3f(Float.parseFloat(split[17]), Float.parseFloat(split[18]), Float.parseFloat(split[19])); Vector3f p5 = new Vector3f(Float.parseFloat(split[20]), Float.parseFloat(split[21]), Float.parseFloat(split[22])); Vector3f p6 = new Vector3f(Float.parseFloat(split[23]), Float.parseFloat(split[24]), Float.parseFloat(split[25])); Vector3f p7 = new Vector3f(Float.parseFloat(split[26]), Float.parseFloat(split[27]), Float.parseFloat(split[28])); Vector3f p8 = new Vector3f(Float.parseFloat(split[29]), Float.parseFloat(split[30]), Float.parseFloat(split[31])); CollisionShapeBox box = new CollisionShapeBox(pos, size, p1, p2, p3, p4, p5, p6, p7, p8, "turret"); d.collisionBox.add(box); }); parsers.put("LeftLinkPoint", (split, d) -> d.leftTrackPoints.add(new Vector3f(split[1], d.shortName))); parsers.put("RightLinkPoint", (split, d) -> d.rightTrackPoints.add(new Vector3f(split[1], d.shortName))); parsers.put("TrackLinkLength", (split, d) -> d.trackLinkLength = Float.parseFloat(split[1])); parsers.put("RadarDetectableAltitude", (split, d) -> d.radarDetectableAltitude = Integer.parseInt(split[1])); parsers.put("Stealth", (split, d) -> d.stealth = split[1].equals("True")); } public DriveableType(TypeFile file) { super(file); } @Override public void preRead(TypeFile file) { super.preRead(file); //Make sure the passenger arrays are set up first for(String line : file.getLines()) { if(line == null) break; if(line.startsWith("//")) continue; String[] split = line.split(" "); if(split.length < 2) continue; if(split[0].equals("Passengers")) { numPassengers = Integer.parseInt(split[1]); seats = new Seat[numPassengers + 1]; break; } } //Make sure NumWheels is read before anything else for(String line : file.getLines()) { if(line == null) break; if(line.startsWith("//")) continue; String[] split = line.split(" "); if(split.length < 2) continue; if(split[0].equals("NumWheels")) { wheelPositions = new DriveablePosition[Integer.parseInt(split[1])]; break; } } types.add(this); } @Override public void postRead(TypeFile file) { super.postRead(file); } @Override protected void read(String[] split, TypeFile file) { try { // Special case for anything that reads multiple lines if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) model = FlansMod.proxy.loadModel(split[1], shortName, ModelDriveable.class); else { ParseFunc parser = parsers.get(split[0]); if(parser != null) { parser.Parse(split, this); } else { super.read(split, file); } } } catch(Exception e) { FlansMod.log.error("Errored reading " + file.name); FlansMod.log.throwing(e); } } public abstract EntityDriveable createDriveable(World world, double x, double y, double z, DriveableData data); private DriveablePosition getShootPoint(String[] split) { //Its a gun with a type if(split.length == 6) { return new PilotGun(split); } else if(split.length == 5) { return new DriveablePosition(split); } return new DriveablePosition(new Vector3f(), EnumDriveablePart.core); } public List shootPoints(boolean s) { return s ? shootPointsSecondary : shootPointsPrimary; } public boolean alternate(boolean s) { return s ? alternateSecondary : alternatePrimary; } public EnumWeaponType weaponType(boolean s) { return s ? secondary : primary; } public int shootDelay(boolean s) { return s ? shootDelaySecondary : shootDelayPrimary; } public String shootSound(boolean s) { return s ? shootSoundSecondary : shootSoundPrimary; } public int numEngines() { return 1; } public int ammoSlots() { return numPassengerGunners + pilotGuns.size(); } public boolean isValidAmmo(BulletType bulletType, EnumWeaponType weaponType) { return (acceptAllAmmo || ammo.contains(bulletType)) && bulletType.weaponType == weaponType; } /** * Find the items needed to rebuild a part. The returned array is disconnected from the template items it has looked * up */ public ArrayList getItemsRequired(DriveablePart part, PartType engine) { ArrayList stacks = new ArrayList<>(); //Start with the items required to build this part if(partwiseRecipe.get(part.type) != null) { for(ItemStack stack : partwiseRecipe.get(part.type)) { stacks.add(stack.copy()); } } //Add the items required for the guns connected to this part for(PilotGun gun : pilotGuns) { if(gun.part == part.type) { stacks.add(new ItemStack(gun.type.item)); } } for(Seat seat : seats) { if(seat != null && seat.part == part.type && seat.gunType != null) { stacks.add(new ItemStack(seat.gunType.item)); } } return stacks; } public static DriveableType getDriveable(String find) { for(DriveableType type : types) { if(type.shortName.equals(find)) return type; } return null; } @Override public void addLoot(LootTableLoadEvent event) { //Do not add vehicles to dungeon chests. That would be so op. } public class ParticleEmitter { /** * The name of the effect */ public EnumParticleTypes effectType; /** * The rate of emission */ public int emitRate; /** * The centre of the effect emitter */ public Vector3f origin; /** * The size of the box in which it emits */ public Vector3f extents; /** * The velocity of the particle */ public Vector3f velocity; /** * Lower throttle bound */ public float minThrottle; /** * Upper throttle bound */ public float maxThrottle; /** * Model part the emitter is bound to */ public String part; /** * Minimum health for the emitter to work */ public float minHealth; /** * Maximum health for the emitter to work */ public float maxHealth; } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } @Override public float GetRecommendedScale() { return 100.0f / cameraDistance; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntityDamageSourceCollision.java ================================================ package com.flansmod.common.driveables; import net.minecraft.util.EntityDamageSource; public class EntityDamageSourceCollision extends EntityDamageSource { public EntityDriveable source; public EntityDamageSourceCollision(EntityDriveable driveable) { super(driveable.getDriveableType().shortName, driveable); source = driveable; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntityDriveable.java ================================================ package com.flansmod.common.driveables; import java.util.ArrayList; import java.util.List; import io.netty.buffer.ByteBuf; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.NonNullList; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameType; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.api.IExplodeable; import com.flansmod.client.EntityCamera; import com.flansmod.client.FlansModClient; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.client.handlers.KeyInputHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.DriveableType.ParticleEmitter; import com.flansmod.common.driveables.mechas.ContainerMechaInventory; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.EnumSpreadPattern; import com.flansmod.common.guns.FireableGun; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.InventoryHelper; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootBulletHandler; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.guns.raytracing.FlansModRaytracer.BulletHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.DriveableHit; import com.flansmod.common.network.PacketDriveableDamage; import com.flansmod.common.network.PacketDriveableKey; import com.flansmod.common.network.PacketDriveableKeyHeld; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.parts.EnumPartCategory; import com.flansmod.common.parts.ItemPart; import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.vector.Vector3f; import static com.flansmod.common.util.BlockUtil.destroyBlock; public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData { public boolean syncFromServer = true; /** Ticks since last server update. Use to smoothly transition to new position */ public int serverPositionTransitionTicker; /** Server side position, as synced by PacketVehicleControl packets */ public double serverPosX, serverPosY, serverPosZ; /** Server side rotation, as synced by PacketVehicleControl packets */ public double serverYaw, serverPitch, serverRoll; /** The driveable data which contains the inventory, the engine and the fuel */ public DriveableData driveableData; /** The shortName of the driveable type, used to obtain said type */ public String driveableType; /** * The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to * obtain the thrust */ public float throttle; /** The wheels on this plane */ public EntityWheel[] wheels; public boolean fuelling; /** Extra prevRotation field for smoothness in all 3 rotational axes */ public float prevRotationRoll; /** Angular velocity */ public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); /** Whether each mouse button is held */ public boolean primaryShootHeld = false, secondaryShootHeld = false; /** Shoot delay variables */ public float shootDelayPrimary, shootDelaySecondary; /** Minigun speed variables */ public float minigunSpeedPrimary, minigunSpeedSecondary; /** Current gun variables for alternating weapons */ public int currentPrimaryGunShootPointIndex, currentSecondaryGunShootPointIndex; /** Whether each mouse button is held */ public boolean leftMouseHeld = false, rightMouseHeld = false; /** Angle of harvester aesthetic piece */ public float harvesterAngle; public RotatedAxes prevAxes; public RotatedAxes axes; private EntitySeat[] seats; /** Until this is true, just look for seat and wheel connections */ protected boolean readyForUpdates = false; private float yOffset; public EntityLivingBase camera; private int[] emitterTimers; public int animCount = 0; public int animFrame = 0; // Gun recoil public boolean isRecoil = false; public float recoilPos = 0; public float lastRecoilPos = 0; public int recoilTimer = 0; /** Can't break the block with hardness greater than this value * when collided */ public float collisionForce = 30F; /** Damage factor of unbreakable block such as bedrock when collided */ public float unbreakableBlockDamage = 100F; public EntityDriveable(World world) { super(world); axes = new RotatedAxes(); prevAxes = new RotatedAxes(); preventEntitySpawning = true; setSize(1F, 1F); yOffset = 6F / 16F; ignoreFrustumCheck = true; } public EntityDriveable(World world, DriveableType t, DriveableData d) { this(world); driveableType = t.shortName; driveableData = d; } protected void initType(DriveableType type, boolean firstSpawn, boolean clientSide) { seats = new EntitySeat[type.numPassengers + 1]; wheels = new EntityWheel[type.wheelPositions.length]; if(!clientSide && firstSpawn) { for(int i = 0; i < type.numPassengers + 1; i++) { seats[i] = new EntitySeat(world, this, i); world.spawnEntity(seats[i]); seats[i].startRiding(this); } for(int i = 0; i < wheels.length; i++) { wheels[i] = new EntityWheel(world, this, i); world.spawnEntity(wheels[i]); wheels[i].startRiding(this); } } stepHeight = type.wheelStepHeight; yOffset = type.yOffset; emitterTimers = new int[type.emitters.size()]; for(int i = 0; i < type.emitters.size(); i++) { emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate); } } @SideOnly(Side.CLIENT) @Override public boolean isInRangeToRender3d(double x, double y, double z) { double dX = this.posX - x; double dY = this.posY - y; double dZ = this.posZ - z; double distSq = dX * dX + dY * dY + dZ * dZ; double maxDist = 200.0D * getRenderDistanceWeight(); return distSq < maxDist * maxDist; } @Override protected void writeEntityToNBT(NBTTagCompound tag) { driveableData.writeToNBT(tag); tag.setString("Type", driveableType); tag.setFloat("RotationYaw", axes.getYaw()); tag.setFloat("RotationPitch", axes.getPitch()); tag.setFloat("RotationRoll", axes.getRoll()); } @Override protected void readEntityFromNBT(NBTTagCompound tag) { driveableType = tag.getString("Type"); driveableData = new DriveableData(tag); initType(DriveableType.getDriveable(driveableType), false, false); prevRotationYaw = tag.getFloat("RotationYaw"); prevRotationPitch = tag.getFloat("RotationPitch"); prevRotationRoll = tag.getFloat("RotationRoll"); axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll); } @Override public void writeSpawnData(ByteBuf data) { ByteBufUtils.writeUTF8String(data, driveableType); NBTTagCompound tag = new NBTTagCompound(); driveableData.writeToNBT(tag); ByteBufUtils.writeTag(data, tag); data.writeFloat(axes.getYaw()); data.writeFloat(axes.getPitch()); data.writeFloat(axes.getRoll()); // Write damage for(EnumDriveablePart ep : EnumDriveablePart.values()) { DriveablePart part = getDriveableData().parts.get(ep); data.writeInt(part.health); data.writeBoolean(part.onFire); } } @Override public void readSpawnData(ByteBuf data) { try { driveableType = ByteBufUtils.readUTF8String(data); driveableData = new DriveableData(ByteBufUtils.readTag(data)); initType(getDriveableType(), false, true); axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat()); prevRotationYaw = axes.getYaw(); prevRotationPitch = axes.getPitch(); prevRotationRoll = axes.getRoll(); // Read damage for(EnumDriveablePart ep : EnumDriveablePart.values()) { DriveablePart part = getDriveableData().parts.get(ep); part.health = data.readInt(); part.onFire = data.readBoolean(); } } catch(Exception e) { FlansMod.log.error("Failed to retrieve plane type from server."); super.setDead(); FlansMod.log.throwing(e); } camera = new EntityCamera(world, this); world.spawnEntity(camera); } /** * Called with the movement of the mouse. Used in controlling vehicles if need be. * * @param deltaY * @param deltaX * @return if mouse movement was handled. */ @Override public abstract void onMouseMoved(int deltaX, int deltaY); @Override @SideOnly(Side.CLIENT) public EntityLivingBase getCamera() { return camera; } protected boolean canSit(int seat) { return getDriveableType().numPassengers >= seat && seats[seat].getControllingPassenger() == null; } @Override protected boolean canTriggerWalking() { return false; } @Override protected void entityInit() { } @Override public AxisAlignedBB getCollisionBox(Entity entity) { return null; } @Override public boolean canBePushed() { return false; } @Override public double getMountedYOffset() { return -0.3D; } @Override public double getYOffset() { return yOffset; } /** * Pass generic damage to the core */ @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { return world.isRemote || isDead || attackPart(EnumDriveablePart.core, damagesource, i); } @Override public void setDead() { super.setDead(); if(world.isRemote) camera.setDead(); for(EntitySeat seat : seats) { if(seat != null) seat.reallySetDead(); } for(EntityWheel wheel : wheels) { if(wheel != null) wheel.reallySetDead(); } } @SideOnly(Side.CLIENT) private void reportVehicleError() { FlansMod.log.warn("Vehicle error in " + this); FlansModClient.numVehicleExceptions++; } @Override public boolean canBeCollidedWith() { return !isDead; } @Override public void applyEntityCollision(Entity entity) { if(!isPartOfThis(entity)) super.applyEntityCollision(entity); } @Override public void setPositionAndRotationDirect(double d, double d1, double d2, float f, float f1, int i, boolean b) { if(ticksExisted > 1) return; if(!(getControllingPassenger() instanceof EntityPlayer) || !FlansMod.proxy.isThePlayer( (EntityPlayer)getControllingPassenger())) { if(syncFromServer) { serverPositionTransitionTicker = i + 5; } else { double var10 = d - posX; double var12 = d1 - posY; double var14 = d2 - posZ; double var16 = var10 * var10 + var12 * var12 + var14 * var14; if(var16 <= 1.0D) { return; } serverPositionTransitionTicker = 3; } serverPosX = d; serverPosY = d1; serverPosZ = d2; serverYaw = f; serverPitch = f1; } } public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throttle, float steeringYaw) { if(world.isRemote) { serverPosX = x; serverPosY = y; serverPosZ = z; serverYaw = yaw; serverPitch = pitch; serverRoll = roll; serverPositionTransitionTicker = 5; } else { setPosition(x, y, z); prevRotationYaw = yaw; prevRotationPitch = pitch; prevRotationRoll = roll; setRotation(yaw, pitch, roll); } // Set the motions regardless of side. motionX = motX; motionY = motY; motionZ = motZ; angularVelocity = new Vector3f(velYaw, velPitch, velRoll); this.throttle = throttle; } @Override public void setVelocity(double d, double d1, double d2) { motionX = d; motionY = d1; motionZ = d2; } @Override public boolean serverHandleKeyPress(int key, EntityPlayer player) { switch(key) { case 6: if(getSeat(0).getControllingPassenger() != null) getSeat(0).removePassengers(); return true; case 8: if(getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) // Secondary { shoot(true); return true; } case 9: if(getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) // Primary { shoot(false); return true; } } return false; } @Override @SideOnly(Side.CLIENT) public boolean pressKey(int key, EntityPlayer player, boolean isOnEvent) { switch(key) { case 6: //Exit { Minecraft mc = Minecraft.getMinecraft(); mc.setRenderViewEntity(mc.player); FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); return true; } case 8: //Drop bomb { if(isOnEvent) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); } else if(!secondaryShootHeld) { updateKeyHeldState(8, true); } return true; } case 9: //Shoot bullet { if(isOnEvent) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); } else if(!primaryShootHeld) { updateKeyHeldState(9, true); } return true; } case 18: { togglePerspective(); return true; } default: { return false; } } } @Override public void updateKeyHeldState(int key, boolean held) { if(world.isRemote) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); } switch(key) { case 9: primaryShootHeld = held; break; case 8: secondaryShootHeld = held; break; } } /** * Shoot method called by pressing / holding shoot buttons */ public void shoot(boolean secondary) { DriveableType type = getDriveableType(); List shootPoints = type.shootPoints(secondary); EnumWeaponType weaponType = type.weaponType(secondary); boolean driverIsLivingEntity = seats[0] != null && seats[0].getControllingPassenger() instanceof EntityLivingBase; boolean gunHasDelayRemaining = getShootDelay(secondary) > 0; boolean gunHasShootPoints = !shootPoints.isEmpty(); if(driverIsLivingEntity && !gunHasDelayRemaining && gunHasShootPoints) { // For alternating guns, move on to the next one if(type.alternate(secondary)) { int nextShootPointIndex = (getCurrentShootPointIndex(secondary) + 1) % shootPoints.size(); setCurrentShootPointIndex(nextShootPointIndex, secondary); shootFromPoint(type, shootPoints.get(nextShootPointIndex), nextShootPointIndex, secondary, weaponType); } else { for(int i = 0; i < shootPoints.size(); i++) { shootFromPoint(type, shootPoints.get(i), i, secondary, weaponType); } } } } public boolean driverIsCreative() { EntityPlayer driver = getDriver(); return driver != null && driver.isCreative(); } public EntityPlayer getDriver() { if(seats != null && seats[0] != null && seats[0].getControllingPassenger() instanceof EntityPlayer) { return ((EntityPlayer)seats[0].getControllingPassenger()); } else { return null; } } private void shootFromPoint( DriveableType type, ShootPoint shootPoint, int shootPointIndex, boolean secondary, EnumWeaponType weaponType) { Vector3f gunVec = getOrigin(shootPoint); Vector3f lookVector = getLookVector(shootPoint); switch(weaponType) { case BOMB: dropBomb(type, secondary, weaponType, gunVec, lookVector); break; case MISSILE: case SHELL: fireShell(type, secondary, weaponType, gunVec, lookVector); break; case GUN: fireGun(type, shootPoint, shootPointIndex, secondary, gunVec, lookVector); break; case MINE: case NONE: default: break; } setShootDelay(type.shootDelay(secondary), secondary); } private void fireGun(DriveableType type, ShootPoint shootPoint, int shootPointIndex, boolean secondary, Vector3f gunVec, Vector3f lookVector) { if(shootPoint.rootPos instanceof PilotGun) { PilotGun pilotGun = (PilotGun)shootPoint.rootPos; GunType gunType = pilotGun.type; ItemStack ammoItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + shootPointIndex]; Item ammoItem = ammoItemStack.getItem(); boolean isAmmo = ammoItem instanceof ItemShootable; boolean isValidAmmoForGun = isAmmo && gunType.isCorrectAmmo(((ItemShootable) ammoItem).type); //TODO grenades wont work (currently no vehicle with this feature exists) if(isValidAmmoForGun && ((ItemShootable) ammoItem).type instanceof BulletType) { ShootableType ammoType = ((ItemShootable) ammoItem).type; BulletType bulletType = (BulletType) ammoType; FireableGun fireableGun = new FireableGun( gunType, gunType.damage, gunType.bulletSpread, gunType.bulletSpeed, gunType.spreadPattern); FiredShot shot = new FiredShot(fireableGun, bulletType, this, (EntityPlayerMP)getDriver()); ShootBulletHandler handler = isExtraBullet -> { ammoItemStack.damageItem(1, getDriver()); if(ammoItemStack.isEmpty()) { driveableData.ammo[getDriveableType().numPassengerGunners + shootPointIndex] = ItemStack.EMPTY .copy(); } }; Vector3f gunVector = Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null); ShotHandler.fireGun(world, shot, gunType.numBullets * bulletType.numBullets, gunVector, lookVector, handler); if(type.shootSound(secondary) != null) { PacketPlaySound.sendSoundPacket(gunVector.x, gunVector.y, gunVector.z, FlansMod.soundRange, world.provider.getDimension(), type.shootSound(secondary), false); } } } } private void fireShell(DriveableType type, boolean secondary, EnumWeaponType weaponType, Vector3f gunVec, Vector3f lookVector) { if(TeamsManager.shellsEnabled) { for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { ItemStack shell = driveableData.getStackInSlot(i); if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo( ((ItemBullet)shell.getItem()).type, weaponType)) { shootProjectile(i, gunVec, lookVector, type, secondary, (float)getSpeed() + 3f); break; } } } } private void dropBomb(DriveableType type, boolean secondary, EnumWeaponType weaponType, Vector3f gunVec, Vector3f lookVector) { if(TeamsManager.bombsEnabled) { for(int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) { ItemStack bomb = driveableData.getStackInSlot(i); if(bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo( ((ItemBullet)bomb.getItem()).type, weaponType)) { shootProjectile(i, gunVec, lookVector, type, secondary, (float)getSpeed()); break; } } } } public double getSpeed() { return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); } public Vector3f getOrigin(ShootPoint shootPoint) { DriveablePosition driveablePosition = shootPoint.rootPos; // Rotate the gun vector to global axes Vector3f localGunVec = new Vector3f(driveablePosition.position); if(driveablePosition.part == EnumDriveablePart.turret) { // Untranslate by the turret origin, to get the rotation about the right point Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); // Rotate by the turret angles localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); // Translate by the turret origin Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); } return rotate(localGunVec); } public Vector3f getLookVector(ShootPoint shootPoint) { return axes.getXAxis(); } private void shootProjectile(final Integer slot, Vector3f gunVec, Vector3f lookVector, DriveableType type, Boolean secondary, float speed) { ItemStack bullet = driveableData.getStackInSlot(slot); ItemBullet bulletItem = (ItemBullet)bullet.getItem(); int damageMultiplier = secondary ? type.damageModifierSecondary : type.damageModifierPrimary; FireableGun fireableGun = new FireableGun(bulletItem.type, bulletItem.type.damageVsLiving * damageMultiplier, bulletItem.type.damageVsDriveable * damageMultiplier, bulletItem.type.bulletSpread, speed, EnumSpreadPattern.circle); FiredShot shot = new FiredShot(fireableGun, bulletItem.type, this, (EntityPlayerMP)getDriver()); ShootBulletHandler handler = isExtraBullet -> { if(!driverIsCreative()) { ItemStack bulletStack = driveableData.getStackInSlot(slot); bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); if(bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { bulletStack.setItemDamage(0); bulletStack.setCount(bulletStack.getCount() - 1); if(bulletStack.getCount() == 0) bulletStack = ItemStack.EMPTY.copy(); } driveableData.setInventorySlotContents(slot, bulletStack); } }; Vector3f gunVector = Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null); ShotHandler.fireGun(world, shot, bulletItem.type.numBullets, gunVector, lookVector, handler); if(type.shootSound(secondary) != null) { //TODO proper general sound implementation PacketPlaySound.sendSoundPacket(gunVector.x, gunVector.y, gunVector.z, FlansMod.soundRange, world.provider.getDimension(), type.shootSound(secondary), false); } // Reset the shoot delay setShootDelay(type.shootDelay(secondary), secondary); } @Override public void onUpdate() { super.onUpdate(); prevRotationYaw = axes.getYaw(); prevRotationPitch = axes.getPitch(); prevRotationRoll = axes.getRoll(); DriveableType type = getDriveableType(); // Do a full check of our passengers for wheels or seats for(Entity passenger : getPassengers()) { if(passenger instanceof EntitySeat) { EntitySeat seat = (EntitySeat)passenger; if(seat.getExpectedSeatID() >= 0 && seats[seat.getExpectedSeatID()] != seat) { if(seats[seat.getExpectedSeatID()] != null) { FlansMod.log.error("Driveable already had a seat in place"); seats[seat.getExpectedSeatID()].setDead(); } seats[seat.getExpectedSeatID()] = seat; } } else if(passenger instanceof EntityWheel) { EntityWheel wheel = (EntityWheel)passenger; if(wheel.getExpectedWheelID() >= 0 && wheels[wheel.getExpectedWheelID()] != wheel) { if(wheels[wheel.getExpectedWheelID()] != null) { FlansMod.log.error("Driveable already had a wheel in place"); wheels[wheel.getExpectedWheelID()].setDead(); } wheels[wheel.getExpectedWheelID()] = wheel; } } else { FlansMod.log.warn("Entity " + passenger + " is riding a driveable core entity."); } } readyForUpdates = true; for(int i = 0; i < type.numPassengers; i++) { if(seats[i] == null) { readyForUpdates = false; } } for(int i = 0; i < type.wheelPositions.length; i++) { if(wheels[i] == null) { readyForUpdates = false; } } if(!readyForUpdates) { if(!world.isRemote) { // Well heck, if it's bork, let's make new ones initType(type, true, false); } // If we end up stuck like this on a client, handle updates from server if(world.isRemote) { // The driveable is currently moving towards its server position. Continue doing so. if(serverPositionTransitionTicker > 0) { moveTowardServerPosition(); } // If the driveable is at its server position and does not have the next update, it should just simulate // itself as a server side driveable would, so continue } return; } // Reset weapon key held states if necessary if(world.isRemote) { if(primaryShootHeld && !KeyInputHandler.primaryVehicleInteract.isKeyDown()) { primaryShootHeld = false; updateKeyHeldState(9, false); } if(secondaryShootHeld && !KeyInputHandler.secondaryVehicleInteract.isKeyDown()) { secondaryShootHeld = false; updateKeyHeldState(8, false); } } // Harvest stuff // Aesthetics if(hasEnoughFuel()) { harvesterAngle += throttle / 5F; } // Actual harvesting if(type.harvestBlocks && type.health.get(EnumDriveablePart.harvester) != null) { CollisionBox box = type.health.get(EnumDriveablePart.harvester); for(float x = box.x; x <= box.x + box.w; x++) { for(float y = box.y; y <= box.y + box.h; y++) { for(float z = box.z; z <= box.z + box.d; z++) { Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); int blockX = (int)Math.round(posX + v.x); int blockY = (int)Math.round(posY + v.y); int blockZ = (int)Math.round(posZ + v.z); IBlockState block = world.getBlockState(new BlockPos(blockX, blockY, blockZ)); boolean cancelled = false; if(getDriver() != null) { int eventOutcome = ForgeHooks.onBlockBreakEvent(world, driverIsCreative() ? GameType.CREATIVE : getDriver().capabilities.allowEdit ? GameType.SURVIVAL : GameType.ADVENTURE, (EntityPlayerMP)getDriver(), new BlockPos(blockX, blockY, blockZ)); cancelled = eventOutcome == -1; } if(!cancelled) { if(type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(world, new BlockPos(blockX, blockY, blockZ)) >= 0F) { // Add the item stack to mecha inventory NonNullList stacks = NonNullList.create(); block.getBlock().getDrops(stacks, world, new BlockPos(blockX, blockY, blockZ), world.getBlockState(new BlockPos(blockX, blockY, blockZ)), 0); for(ItemStack stack : stacks) { if(!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !world.isRemote && world.getGameRules().getBoolean( "doTileDrops")) { world.spawnEntity( new EntityItem(world, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); } } // Destroy block if(!world.isRemote) { WorldServer worldServer = (WorldServer)world; BlockPos pos = new BlockPos(blockX, blockY, blockZ); destroyBlock(worldServer, pos, getDriver(), false); } } } } } } } //Gun recoil if(leftMouseHeld) { tryRecoil(); setRecoilTimer(); } lastRecoilPos = recoilPos; if(recoilPos > 180 - (180 / type.recoilTime)) { recoilPos = 0; isRecoil = false; } if(isRecoil) recoilPos = recoilPos + (180 / type.recoilTime); if(recoilTimer >= 0) recoilTimer--; for(DriveablePart part : getDriveableData().parts.values()) { if(part.box != null) { part.update(this); // Client side particles if(world.isRemote) { if(part.onFire) { // Pick a random position within the bounding box and spawn a flame there Vector3f pos = getRandPosInBoundingBox(part); world.spawnParticle(EnumParticleTypes.FLAME, posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); } if(part.health > 0 && part.health < part.maxHealth / 2) { Vector3f pos = getRandPosInBoundingBox(part); world.spawnParticle( part.health < part.maxHealth / 4 ? EnumParticleTypes.SMOKE_LARGE : EnumParticleTypes.SMOKE_NORMAL, posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); } } // Server side fire handling if(part.onFire) { // Rain can put out fire if(world.isRaining() && rand.nextInt(40) == 0) part.onFire = false; // Also water blocks // Get the centre point of the part Vector3f pos = axes.findLocalVectorGlobally( new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F)); if(world.getBlockState(new BlockPos(MathHelper.floor(posX + pos.x), MathHelper.floor(posY + pos.y), MathHelper.floor(posZ + pos.z))).getMaterial() == Material.WATER) { part.onFire = false; } } else { Vector3f pos = getPartLocalVectorGlobally(part); if(world.getBlockState(new BlockPos(MathHelper.floor(posX + pos.x), MathHelper.floor(posY + pos.y), MathHelper.floor(posZ + pos.z))).getMaterial() == Material.LAVA) { part.onFire = true; } } } } for(int i = 0; i < type.emitters.size(); i++) { ParticleEmitter emitter = type.emitters.get(i); emitterTimers[i]--; boolean canEmit = false; DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part)); float healthPercentage = (float)part.health / (float)part.maxHealth; if(isPartIntact(EnumDriveablePart.getPart( emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth) { canEmit = true; } if(emitterTimers[i] <= 0) { if(throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle && canEmit) { // Emit! Vector3f velocity = new Vector3f(0, 0, 0); Vector3f pos = new Vector3f(0, 0, 0); if(seats != null && seats[0] != null) { if(EnumDriveablePart.getPart( emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart( emitter.part) != EnumDriveablePart.head) { Vector3f localPosition = new Vector3f( emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); pos = axes.findLocalVectorGlobally(localPosition); velocity = axes.findLocalVectorGlobally(emitter.velocity); } else if(EnumDriveablePart.getPart( emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart( emitter.part) != EnumDriveablePart.head) { Vector3f localPosition2 = new Vector3f( emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw() + axes.getYaw(), axes.getPitch(), axes.getRoll()); pos = yawOnlyLooking.findLocalVectorGlobally(localPosition2); velocity = yawOnlyLooking.findLocalVectorGlobally(emitter.velocity); } world.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z); } } emitterTimers[i] = emitter.emitRate; } } checkParts(); prevRotationYaw = axes.getYaw(); prevRotationPitch = axes.getPitch(); prevRotationRoll = axes.getRoll(); prevAxes = axes.clone(); boolean canThrust = driverIsCreative() || driveableData.fuelInTank > 0; // If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions if((getDriver() == null) || !canThrust && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0) { throttle *= 0.98F; primaryShootHeld = secondaryShootHeld = false; } else if(getDriver() != null && getDriver() == getControllingPassenger()) { reportVehicleError(); } if(seats[0] != null && seats[0].getRidingEntity() == null) { rightMouseHeld = leftMouseHeld = false; } // Check if shooting if(shootDelayPrimary > 0) shootDelayPrimary--; if(shootDelaySecondary > 0) shootDelaySecondary--; if(!world.isRemote) { if(primaryShootHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO) shoot(false); if(secondaryShootHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO) shoot(true); minigunSpeedPrimary *= 0.9F; minigunSpeedSecondary *= 0.9F; if(primaryShootHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN) { minigunSpeedPrimary += 0.1F; if(minigunSpeedPrimary > 1F) shoot(false); } if(secondaryShootHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN) { minigunSpeedSecondary += 0.1F; if(minigunSpeedSecondary > 1F) shoot(true); } } // Handle fuel int fuelMultiplier = 2; // The tank is currently full, so do nothing if(getDriveableData().fuelInTank >= type.fuelTankSize) return; // Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources for(int i = 0; i < getDriveableData().getSizeInventory(); i++) { ItemStack stack = getDriveableData().getStackInSlot(i); if(stack == null || stack.isEmpty()) continue; Item item = stack.getItem(); // Check for Flan's Mod fuel items if(item instanceof ItemPart) { PartType part = ((ItemPart)item).type; // Check it is a fuel item if(part.category == EnumPartCategory.FUEL) { // Put 2 points of fuel getDriveableData().fuelInTank += fuelMultiplier; // Damage the fuel item to indicate being used up int damage = stack.getItemDamage(); stack.setItemDamage(damage + 1); // If we have finished this fuel item if(damage >= stack.getMaxDamage()) { // Reset the damage to 0 stack.setItemDamage(0); // Consume one item stack.setCount(stack.getCount() - 1); // If we consumed the last one, destroy the stack if(stack.getCount() <= 0) getDriveableData().setInventorySlotContents(i, ItemStack.EMPTY.copy()); } // We found a fuel item and consumed some, so we are done break; } // Check for Buildcraft oil and fuel buckets else if(FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual( FlansMod.hooks.BuildCraftOilBucket) && getDriveableData().fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize) { getDriveableData().fuelInTank += 1000 * fuelMultiplier; getDriveableData().setInventorySlotContents(i, new ItemStack(Items.BUCKET)); } else if(FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual( FlansMod.hooks.BuildCraftFuelBucket) && getDriveableData().fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize) { getDriveableData().fuelInTank += 2000 * fuelMultiplier; getDriveableData().setInventorySlotContents(i, new ItemStack(Items.BUCKET)); } } } } public void PostUpdate() { if(Double.isNaN(posX) || Double.isNaN(posY) || Double.isNaN(posZ) || Float.isNaN(rotationYaw) || Float.isNaN(rotationPitch) || !axes.isValid()) { FlansMod.log.error("Driveable went to NaNsville. Reverting one frame"); posX = prevPosX; posY = prevPosY; posZ = prevPosZ; // Just reset the axes axes = new RotatedAxes(); prevAxes = new RotatedAxes(); } } public void tryRecoil() { int slot = -1; DriveableType type = getDriveableType(); for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { ItemStack shell = driveableData.getStackInSlot(i); if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, EnumWeaponType.SHELL)) { slot = i; } } if(recoilTimer <= 0 && slot != -1) isRecoil = true; } public void setRecoilTimer() { int slot = -1; DriveableType type = getDriveableType(); for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { ItemStack shell = driveableData.getStackInSlot(i); if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, EnumWeaponType.SHELL)) { slot = i; } } if(recoilTimer <= 0 && slot != -1) recoilTimer = getDriveableType().shootDelayPrimary; } private Vector3f getRandPosInBoundingBox(DriveablePart part) { // Pick a random position within the bounding box and spawn a flame there return axes.findLocalVectorGlobally( new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); } protected void moveTowardServerPosition() { double x = posX + (serverPosX - posX) / serverPositionTransitionTicker; double y = posY + (serverPosY - posY) / serverPositionTransitionTicker; double z = posZ + (serverPosZ - posZ) / serverPositionTransitionTicker; double dYaw = MathHelper.wrapDegrees(serverYaw - axes.getYaw()); double dPitch = MathHelper.wrapDegrees(serverPitch - axes.getPitch()); double dRoll = MathHelper.wrapDegrees(serverRoll - axes.getRoll()); rotationYaw = (float)(axes.getYaw() + dYaw / serverPositionTransitionTicker); rotationPitch = (float)(axes.getPitch() + dPitch / serverPositionTransitionTicker); float rotationRoll = (float)(axes.getRoll() + dRoll / serverPositionTransitionTicker); --serverPositionTransitionTicker; setPosition(x, y, z); setRotation(rotationYaw, rotationPitch, rotationRoll); } public void checkForCollisions() { boolean crashInWater = false; double speed = getSpeedXYZ(); for(DriveablePosition p : getDriveableType().collisionPoints) { if(driveableData.parts.get(p.part).dead) continue; Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position); Vec3d lastPos = new Vec3d(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z); Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position); Vec3d currentPos = new Vec3d(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z); if(FlansMod.DEBUG && world.isRemote) { world.spawnEntity(new EntityDebugVector(world, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F)); } RayTraceResult hit = world.rayTraceBlocks(lastPos, currentPos, crashInWater); if(hit != null && hit.typeOfHit == Type.BLOCK) { BlockPos pos = hit.getBlockPos(); IBlockState state = world.getBlockState(pos); float blockHardness = state.getBlockHardness(world, pos); float damage = (float)speed; // unbreakable block if(blockHardness < 0F) { damage *= unbreakableBlockDamage * unbreakableBlockDamage; } else { damage *= blockHardness * blockHardness; } // Attack the part if(!attackPart(p.part, DamageSource.IN_WALL, damage) && TeamsManager.driveablesBreakBlocks) { // And if it didn't die from the attack, break the block // TODO: [1.12] Heck // playAuxSFXAtEntity(null, 2001, pos, Block.getStateId(state)); if(!world.isRemote && blockHardness <= collisionForce) { WorldServer worldServer = (WorldServer)world; destroyBlock(worldServer, pos, getDriver(), true); } } else { // The part died! world.createExplosion(this, currentPos.x, currentPos.y, currentPos.z, 1F, false); } } } } @Override public void fall(float distance, float damageMultiplier) { if(distance <= 0) return; int i = MathHelper.ceil(distance - 10F); if(i > 0) attackPart(EnumDriveablePart.core, DamageSource.FALL, damageMultiplier * i / 5); } /** * Attack a certain part of a driveable and return whether it broke or not */ public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { DriveablePart part = driveableData.parts.get(ep); return part.attack(damage, source.isFireDamage()); } /** * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global * coordinates */ public Vector3f rotate(Vector3f inVec) { return axes.findLocalVectorGlobally(inVec); } /** * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global * coordinates */ public Vector3f rotate(Vec3d inVec) { return rotate(inVec.x, inVec.y, inVec.z); } /** * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global * coordinates */ public Vector3f rotate(double x, double y, double z) { return rotate(new Vector3f((float)x, (float)y, (float)z)); } /** * Rotate the plane locally by some angle about the yaw axis */ public void rotateYaw(float rotateBy) { if(Math.abs(rotateBy) < 0.01F) return; axes.rotateLocalYaw(rotateBy); updatePrevAngles(); } /** * Rotate the plane locally by some angle about the pitch axis */ public void rotatePitch(float rotateBy) { if(Math.abs(rotateBy) < 0.01F) return; axes.rotateLocalPitch(rotateBy); updatePrevAngles(); } /** * Rotate the plane locally by some angle about the roll axis */ public void rotateRoll(float rotateBy) { if(Math.abs(rotateBy) < 0.01F) return; axes.rotateLocalRoll(rotateBy); updatePrevAngles(); } public void updatePrevAngles() { // Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick. double dYaw = axes.getYaw() - prevRotationYaw; if(dYaw > 180) prevRotationYaw += 360F; if(dYaw < -180) prevRotationYaw -= 360F; double dPitch = axes.getPitch() - prevRotationPitch; if(dPitch > 180) prevRotationPitch += 360F; if(dPitch < -180) prevRotationPitch -= 360F; double dRoll = axes.getRoll() - prevRotationRoll; if(dRoll > 180) prevRotationRoll += 360F; if(dRoll < -180) prevRotationRoll -= 360F; } public void setRotation(float rotYaw, float rotPitch, float rotRoll) { axes.setAngles(rotYaw, rotPitch, rotRoll); } // Used to stop self collision public boolean isPartOfThis(Entity entity) { for(EntitySeat seat : seats) { if(seat == null) continue; if(entity == seat) return true; if(seat.getControllingPassenger() == entity) return true; } for(EntityWheel wheel : wheels) { if(entity == wheel) return true; } return entity == this; } public DriveableType getDriveableType() { return DriveableType.getDriveable(driveableType); } public DriveableData getDriveableData() { return driveableData; } @Override public boolean isDead() { return isDead; } @Override public Entity getControllingEntity() { return seats[0].getControllingEntity(); } @Override public ItemStack getPickedResult(RayTraceResult target) { ItemStack stack = new ItemStack(getDriveableType().item, 1, 0); NBTTagCompound tags = new NBTTagCompound(); stack.setTagCompound(tags); driveableData.writeToNBT(tags); return stack; } public boolean hasFuel() { if(getDriver() == null) return false; return driverIsCreative() || driveableData.fuelInTank > 0; } public boolean hasEnoughFuel() { if(getDriver() == null) return false; return driverIsCreative() || driveableData.fuelInTank > driveableData.engine.fuelConsumption * throttle; } public double getSpeedXYZ() { return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); } public double getSpeedXZ() { return Math.sqrt(motionX * motionX + motionZ * motionZ); } /** * To be overridden by vehicles to get alternate collision system */ public boolean landVehicle() { return false; } /** * Overridden by planes for wheel parts */ public boolean gearDown() { return true; } /** * Whether or not the plane is on the ground */ public boolean onGround() { // TODO: Replace with proper check based on wheels return onGround; } /** * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is * hit */ public ArrayList attackFromBullet(Vector3f origin, Vector3f motion) { // Make an array to contain the hits ArrayList hits = new ArrayList<>(); // Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null); Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); // Check each part for(DriveablePart part : getDriveableData().parts.values()) { // Ray trace the bullet DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector); if(hit != null) hits.add(hit); } return hits; } /** * Called if the bullet actually hit the part returned by the raytrace * * @param penetratingPower */ public float bulletHit(BulletType bulletType, float damage, DriveableHit hit, float penetratingPower) { DriveablePart part = getDriveableData().parts.get(hit.part); part.hitByBullet(bulletType, damage); // This is server side bsns if(!world.isRemote) { checkParts(); // If it hit, send a damage update packet FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); } return penetratingPower - 5F; } /** * A simple raytracer for the driveable. Called by tools */ public DriveablePart raytraceParts(Vector3f origin, Vector3f motion) { // Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null); Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); // Check each part for(DriveablePart part : getDriveableData().parts.values()) { // Ray trace the bullet if(part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null) { return part; } } return null; } /** * For overriding for toggles such as gear up / down on planes */ public boolean canHitPart(EnumDriveablePart part) { return true; } /** * Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that * child parts are destroyed when their parents are */ public void checkParts() { for(DriveablePart part : getDriveableData().parts.values()) { if(part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { killPart(part); } } // If the core was destroyed, kill the driveable if(getDriveableData().parts.get(EnumDriveablePart.core).dead) { if(!world.isRemote) { for(DriveablePart part : driveableData.parts.values()) { if(part.health > 0 && !part.dead) killPart(part); } } setDead(); } } /** * Internal method for killing driveable parts */ private void killPart(DriveablePart part) { if(part.dead) return; part.health = 0; part.dead = true; // Drop items DriveableType type = getDriveableType(); if(!world.isRemote) { Vector3f pos = new Vector3f(0, 0, 0); // Get the midpoint of the part if(part.box != null) pos = getPartLocalVectorGlobally(part); ArrayList drops = type.getItemsRequired(part, getDriveableData().engine); if(drops != null) { // Drop each item stack for(ItemStack stack : drops) { world.spawnEntity(new EntityItem(world, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy())); } } dropItemsOnPartDeath(pos, part); // Inventory is in the core, so drop it if the core is broken if(part.type == EnumDriveablePart.core) { for(EntityPlayer player : world.playerEntities) { if(player.openContainer instanceof ContainerDriveableInventory) { if(((ContainerDriveableInventory)player.openContainer).plane.getEntityId() == getEntityId()) { player.closeScreen(); //player.openGui(null, 0, world, (int)posX, (int)posY, (int)posZ); } } else if(player.openContainer instanceof ContainerMechaInventory) { if(((ContainerMechaInventory)player.openContainer).mecha.getEntityId() == getEntityId()) { player.closeScreen(); //player.openGui(null, 0, world, (int)posX, (int)posY, (int)posZ); } } } for(int i = 0; i < getDriveableData().getSizeInventory(); i++) { ItemStack stack = getDriveableData().getStackInSlot(i); if(stack != null && !stack.isEmpty()) { world.spawnEntity(new EntityItem(world, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack)); } } } } // Kill all child parts to stop things floating unconnected for(EnumDriveablePart child : part.type.getChildren()) { killPart(getDriveableData().parts.get(child)); } } private Vector3f getPartLocalVectorGlobally(DriveablePart part) { return axes.findLocalVectorGlobally(new Vector3f( part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); } /** * Method for planes, vehicles and whatnot to drop their own specific items if they wish */ protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part); @Override public float getPlayerRoll() { return axes.getRoll(); } @Override public float getPrevPlayerRoll() { return prevAxes.getRoll(); } @Override public void explode() { } @Override public float getCameraDistance() { return getDriveableType().cameraDistance; } public boolean isPartIntact(EnumDriveablePart part) { DriveablePart thisPart = getDriveableData().parts.get(part); return thisPart.maxHealth == 0 || thisPart.health > 0; } public abstract boolean hasMouseControlMode(); public abstract String getBombInventoryName(); public abstract String getMissileInventoryName(); public boolean rotateWithTurret(Seat seat) { return seat.part == EnumDriveablePart.turret; } @Override public String getName() { return getDriveableType().name; } @SideOnly(Side.CLIENT) public boolean showInventory(int seat) { return seat != 0 || !FlansModClient.controlModeMouse; } public float getShootDelay(boolean secondary) { return secondary ? shootDelaySecondary : shootDelayPrimary; } public float getMinigunSpeed(boolean secondary) { return secondary ? minigunSpeedSecondary : minigunSpeedPrimary; } public int getCurrentShootPointIndex(boolean secondary) { return secondary ? currentSecondaryGunShootPointIndex : currentPrimaryGunShootPointIndex; } public void setShootDelay(float f, boolean secondary) { if(secondary) shootDelaySecondary = f; else shootDelayPrimary = f; } public void setMinigunSpeed(float f, boolean secondary) { if(secondary) minigunSpeedSecondary = f; else minigunSpeedPrimary = f; } public void setCurrentShootPointIndex(int i, boolean secondary) { if(secondary) currentSecondaryGunShootPointIndex = i; else currentPrimaryGunShootPointIndex = i; } @Override protected boolean canFitPassenger(Entity passenger) { if(passenger instanceof EntitySeat || passenger instanceof EntityWheel) { return getPassengers().size() < getDriveableType().numPassengers + getDriveableType().wheelPositions.length + 1; } return false; } @Override public void updatePassenger(Entity passenger) { // They can handle themselves, but maybe the code should be moved to here } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); } public EntitySeat getSeat(EntityLivingBase passenger) { for(EntitySeat seat : seats) { if(seat.getControllingEntity() == passenger) { return seat; } } return null; } @Override protected void addPassenger(Entity passenger) { super.addPassenger(passenger); if(world.isRemote) { // We need to do some handling to work out which seat to get into. Or not? } } public void registerSeat(EntitySeat seat) { seats[seat.getExpectedSeatID()] = seat; } public void registerWheel(EntityWheel wheel) { wheels[wheel.getExpectedWheelID()] = wheel; } public EntitySeat[] getSeats() { return seats; } public EntitySeat getSeat(int id) { if(seats[id] == null) { for(Entity passenger : getPassengers()) { if(passenger instanceof EntitySeat) { EntitySeat seat = (EntitySeat)passenger; if(seat.getExpectedSeatID() == id) { seats[id] = seat; seats[id].driveable = this; break; } } } } return seats[id]; } public EntityWheel getWheel(int id) { if(wheels[id] == null) { for(Entity passenger : getPassengers()) { if(passenger instanceof EntityWheel) { EntityWheel wheel = (EntityWheel)passenger; if(wheel.getExpectedWheelID() == id) { wheels[id] = wheel; break; } } } } return wheels[id]; } @SideOnly(Side.CLIENT) public void togglePerspective() { Minecraft mc = Minecraft.getMinecraft(); if(mc.gameSettings.thirdPersonView == 0) mc.setRenderViewEntity((getCamera() == null ? mc.player : getCamera())); else mc.setRenderViewEntity(mc.player); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntityPlane.java ================================================ package com.flansmod.common.driveables; import net.minecraft.entity.MoverType; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.network.PacketDriveableControl; import com.flansmod.common.network.PacketPlaneControl; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Matrix4f; import com.flansmod.common.vector.Vector3f; public class EntityPlane extends EntityDriveable { /** * The flap positions, used for rendering and for controlling the plane rotations */ public float flapsYaw, flapsPitchLeft, flapsPitchRight; /** * Position of looping engine sound */ public int soundPosition; /** * The angle of the propeller for the renderer */ public float propAngle; /** * Weapon delays */ public int bombDelay, gunDelay; /** * Despawn timer */ public int ticksSinceUsed = 0; /** * Mostly aesthetic model variables. Gear actually has a variable hitbox */ public boolean varGear = true, varDoor = false, varWing = false; /** * Delayer for gear, door and wing buttons */ public int toggleTimer = 0; /** * Current plane mode */ public EnumPlaneMode mode; public EntityPlane(World world) { super(world); } public EntityPlane(World world, double x, double y, double z, PlaneType type, DriveableData data) { super(world, type, data); setPosition(x, y, z); prevPosX = x; prevPosY = y; prevPosZ = z; initType(type, true, false); } public EntityPlane(World world, double x, double y, double z, EntityPlayer placer, PlaneType type, DriveableData data) { this(world, x, y, z, type, data); rotateYaw(placer.rotationYaw + 90F); rotatePitch(type.restingPitch); } @Override public void initType(DriveableType type, boolean firstSpawn, boolean clientSide) { super.initType(type, firstSpawn, clientSide); mode = (((PlaneType)type).mode == EnumPlaneMode.HELI ? EnumPlaneMode.HELI : EnumPlaneMode.PLANE); } @Override protected void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); tag.setTag("Pos", this.newDoubleNBTList(this.posX, this.posY + 1D, this.posZ)); tag.setBoolean("VarGear", varGear); tag.setBoolean("VarDoor", varDoor); tag.setBoolean("VarWing", varWing); } @Override protected void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); varGear = tag.getBoolean("VarGear"); varDoor = tag.getBoolean("VarDoor"); varWing = tag.getBoolean("VarWing"); } /** * Called with the movement of the mouse. Used in controlling vehicles if need be. * * @param deltaY * @param deltaX */ @Override public void onMouseMoved(int deltaX, int deltaY) { if(!FMLCommonHandler.instance().getSide().isClient()) return; if(!FlansMod.proxy.mouseControlEnabled()) return; float sensitivity = 0.02F; flapsPitchLeft -= sensitivity * deltaY; flapsPitchRight -= sensitivity * deltaY; flapsPitchLeft -= sensitivity * deltaX; flapsPitchRight += sensitivity * deltaX; } @Override public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throttle, float steeringYaw) { super.setPositionRotationAndMotion(x, y, z, yaw, pitch, roll, motX, motY, motZ, velYaw, velPitch, velRoll, throttle, steeringYaw); flapsYaw = steeringYaw; } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) { if(isDead) return false; if(world.isRemote) return false; //If they are using a repair tool, don't put them in ItemStack currentItem = entityplayer.getHeldItemMainhand(); if(currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables) return true; PlaneType type = this.getPlaneType(); //Check each seat in order to see if the player can sit in it for(int i = 0; i <= type.numPassengers; i++) { if(getSeat(i).processInitialInteract(entityplayer, hand)) { if(i == 0) { bombDelay = type.planeBombDelay; FlansMod.proxy.doTutorialStuff(entityplayer, this); } return true; } } return false; } public boolean serverHandleKeyPress(int key, EntityPlayer player) { return super.serverHandleKeyPress(key, player); } @Override @SideOnly(Side.CLIENT) public boolean pressKey(int key, EntityPlayer player, boolean isOnEvent) { PlaneType type = this.getPlaneType(); //Send keys which require server side updates to the server boolean canThrust = ((getSeat(0) != null && getSeat(0).getControllingPassenger() instanceof EntityPlayer && ((EntityPlayer)getSeat(0).getControllingPassenger()).capabilities.isCreativeMode) || getDriveableData().fuelInTank > 0) && hasWorkingProp(); switch(key) { case 0: //Accelerate : Increase the throttle, up to 1. { if(canThrust || throttle < 0F) { throttle += 0.002F; if(throttle > 1F) throttle = 1F; } return true; } case 1: //Decelerate : Decrease the throttle, down to -1, or 0 if the plane cannot reverse { if(canThrust || throttle > 0F) { throttle -= 0.005F; if(throttle < -1F) throttle = -1F; if(throttle < 0F && type.maxNegativeThrottle == 0F) throttle = 0F; } return true; } case 2: //Left : Yaw the flaps left { flapsYaw -= 1F; return true; } case 3: //Right : Yaw the flaps right { flapsYaw += 1F; return true; } case 4: //Up : Pitch the flaps up { flapsPitchLeft += 1F; flapsPitchRight += 1F; return true; } case 5: //Down : Pitch the flaps down { flapsPitchLeft -= 1F; flapsPitchRight -= 1F; return true; } case 7: //Inventory : Check to see if this plane allows in-flight inventory editing or if the plane is on the ground { if(world.isRemote && (type.invInflight || (Math.abs(throttle) < 0.1F && onGround))) { FlansMod.proxy.openDriveableMenu((EntityPlayer)getSeat(0).getControllingPassenger(), world, this); } return true; } case 10: //Change control mode { FlansMod.proxy.changeControlMode((EntityPlayer)getSeat(0).getControllingPassenger()); return true; } case 11: //Roll left { flapsPitchLeft += 1F; flapsPitchRight -= 1F; return true; } case 12: //Roll right { flapsPitchLeft -= 1F; flapsPitchRight += 1F; return true; } case 13: // Gear { if(toggleTimer <= 0) { varGear = !varGear; player.sendMessage(new TextComponentString("Landing gear " + (varGear ? "down" : "up"))); toggleTimer = 10; FlansMod.getPacketHandler().sendToServer(new PacketDriveableControl(this)); } return true; } case 14: // Door { if(toggleTimer <= 0) { varDoor = !varDoor; if(type.hasDoor) player.sendMessage(new TextComponentString("Doors " + (varDoor ? "open" : "closed"))); toggleTimer = 10; FlansMod.getPacketHandler().sendToServer(new PacketDriveableControl(this)); } return true; } case 15: // Wing { if(toggleTimer <= 0) { if(type.hasWing) { varWing = !varWing; player.sendMessage(new TextComponentString("Switching mode")); } if(type.mode == EnumPlaneMode.VTOL) { if(mode == EnumPlaneMode.HELI) mode = EnumPlaneMode.PLANE; else mode = EnumPlaneMode.HELI; player.sendMessage(new TextComponentString( mode == EnumPlaneMode.HELI ? "Entering hover mode" : "Entering plane mode")); } toggleTimer = 10; FlansMod.getPacketHandler().sendToServer(new PacketDriveableControl(this)); } return true; } case 16: // Trim Button { axes.setAngles(axes.getYaw(), 0, 0); return true; } default: { return super.pressKey(key, player, isOnEvent); } } } @Override public void updateKeyHeldState(int key, boolean held) { super.updateKeyHeldState(key, held); } @Override public void onUpdate() { super.onUpdate(); if(!readyForUpdates) { return; } //Get plane type PlaneType type = getPlaneType(); DriveableData data = getDriveableData(); if(type == null) { FlansMod.log.warn("Plane type null. Not ticking plane"); return; } //Work out if this is the client side and the player is driving boolean thePlayerIsDrivingThis = world.isRemote && getSeat(0) != null && getSeat(0).getControllingPassenger() instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)getSeat(0).getControllingPassenger()); //Despawning ticksSinceUsed++; if(!world.isRemote && getSeat(0).getControllingPassenger() != null) ticksSinceUsed = 0; if(!world.isRemote && TeamsManager.planeLife > 0 && ticksSinceUsed > TeamsManager.planeLife * 20) { setDead(); } //Shooting, inventories, etc. //Decrement bomb and gun timers if(bombDelay > 0) bombDelay--; if(gunDelay > 0) gunDelay--; if(toggleTimer > 0) toggleTimer--; //Aesthetics //Rotate the propellers if(hasEnoughFuel()) { propAngle += (Math.pow(throttle, 0.4)) * 1.5; } //Return the flaps to their resting position flapsYaw *= 0.9F; flapsPitchLeft *= 0.9F; flapsPitchRight *= 0.9F; //Limit flap angles if(flapsYaw > 20) flapsYaw = 20; if(flapsYaw < -20) flapsYaw = -20; if(flapsPitchRight > 20) flapsPitchRight = 20; if(flapsPitchRight < -20) flapsPitchRight = -20; if(flapsPitchLeft > 20) flapsPitchLeft = 20; if(flapsPitchLeft < -20) flapsPitchLeft = -20; //Player is not driving this. Update its position from server update packets if(world.isRemote && !thePlayerIsDrivingThis) { //The driveable is currently moving towards its server position. Continue doing so. if(serverPositionTransitionTicker > 0) { moveTowardServerPosition(); } //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side plane would, so continue } //Movement //Throttle handling //Without a player, default to 0 //With a player default to 0.5 for helicopters (hover speed) //And default to the range 0.25 ~ 0.5 for planes (taxi speed ~ take off speed) float throttlePull = 0.99F; if(getSeat(0) != null && getSeat(0).getControllingPassenger() != null && mode == EnumPlaneMode.HELI && canThrust()) throttle = (throttle - 0.5F) * throttlePull + 0.5F; //Get the speed of the plane float lastTickSpeed = (float)getSpeedXYZ(); //Alter angles //Sensitivity function float sensitivityAdjust = 2.00677104758f - (float)Math.exp(-2.0f * throttle) / (4.5f * (throttle + 0.1f)); sensitivityAdjust = MathHelper.clamp(sensitivityAdjust, 0.0f, 1.0f); //Scalar sensitivityAdjust *= 0.125F; float yaw = flapsYaw * (flapsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier) * sensitivityAdjust; //if(throttle < 0.2F) // sensitivityAdjust = throttle * 2.5F; //Pitch according to the sum of flapsPitchLeft and flapsPitchRight / 2 float flapsPitch = (flapsPitchLeft + flapsPitchRight) / 2F; float pitch = flapsPitch * (flapsPitch > 0 ? type.lookUpModifier : type.lookDownModifier) * sensitivityAdjust; //Roll according to the difference between flapsPitchLeft and flapsPitchRight / 2 float flapsRoll = (flapsPitchRight - flapsPitchLeft) / 2F; float roll = flapsRoll * (flapsRoll > 0 ? type.rollLeftModifier : type.rollRightModifier) * sensitivityAdjust; //Damage modifiers if(mode == EnumPlaneMode.PLANE) { if(!isPartIntact(EnumDriveablePart.tail)) { yaw = 0; pitch = 0; roll = 0; } if(!isPartIntact(EnumDriveablePart.leftWing)) roll -= 7F * getSpeedXZ(); if(!isPartIntact(EnumDriveablePart.rightWing)) roll += 7F * getSpeedXZ(); } axes.rotateLocalYaw(yaw); axes.rotateLocalPitch(pitch); axes.rotateLocalRoll(-roll); if(world.isRemote && !FlansMod.proxy.mouseControlEnabled()) { //axes.rotateGlobalRoll(-axes.getRoll() * 0.1F); } //Some constants float g = 0.98F / 10F; float drag = 1F - (0.05F * type.drag); float wobbleFactor = 0F;//.005F; float throttleScaled = 0.01F * (type.maxThrottle + (data.engine == null ? 0 : data.engine.engineSpeed)); if(!canThrust()) throttleScaled = 0; int numPropsWorking = 0; int numProps = 0; switch(mode) { case HELI: //Count the number of working propellers for(Propeller prop : type.heliPropellers) if(isPartIntact(prop.planePart)) numPropsWorking++; numProps = type.heliPropellers.size(); Vector3f up = axes.getYAxis(); throttleScaled *= numProps == 0 ? 0 : (float)numPropsWorking / numProps * 2F; float upwardsForce = throttle * throttleScaled + (g - throttleScaled / 2F); if(throttle < 0.5F) upwardsForce = g * throttle * 2F; if(!isPartIntact(EnumDriveablePart.blades)) { upwardsForce = 0F; } //Move up //Throttle - 0.5 means that the positive throttle scales from -0.5 to +0.5. Thus it accounts for gravity-ish motionX += upwardsForce * up.x * 0.5F; motionY += upwardsForce * up.y; motionZ += upwardsForce * up.z * 0.5F; //Apply gravity motionY -= g; //Apply wobble //motionX += rand.nextGaussian() * wobbleFactor; //motionY += rand.nextGaussian() * wobbleFactor; //motionZ += rand.nextGaussian() * wobbleFactor; //Apply drag motionX *= drag; motionY *= drag; motionZ *= drag; data.fuelInTank -= upwardsForce * data.engine.fuelConsumption * 2F; break; case PLANE: //Count the number of working propellers for(Propeller prop : type.propellers) if(isPartIntact(prop.planePart)) numPropsWorking++; numProps = type.propellers.size(); float throttleTemp = throttle * (numProps == 0 ? 0 : (float)numPropsWorking / numProps * 2F); //Apply forces Vector3f forwards = (Vector3f)axes.getXAxis().normalise(); //Sanity limiter if(lastTickSpeed > 2F) lastTickSpeed = 2F; float newSpeed = lastTickSpeed + throttleScaled * 2F; //Calculate the amount to alter motion by float proportionOfMotionToCorrect = 2F * throttleTemp - 0.5F; if(proportionOfMotionToCorrect < throttle * 0.25f) proportionOfMotionToCorrect = throttle * 0.25f; if(proportionOfMotionToCorrect > 0.6F) proportionOfMotionToCorrect = 0.6F; //Apply gravity g = 0.98F / 20F; motionY -= g; //Apply lift int numWingsIntact = 0; if(isPartIntact(EnumDriveablePart.rightWing)) numWingsIntact++; if(isPartIntact(EnumDriveablePart.leftWing)) numWingsIntact++; float amountOfLift = 2F * g * throttleTemp * numWingsIntact / 2F; if(amountOfLift > g) amountOfLift = g; if(!isPartIntact(EnumDriveablePart.tail)) amountOfLift *= 0.75F; motionY += amountOfLift; //Cut out some motion for correction motionX *= 1F - proportionOfMotionToCorrect; motionY *= 1F - proportionOfMotionToCorrect; motionZ *= 1F - proportionOfMotionToCorrect; //Add the corrected motion motionX += proportionOfMotionToCorrect * newSpeed * forwards.x; motionY += proportionOfMotionToCorrect * newSpeed * forwards.y; motionZ += proportionOfMotionToCorrect * newSpeed * forwards.z; //Apply drag motionX *= drag; motionY *= drag; motionZ *= drag; data.fuelInTank -= Math.abs(throttle) * throttleScaled * data.engine.fuelConsumption * 10F; break; default: break; } double motion = Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); if(motion > 10) { motionX *= 10 / motion; motionY *= 10 / motion; motionZ *= 10 / motion; } for(EntityWheel wheel : wheels) { if(wheel != null && world != null) { wheel.prevPosX = wheel.posX; wheel.prevPosY = wheel.posY; wheel.prevPosZ = wheel.posZ; } } for(EntityWheel wheel : wheels) { if(wheel != null && world != null) if(type.floatOnWater && world.containsAnyLiquid(wheel.getEntityBoundingBox())) { motionY += type.buoyancy; } } //Move the wheels first for(EntityWheel wheel : wheels) { if(wheel != null) { wheel.prevPosY = wheel.posY; wheel.move(MoverType.SELF, motionX, motionY, motionZ); } } //Update wheels for(int i = 0; i < 2; i++) { Vector3f amountToMoveCar = new Vector3f(motionX / 2F, motionY / 2F, motionZ / 2F); for(EntityWheel wheel : wheels) { if(wheel == null) continue; //Hacky way of forcing the car to step up blocks onGround = true; wheel.onGround = true; //Update angles wheel.rotationYaw = axes.getYaw(); //Pull wheels towards car Vector3f targetWheelPos = axes.findLocalVectorGlobally( getPlaneType().wheelPositions[wheel.getExpectedWheelID()].position); Vector3f currentWheelPos = new Vector3f(wheel.posX - posX, wheel.posY - posY, wheel.posZ - posZ); float targetWheelLength = targetWheelPos.length(); float currentWheelLength = currentWheelPos.length(); if(currentWheelLength > targetWheelLength * 3.0d) { // Make wheels break? //this.attackPart(EnumDriveablePart.backLeftWheel, source, damage); } float dLength = targetWheelLength - currentWheelLength; float dAngle = Vector3f.angle(targetWheelPos, currentWheelPos); { //Now Lerp by wheelSpringStrength and work out the new positions float newLength = currentWheelLength + dLength * type.wheelSpringStrength; Vector3f rotateAround = Vector3f.cross(targetWheelPos, currentWheelPos, null); rotateAround.normalise(); Matrix4f mat = new Matrix4f(); mat.m00 = currentWheelPos.x; mat.m10 = currentWheelPos.y; mat.m20 = currentWheelPos.z; mat.rotate(dAngle * type.wheelSpringStrength, rotateAround); axes.rotateGlobal(-dAngle * type.wheelSpringStrength, rotateAround); Vector3f newWheelPos = new Vector3f(mat.m00, mat.m10, mat.m20); newWheelPos.normalise().scale(newLength); //The proportion of the spring adjustment that is applied to the wheel. 1 - this is applied to the plane float wheelProportion = 0.75F; //wheel.motionX = (newWheelPos.x - currentWheelPos.x) * wheelProportion; //wheel.motionY = (newWheelPos.y - currentWheelPos.y) * wheelProportion; //wheel.motionZ = (newWheelPos.z - currentWheelPos.z) * wheelProportion; Vector3f amountToMoveWheel = new Vector3f(); amountToMoveWheel.x = (newWheelPos.x - currentWheelPos.x) * (1F - wheelProportion); amountToMoveWheel.y = (newWheelPos.y - currentWheelPos.y) * (1F - wheelProportion); amountToMoveWheel.z = (newWheelPos.z - currentWheelPos.z) * (1F - wheelProportion); amountToMoveCar.x -= (newWheelPos.x - currentWheelPos.x) * (1F - wheelProportion); amountToMoveCar.y -= (newWheelPos.y - currentWheelPos.y) * (1F - wheelProportion); amountToMoveCar.z -= (newWheelPos.z - currentWheelPos.z) * (1F - wheelProportion); //The difference between how much the wheel moved and how much it was meant to move. i.e. the reaction force from the block //amountToMoveCar.x += ((wheel.posX - wheel.prevPosX) - (motionX)) * 0.616F / wheels.length; amountToMoveCar.y += ((wheel.posY - wheel.prevPosY) - (motionY)) * 0.5F / wheels.length; //amountToMoveCar.z += ((wheel.posZ - wheel.prevPosZ) - (motionZ)) * 0.0616F / wheels.length; if(amountToMoveWheel.lengthSquared() >= 32f * 32f) { FlansMod.log.warn("Wheel tried to move " + amountToMoveWheel.length() + " in a single frame, capping at 32 blocks"); amountToMoveWheel.normalise(); amountToMoveWheel.scale(32f); } wheel.move(MoverType.SELF, amountToMoveWheel.x, amountToMoveWheel.y, amountToMoveWheel.z); } } move(MoverType.SELF, amountToMoveCar.x, amountToMoveCar.y, amountToMoveCar.z); } checkForCollisions(); //Sounds //Starting sound if(throttle > 0.01F && throttle < 0.2F && soundPosition == 0 && hasEnoughFuel()) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.startSound, false); soundPosition = type.startSoundLength; } //Flying sound if(throttle > 0.2F && soundPosition == 0 && hasEnoughFuel()) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.engineSound, false); soundPosition = type.engineSoundLength; } //Sound decrementer if(soundPosition > 0) soundPosition--; for(EntitySeat seat : getSeats()) { if(seat != null) seat.updatePosition(); } //Calculate movement on the client and then send position, rotation etc to the server if(serverPosX != posX || serverPosY != posY || serverPosZ != posZ || serverYaw != axes.getYaw()) { if(thePlayerIsDrivingThis) { FlansMod.getPacketHandler().sendToServer(new PacketPlaneControl(this)); serverPosX = posX; serverPosY = posY; serverPosZ = posZ; serverYaw = axes.getYaw(); } } PostUpdate(); } public boolean canThrust() { return (getSeat(0) != null && getSeat(0).getControllingPassenger() instanceof EntityPlayer && ((EntityPlayer)getSeat(0).getControllingPassenger()).capabilities.isCreativeMode) || driveableData.fuelInTank > 0; } @Override public void setDead() { super.setDead(); } @Override public boolean gearDown() { return varGear; } private boolean hasWorkingProp() { PlaneType type = getPlaneType(); if(type.mode == EnumPlaneMode.HELI || type.mode == EnumPlaneMode.VTOL) for(Propeller prop : type.heliPropellers) if(isPartIntact(prop.planePart)) return true; if(type.mode == EnumPlaneMode.PLANE || type.mode == EnumPlaneMode.VTOL) for(Propeller prop : type.propellers) if(isPartIntact(prop.planePart)) return true; return false; } public boolean attackEntityFrom(DamageSource damagesource, float i, boolean doDamage) { if(world.isRemote || isDead) return true; PlaneType type = PlaneType.getPlane(driveableType); if(damagesource.damageType.equals("player") && damagesource.getTrueSource().onGround && (getSeat(0) == null || getSeat(0).getControllingPassenger() == null)) { ItemStack planeStack = new ItemStack(type.item, 1, driveableData.paintjobID); NBTTagCompound tags = new NBTTagCompound(); planeStack.setTagCompound(tags); driveableData.writeToNBT(tags); entityDropItem(planeStack, 0.5F); setDead(); } return true; } @Override public boolean canHitPart(EnumDriveablePart part) { return varGear || (part != EnumDriveablePart.coreWheel && part != EnumDriveablePart.leftWingWheel && part != EnumDriveablePart.rightWingWheel && part != EnumDriveablePart.tailWheel); } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { return attackEntityFrom(damagesource, i, true); } public PlaneType getPlaneType() { return PlaneType.getPlane(driveableType); } @Override protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part) { } @Override public String getBombInventoryName() { return "Bombs"; } @Override public String getMissileInventoryName() { return "Missiles"; } @Override public boolean hasMouseControlMode() { return true; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntitySeat.java ================================================ package com.flansmod.common.driveables; import java.util.List; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.passive.EntityAnimal; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemLead; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.client.FlansModClient; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.FireableGun; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.network.PacketDriveableKey; import com.flansmod.common.network.PacketDriveableKeyHeld; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.network.PacketSeatUpdates; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; import static com.flansmod.common.PlayerHandler.floatingTickCount; public class EntitySeat extends Entity implements IControllable, IEntityAdditionalSpawnData { private int driveableID; private int seatID; public EntityDriveable driveable; public float playerRoll, prevPlayerRoll; public Seat seatInfo; public RotatedAxes playerLooking; public RotatedAxes prevPlayerLooking; /** * A set of axes used to calculate where the player is looking, x axis is the direction of looking, y is up */ public RotatedAxes looking; /** * For smooth rendering */ public RotatedAxes prevLooking; /** * Delay ticker for shooting guns */ public float gunDelay; /** * Minigun speed */ public float minigunSpeed; /** * Minigun angle for render */ public float minigunAngle; /** * Sound delay ticker for looping sounds */ public int soundDelay; public int yawSoundDelay = 0; public int pitchSoundDelay = 0; public boolean playYawSound = false; public boolean playPitchSound = false; private double playerPosX, playerPosY, playerPosZ; private float playerYaw, playerPitch; /** * For smoothness */ private double prevPlayerPosX, prevPlayerPosY, prevPlayerPosZ; private float prevPlayerYaw, prevPlayerPitch; private boolean shooting; /** * Default constructor for spawning client side Should not be called server side EVER */ public EntitySeat(World world) { super(world); setSize(1F, 1F); prevLooking = new RotatedAxes(); looking = new RotatedAxes(); playerLooking = new RotatedAxes(); prevPlayerLooking = new RotatedAxes(); } /** * Server side seat constructor */ public EntitySeat(World world, EntityDriveable d, int id) { this(world); driveable = d; driveableID = d.getEntityId(); seatInfo = driveable.getDriveableType().seats[id]; seatID = id; setPosition(d.posX, d.posY, d.posZ); playerPosX = prevPlayerPosX = posX; playerPosY = prevPlayerPosY = posY; playerPosZ = prevPlayerPosZ = posZ; looking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); prevLooking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); } @Override public void onUpdate() { super.onUpdate(); if(driveable == null) { if(getRidingEntity() instanceof EntityDriveable) { driveable = (EntityDriveable)getRidingEntity(); driveable.registerSeat(this); } return; } // Update gun delay ticker if(gunDelay > 0) gunDelay--; // Update sound delay ticker if(soundDelay > 0) soundDelay--; if(yawSoundDelay > 0) yawSoundDelay--; if(pitchSoundDelay > 0) pitchSoundDelay--; if(playYawSound && yawSoundDelay == 0 && seatInfo.traverseSounds) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, seatInfo.yawSound, false); yawSoundDelay = seatInfo.yawSoundLength; } if(playPitchSound && pitchSoundDelay == 0 && seatInfo.traverseSounds) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, seatInfo.pitchSound, false); pitchSoundDelay = seatInfo.pitchSoundLength; } Entity entityInThisSeat = getControllingPassenger(); boolean isThePlayer = entityInThisSeat instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)entityInThisSeat); // Reset traverse sounds if player exits the vehicle if(!isThePlayer) { playYawSound = false; playPitchSound = false; yawSoundDelay = 0; pitchSoundDelay = 0; } // If on the client if(world.isRemote) { if(isDriverSeat() && isThePlayer && FlansMod.proxy.mouseControlEnabled() && driveable.hasMouseControlMode()) { looking = new RotatedAxes(); playerLooking = new RotatedAxes(); } if(entityInThisSeat instanceof EntityPlayer && shooting) { pressKey(9, (EntityPlayer)entityInThisSeat, false); } } else { if(entityInThisSeat instanceof EntityPlayerMP) { // Reset the floating tick count value for a player to avoid kicking them for flight detection try { floatingTickCount.setInt(((EntityPlayerMP)entityInThisSeat).connection, 0); } catch(IllegalAccessException e) { FlansMod.log.error("Failed to reset player's floating state.", e); } } } minigunSpeed *= 0.95F; minigunAngle += minigunSpeed; } @SideOnly(Side.CLIENT) private void updateSeatRotation() { Entity entityInThisSeat = getControllingPassenger(); boolean isThePlayer = entityInThisSeat instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)entityInThisSeat); if (!isThePlayer) return; // Move the seat accordingly // Consider new Yaw and Yaw limiters float targetX = playerLooking.getYaw(); float yawToMove = (targetX - looking.getYaw()); while(yawToMove > 180F) { yawToMove -= 360F; } while(yawToMove <= -180F) { yawToMove += 360F; } float signDeltaX = 0; if(yawToMove > (seatInfo.aimingSpeed.x / 2) && !seatInfo.legacyAiming) { signDeltaX = 1; } else if(yawToMove < -(seatInfo.aimingSpeed.x / 2) && !seatInfo.legacyAiming) { signDeltaX = -1; } else { signDeltaX = 0; } // Calculate new yaw and consider yaw limiters float newYaw = 0f; if(seatInfo.legacyAiming || (signDeltaX == 0)) { newYaw = playerLooking.getYaw(); } else { newYaw = looking.getYaw() + signDeltaX * seatInfo.aimingSpeed.x; } // Since the yaw limiters go from -360 to 360, we need to find a pair of yaw values and check them both float otherNewYaw = newYaw - 360F; if(newYaw < 0) otherNewYaw = newYaw + 360F; if((!(newYaw >= seatInfo.minYaw) || !(newYaw <= seatInfo.maxYaw)) && (!(otherNewYaw >= seatInfo.minYaw) || !(otherNewYaw <= seatInfo.maxYaw))) { float newYawDistFromRange = Math.min(Math.abs(newYaw - seatInfo.minYaw), Math.abs(newYaw - seatInfo.maxYaw)); float otherNewYawDistFromRange = Math.min(Math.abs(otherNewYaw - seatInfo.minYaw), Math.abs(otherNewYaw - seatInfo.maxYaw)); // If the newYaw is closer to the range than the otherNewYaw, move newYaw into the range if(newYawDistFromRange <= otherNewYawDistFromRange) { if(newYaw > seatInfo.maxYaw) newYaw = seatInfo.maxYaw; if(newYaw < seatInfo.minYaw) newYaw = seatInfo.minYaw; } // Else, the otherNewYaw is closer, so move it in else { if(otherNewYaw > seatInfo.maxYaw) otherNewYaw = seatInfo.maxYaw; if(otherNewYaw < seatInfo.minYaw) otherNewYaw = seatInfo.minYaw; // Then match up the newYaw with the otherNewYaw if(newYaw < 0) newYaw = otherNewYaw - 360F; else newYaw = otherNewYaw + 360F; } } // Calculate the new pitch and consider pitch limiters float targetY = playerLooking.getPitch(); float pitchToMove = (targetY - looking.getPitch()); while(pitchToMove > 180F) { pitchToMove -= 360F; } while(pitchToMove <= -180F) { pitchToMove += 360F; } float signDeltaY = 0; if(pitchToMove > (seatInfo.aimingSpeed.y / 2) && !seatInfo.legacyAiming) { signDeltaY = 1; } else if(pitchToMove < -(seatInfo.aimingSpeed.y / 2) && !seatInfo.legacyAiming) { signDeltaY = -1; } else { signDeltaY = 0; } float newPitch = 0f; // Pitches the gun at the last possible moment in order to reach target pitch at the same time as target yaw. float minYawToMove = 0f; float currentYawToMove = 0f; if(seatInfo.latePitch) { minYawToMove = ((float)Math .sqrt((pitchToMove / seatInfo.aimingSpeed.y) * (pitchToMove / seatInfo.aimingSpeed.y))) * seatInfo.aimingSpeed.x; } else { minYawToMove = 360f; } currentYawToMove = (float)Math.sqrt((yawToMove) * (yawToMove)); if(seatInfo.legacyAiming || (signDeltaY == 0)) { newPitch = playerLooking.getPitch(); } else if(!seatInfo.yawBeforePitch && currentYawToMove < minYawToMove) { newPitch = looking.getPitch() + signDeltaY * seatInfo.aimingSpeed.y; } else if(seatInfo.yawBeforePitch && signDeltaX == 0) { newPitch = looking.getPitch() + signDeltaY * seatInfo.aimingSpeed.y; } else if(seatInfo.yawBeforePitch) { newPitch = looking.getPitch(); } else { newPitch = looking.getPitch(); } if(newPitch > -seatInfo.minPitch) newPitch = -seatInfo.minPitch; if(newPitch < -seatInfo.maxPitch) newPitch = -seatInfo.maxPitch; if(looking.getYaw() != newYaw || looking.getPitch() != newPitch) { // Now set the new angles prevLooking = looking.clone(); looking.setAngles(newYaw, newPitch, 0F); FlansMod.getPacketHandler().sendToServer(new PacketSeatUpdates(this)); } playYawSound = signDeltaX != 0 && seatInfo.traverseSounds; if(signDeltaY != 0 && !seatInfo.yawBeforePitch && currentYawToMove < minYawToMove) { playPitchSound = true; } else playPitchSound = signDeltaY != 0 && seatInfo.yawBeforePitch && signDeltaX == 0; } /** * Set the position to be that of the driveable plus the local position, rotated */ public void updatePosition() { if(driveable == null) { if(getRidingEntity() instanceof EntityDriveable) { driveable = (EntityDriveable)getRidingEntity(); } else { return; } } if(seatInfo == null) seatInfo = driveable.getDriveableType().seats[seatID]; if (world.isRemote) updateSeatRotation(); prevPlayerPosX = playerPosX; prevPlayerPosY = playerPosY; prevPlayerPosZ = playerPosZ; prevPlayerYaw = playerYaw; prevPlayerPitch = playerPitch; prevPlayerRoll = playerRoll; // Get the position of this seat on the driveable axes Vector3f localPosition = new Vector3f(seatInfo.x / 16F, seatInfo.y / 16F, seatInfo.z / 16F); // Rotate the offset vector by the turret yaw if(driveable != null && driveable.getSeat(0) != null && driveable.getSeat(0).looking != null) { RotatedAxes yawOnlyLooking = new RotatedAxes(driveable.getSeat(0).looking.getYaw(), 0F, 0F); Vector3f rotatedOffset = yawOnlyLooking.findLocalVectorGlobally(seatInfo.rotatedOffset); Vector3f.add(localPosition, new Vector3f(rotatedOffset.x, 0F, rotatedOffset.z), localPosition); } // Get the position of this seat globally, but positionally relative to the driveable Vector3f relativePosition = driveable.axes.findLocalVectorGlobally(localPosition); if(Math.abs(driveable.posX + relativePosition.x - posX) > 100d || Math.abs(driveable.posY + relativePosition.y - posY) > 100d || Math.abs(driveable.posZ + relativePosition.z - posZ) > 100d) { FlansMod.log.warn("Seat was made to move stupid distance in a frame, cancelling"); } else { // Set the absol setPosition(driveable.posX + relativePosition.x, driveable.posY + relativePosition.y, driveable.posZ + relativePosition.z); } Entity entityInThisSeat = getControllingPassenger(); if(entityInThisSeat != null) { DriveableType type = driveable.getDriveableType(); Vec3d yOffset = driveable.axes.findLocalVectorGlobally(new Vector3f(0, entityInThisSeat.getEyeHeight() * 3 / 4, 0)) .toVec3().subtract(0, entityInThisSeat.getEyeHeight(), 0); // driveable.rotate(0, riddenByEntity.getYOffset(), 0).toVec3(); double x = posX + yOffset.x; double y = posY + yOffset.y; double z = posZ + yOffset.z; if((Math.abs(prevPlayerPosX - x) > 100d || Math.abs(prevPlayerPosY - y) > 100d || Math.abs(prevPlayerPosZ - z) > 100d) && prevPlayerPosY > 0.00001d) { FlansMod.log.warn("Player was made to move stupid distance in a frame, cancelling"); //entityInThisSeat.dismountRidingEntity(); } else { // Set the absol entityInThisSeat.setPosition(playerPosX, playerPosY, playerPosZ); playerPosX = x; playerPosY = y; playerPosZ = z; entityInThisSeat.lastTickPosX = getControllingPassenger().prevPosX = prevPlayerPosX; entityInThisSeat.lastTickPosY = getControllingPassenger().prevPosY = prevPlayerPosY; entityInThisSeat.lastTickPosZ = getControllingPassenger().prevPosZ = prevPlayerPosZ; } // Calculate the local look axes globally RotatedAxes globalLookAxes = driveable.axes.findLocalAxesGlobally(playerLooking); // Set the player's rotation based on this playerYaw = -90F + globalLookAxes.getYaw(); playerPitch = globalLookAxes.getPitch(); double dYaw = playerYaw - prevPlayerYaw; if(dYaw > 180) prevPlayerYaw += 360F; if(dYaw < -180) prevPlayerYaw -= 360F; if(entityInThisSeat instanceof EntityPlayer) { entityInThisSeat.prevRotationYaw = prevPlayerYaw; entityInThisSeat.prevRotationPitch = prevPlayerPitch; entityInThisSeat.rotationYaw = playerYaw; entityInThisSeat.rotationPitch = playerPitch; } // If the entity is a player, roll its view accordingly if(world.isRemote) { playerRoll = -globalLookAxes.getRoll(); } } } @Override @SideOnly(Side.CLIENT) public EntityLivingBase getCamera() { return driveable.getCamera(); } @Override public boolean canBeCollidedWith() { return !isDead; } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { DriveableType type = DriveableType.getDriveable(tags.getString("DriveableType")); seatID = tags.getInteger("Index"); if(type == null) { FlansMod.log.warn("Killing seat due to invalid type tag"); reallySetDead(); return; } seatInfo = type.seats[seatID]; if(getRidingEntity() instanceof EntityDriveable) { driveable = (EntityDriveable)getRidingEntity(); driveable.registerSeat(this); } } @Override protected void writeEntityToNBT(NBTTagCompound tags) { tags.setString("DriveableType", driveable == null ? "" : driveable.getDriveableType().shortName); tags.setInteger("Index", seatID); } @Override public boolean writeToNBTOptional(NBTTagCompound tags) { return false; } @Override @SideOnly(Side.CLIENT) public void onMouseMoved(int deltaX, int deltaY) { Minecraft mc = Minecraft.getMinecraft(); if(driveable == null) return; prevLooking = looking.clone(); prevPlayerLooking = playerLooking.clone(); // Driver seat should pass input to driveable if(isDriverSeat()) { driveable.onMouseMoved(deltaX, deltaY); } // Other seats should look around, but also the driver seat if mouse control mode is disabled if(!isDriverSeat() || !FlansModClient.controlModeMouse || !driveable.hasMouseControlMode()) { float lookSpeed = 4F; // Angle stuff for the player // Calculate the new pitch yaw while considering limiters float newPlayerYaw = playerLooking.getYaw() + deltaX / lookSpeed * mc.gameSettings.mouseSensitivity; float newPlayerPitch = playerLooking.getPitch() - deltaY / lookSpeed * mc.gameSettings.mouseSensitivity; if(newPlayerPitch > -seatInfo.minPitch) newPlayerPitch = -seatInfo.minPitch; if(newPlayerPitch < -seatInfo.maxPitch) newPlayerPitch = -seatInfo.maxPitch; // Since the yaw limiters go from -360 to 360, we need to find a pair of yaw values and check them both float otherNewPlayerYaw = newPlayerYaw - 360F; if(newPlayerYaw < 0) otherNewPlayerYaw = newPlayerYaw + 360F; if((newPlayerYaw >= seatInfo.minYaw && newPlayerYaw <= seatInfo.maxYaw) || (otherNewPlayerYaw >= seatInfo.minYaw && otherNewPlayerYaw <= seatInfo.maxYaw)) { //All is well } else { float newPlayerYawDistFromRange = Math.min(Math.abs(newPlayerYaw - seatInfo.minYaw), Math.abs(newPlayerYaw - seatInfo.maxYaw)); float otherPlayerNewYawDistFromRange = Math.min(Math.abs(otherNewPlayerYaw - seatInfo.minYaw), Math.abs(otherNewPlayerYaw - seatInfo.maxYaw)); // If the newYaw is closer to the range than the otherNewYaw, move newYaw into the range if(newPlayerYawDistFromRange <= otherPlayerNewYawDistFromRange) { if(newPlayerYaw > seatInfo.maxYaw) newPlayerYaw = seatInfo.maxYaw; if(newPlayerYaw < seatInfo.minYaw) newPlayerYaw = seatInfo.minYaw; } // Else, the otherNewYaw is closer, so move it in else { if(otherNewPlayerYaw > seatInfo.maxYaw) otherNewPlayerYaw = seatInfo.maxYaw; if(otherNewPlayerYaw < seatInfo.minYaw) otherNewPlayerYaw = seatInfo.minYaw; //Then match up the newYaw with the otherNewYaw if(newPlayerYaw < 0) newPlayerYaw = otherNewPlayerYaw - 360F; else newPlayerYaw = otherNewPlayerYaw + 360F; } } // Now set the new angles playerLooking.setAngles(newPlayerYaw, newPlayerPitch, 0F); } } @Override public void updateKeyHeldState(int key, boolean held) { if(world.isRemote && driveable != null) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); } if(isDriverSeat()) { driveable.updateKeyHeldState(key, held); } else if(key == 9) { shooting = held; } } @Override @SideOnly(Side.CLIENT) public boolean pressKey(int key, EntityPlayer player, boolean isOnTick) { // Driver seat should pass input to driveable if(isDriverSeat() && driveable != null) { return driveable.pressKey(key, player, isOnTick); } if(world.isRemote && key == 7 && driveable != null) { FlansMod.proxy.openDriveableMenu(player, world, driveable); } if(world.isRemote) { if(driveable != null) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); //setting client side minigun speed for animation if(key == 9) minigunSpeed += 0.1F; } } return false; } @Override public boolean serverHandleKeyPress(int key, EntityPlayer player) { switch (key) { case 9: // Get the gun from the plane type and the ammo from the data GunType gun = seatInfo.gunType; //setting server side minigun speed minigunSpeed += 0.15F; if(gun != null && gun.mode != EnumFireMode.MINIGUN || minigunSpeed > 2F) { if(gunDelay <= 0 && TeamsManager.bulletsEnabled && seatInfo.gunnerID < driveable.getDriveableData().ammo.length) { ItemStack bulletItemStack = driveable.getDriveableData().ammo[seatInfo.gunnerID]; // Check that neither is null and that the bullet item is actually a bullet if(gun != null && bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable) { ShootableType bullet = ((ItemShootable)bulletItemStack.getItem()).type; if(gun.isCorrectAmmo(bullet)) { // Gun origin Vector3f gunOrigin = Vector3f.add(driveable.axes.findLocalVectorGlobally(seatInfo.gunOrigin), new Vector3f(driveable.posX, driveable.posY, driveable.posZ), null); // Calculate the look axes globally Vector3f shootVec = driveable.axes.findLocalVectorGlobally(looking.getXAxis()); // Calculate the origin of the bullets Vector3f yOffset = driveable.axes .findLocalVectorGlobally(new Vector3f(0F, (float)player.getMountedYOffset(), 0F)); FireableGun fireableGun = new FireableGun(gun, gun.damage, gun.bulletSpread, gun.bulletSpeed, gun.spreadPattern); //TODO unchecked cast, grenades wont work (currently no vehicle with this feature exists) FiredShot shot = new FiredShot(fireableGun, (BulletType) bullet, this, (EntityPlayerMP)getControllingPassenger()); ShotHandler.fireGun(world, shot, gun.numBullets*bullet.numBullets, Vector3f.add(yOffset, new Vector3f(gunOrigin.x, gunOrigin.y, gunOrigin.z), null), shootVec); // Play the shoot sound if(soundDelay <= 0) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gun.shootSound, false); soundDelay = gun.shootSoundLength; } //use ammo (unless in creative) if(!((EntityPlayer)getControllingPassenger()).capabilities.isCreativeMode) { // Get the bullet item damage and increment it int damage = bulletItemStack.getItemDamage(); bulletItemStack.setItemDamage(damage + 1); // If the bullet item is completely damaged (empty) if(damage + 1 >= bulletItemStack.getMaxDamage()) { //Set the damage to 0 and consume one ammo item bulletItemStack.setItemDamage(0); bulletItemStack.setCount(bulletItemStack.getCount()-1); if (bulletItemStack.getCount() <= 0) bulletItemStack = ItemStack.EMPTY.copy(); driveable.getDriveableData().ammo[seatInfo.gunnerID] = bulletItemStack; } } // Reset the shoot delay gunDelay = gun.shootDelay; } } } } return true; } return false; } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) //interact : change back when Forge updates { if(isDead) return false; if(world.isRemote) return false; if(driveable == null) return false; // If they are using a repair tool, don't put them in ItemStack currentItem = entityplayer.getHeldItemMainhand(); if(currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables) return true; if(currentItem.getItem() instanceof ItemLead) { if(getControllingPassenger() instanceof EntityAnimal) { // Minecraft will handle dismounting the mob return true; } double checkRange = 10; List nearbyAnimals = world.getEntitiesWithinAABB(EntityAnimal.class, new AxisAlignedBB(posX - checkRange, posY - checkRange, posZ - checkRange, posX + checkRange, posY + checkRange, posZ + checkRange)); for(EntityAnimal animal : nearbyAnimals) { if(animal.getLeashed() && animal.getLeashHolder() == entityplayer) { if(animal.startRiding(this)) { looking.setAngles(-animal.rotationYaw, animal.rotationPitch, 0F); animal.clearLeashed(true, !entityplayer.capabilities.isCreativeMode); playerPosX = prevPlayerPosX = animal.posX; playerPosY = prevPlayerPosY = animal.posY; playerPosZ = prevPlayerPosZ = animal.posZ; } else { FlansMod.log.warn("Failed to put pet in seat"); } } } return true; } // Put them in the seat if(getControllingPassenger() == null && !driveable.getDriveableData().engine.isAIChip) { if(entityplayer.startRiding(this)) { playerPosX = prevPlayerPosX = entityplayer.posX; playerPosY = prevPlayerPosY = entityplayer.posY; playerPosZ = prevPlayerPosZ = entityplayer.posZ; } else { FlansMod.log.warn("Failed to mount seat"); } return true; } return false; } @Override public Entity getControllingEntity() { return getControllingPassenger(); } @Override public Entity getControllingPassenger() { return getPassengers().isEmpty() ? null : getPassengers().get(0); } @Override public boolean isDead() { return isDead; } @Override public void setDead() { // No chance. You do not have the power } public void reallySetDead() { super.setDead(); } public EntitySeat getSeat(EntityLivingBase living) { return this; } public boolean isDriverSeat() { return seatID == 0; } @Override public boolean startRiding(Entity riding) { boolean success = super.startRiding(riding); if(success && riding instanceof EntityDriveable) { EntityDriveable driveable = (EntityDriveable)riding; driveable.registerSeat(this); } playerPosX = prevPlayerPosX = riding.posX; playerPosY = prevPlayerPosY = riding.posY; playerPosZ = prevPlayerPosZ = riding.posZ; return success; } @Override public void updatePassenger(Entity passenger) { if(passenger instanceof EntityPlayer) { passenger.rotationYaw = playerYaw; passenger.rotationPitch = playerPitch; passenger.prevRotationYaw = prevPlayerYaw; passenger.prevRotationPitch = prevPlayerPitch; } passenger.lastTickPosX = passenger.prevPosX = prevPlayerPosX; passenger.lastTickPosY = passenger.prevPosY = prevPlayerPosY; passenger.lastTickPosZ = passenger.prevPosZ = prevPlayerPosZ; passenger.setPosition(playerPosX, playerPosY, playerPosZ); } @Override public ItemStack getPickedResult(RayTraceResult target) { if(driveable == null) return ItemStack.EMPTY.copy(); return driveable.getPickedResult(target); } @Override public float getPlayerRoll() { return playerRoll; } @Override public float getPrevPlayerRoll() { return prevPlayerRoll; } @Override public float getCameraDistance() { return driveable != null && seatID == 0 ? driveable.getDriveableType().cameraDistance * 2.0f : 5F; } @Override public boolean attackEntityFrom(DamageSource source, float f) { if(driveable == null) return false; return driveable.attackEntityFrom(source, f); } @Override public void writeSpawnData(ByteBuf data) { data.writeInt(driveableID); if(seatInfo == null) { data.writeInt(-1); FlansMod.log.warn("Bad seat data. This is very bad"); } else { data.writeInt(seatInfo.id); } } @Override public void readSpawnData(ByteBuf data) { driveableID = data.readInt(); if(world.getEntityByID(driveableID) instanceof EntityDriveable) driveable = (EntityDriveable)world.getEntityByID(driveableID); seatID = data.readInt(); if(seatID >= 0 && driveable != null) { seatInfo = driveable.getDriveableType().seats[seatID]; looking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); playerPosX = prevPlayerPosX = posX = driveable.posX; playerPosY = prevPlayerPosY = posY = driveable.posY; playerPosZ = prevPlayerPosZ = posZ = driveable.posZ; } setPosition(posX, posY, posZ); } public int getExpectedSeatID() { return seatID; } public float getMinigunSpeed() { return minigunSpeed; } @Override public void updateRidden() { if(!updateBlocked) onUpdate(); if(isRiding()) { getRidingEntity().updatePassenger(this); } } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntityVehicle.java ================================================ package com.flansmod.common.driveables; import io.netty.buffer.ByteBuf; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IExplodeable; import com.flansmod.client.model.AnimTankTrack; import com.flansmod.client.model.AnimTrackLink; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.network.PacketVehicleControl; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; public class EntityVehicle extends EntityDriveable implements IExplodeable { /** * Weapon delays */ public int shellDelay, gunDelay; /** * Position of looping sounds */ public int soundPosition; /** * Front wheel yaw, used to control the vehicle steering */ public float wheelsYaw; /** * Despawn time */ private int ticksSinceUsed = 0; /** * Aesthetic door switch */ public boolean varDoor; /** * Wheel rotation angle. Only applies to vehicles that set a rotating wheels flag */ public float wheelsAngle; /** * Delayer for door button */ public int toggleTimer = 0; public AnimTankTrack rightTrack; public AnimTankTrack leftTrack; public AnimTrackLink[] trackLinksLeft = new AnimTrackLink[0]; public AnimTrackLink[] trackLinksRight = new AnimTrackLink[0]; public EntityVehicle(World world) { super(world); stepHeight = 1.0F; } //This one deals with spawning from a vehicle spawner public EntityVehicle(World world, double x, double y, double z, VehicleType type, DriveableData data) { super(world, type, data); stepHeight = 1.0F; setPosition(x, y, z); initType(type, true, false); } //This one allows you to deal with spawning from items public EntityVehicle(World world, double x, double y, double z, EntityPlayer placer, VehicleType type, DriveableData data) { super(world, type, data); stepHeight = 1.0F; setPosition(x, y, z); rotateYaw(placer.rotationYaw + 90F); initType(type, true, false); } public void setupTracks(DriveableType type) { rightTrack = new AnimTankTrack(type.rightTrackPoints, type.trackLinkLength); leftTrack = new AnimTankTrack(type.leftTrackPoints, type.trackLinkLength); int numLinks = Math.round(rightTrack.getTrackLength() / type.trackLinkLength); trackLinksLeft = new AnimTrackLink[numLinks]; trackLinksRight = new AnimTrackLink[numLinks]; for(int i = 0; i < numLinks; i++) { float progress = 0.01F + (type.trackLinkLength * i); int trackPart = leftTrack.getTrackPart(progress); trackLinksLeft[i] = new AnimTrackLink(progress); trackLinksRight[i] = new AnimTrackLink(progress); trackLinksLeft[i].position = leftTrack.getPositionOnTrack(progress); trackLinksRight[i].position = rightTrack.getPositionOnTrack(progress); trackLinksLeft[i].rot = new RotatedAxes(0, 0, rotateTowards(leftTrack.points.get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position)); trackLinksRight[i].rot = new RotatedAxes(0, 0, rotateTowards(rightTrack.points.get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position)); trackLinksLeft[i].zRot = rotateTowards(leftTrack.points .get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position); trackLinksRight[i].zRot = rotateTowards(rightTrack.points .get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position); } } @Override protected void initType(DriveableType type, boolean firstSpawn, boolean clientSide) { setupTracks(type); super.initType(type, firstSpawn, clientSide); } @Override public void readSpawnData(ByteBuf data) { super.readSpawnData(data); } @Override protected void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); tag.setBoolean("VarDoor", varDoor); } @Override protected void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); varDoor = tag.getBoolean("VarDoor"); } /** * Called with the movement of the mouse. Used in controlling vehicles if need be. * * @param deltaY * @param deltaX */ @Override public void onMouseMoved(int deltaX, int deltaY) { } @Override public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throttle, float steeringYaw) { super.setPositionRotationAndMotion(x, y, z, yaw, pitch, roll, motX, motY, motZ, velYaw, velPitch, velRoll, throttle, steeringYaw); wheelsYaw = steeringYaw; } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) { if(isDead) return false; if(world.isRemote) return false; //If they are using a repair tool, don't put them in ItemStack currentItem = entityplayer.getHeldItemMainhand(); if(currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables) return true; VehicleType type = getVehicleType(); //Check each seat in order to see if the player can sit in it for(int i = 0; i <= type.numPassengers; i++) { if(getSeat(i).processInitialInteract(entityplayer, hand)) { if(i == 0) { shellDelay = type.shootDelayPrimary; FlansMod.proxy.doTutorialStuff(entityplayer, this); } return true; } } return false; } @Override @SideOnly(Side.CLIENT) public boolean pressKey(int key, EntityPlayer player, boolean isOnEvent) { VehicleType type = getVehicleType(); switch(key) { case 0: // Accelerate : Increase the throttle, up to 1. { throttle += 0.01F; if(throttle > 1F) throttle = 1F; return true; } case 1: // Decelerate : Decrease the throttle, down to -1, or 0 if the vehicle cannot reverse { throttle -= 0.01F; if(throttle < -1F) throttle = -1F; if(throttle < 0F && type.maxNegativeThrottle == 0F) throttle = 0F; return true; } case 2: // Left : Yaw the wheels left { wheelsYaw -= 1F; return true; } case 3: // Right : Yaw the wheels right { wheelsYaw += 1F; return true; } case 4: // Up : Brake { throttle *= 0.8F; if(onGround) { motionX *= 0.8F; motionZ *= 0.8F; } return true; } case 7: //Inventory { if(world.isRemote) { FlansMod.proxy.openDriveableMenu((EntityPlayer)getSeat(0).getControllingPassenger(), world, this); } return true; } case 14: // Door { if(toggleTimer <= 0) { varDoor = !varDoor; if(type.hasDoor) player.sendMessage(new TextComponentString("Doors " + (varDoor ? "open" : "closed"))); toggleTimer = 10; FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); } return true; } default: { return super.pressKey(key, player, isOnEvent); } } } @Override public Vector3f getLookVector(ShootPoint shootPoint) { return rotate(getSeat(0).looking.getXAxis()); } @Override public void onUpdate() { super.onUpdate(); if(!readyForUpdates) { return; } //Get vehicle type VehicleType type = this.getVehicleType(); DriveableData data = getDriveableData(); if(type == null) { FlansMod.log.warn("Vehicle type null. Not ticking vehicle"); return; } animateFancyTracks(); //Work out if this is the client side and the player is driving boolean thePlayerIsDrivingThis = world.isRemote && getSeat(0) != null && getSeat(0).getControllingPassenger() instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)getSeat(0).getControllingPassenger()); //Despawning ticksSinceUsed++; if(!world.isRemote && getSeat(0).getControllingPassenger() != null) ticksSinceUsed = 0; if(!world.isRemote && TeamsManager.vehicleLife > 0 && ticksSinceUsed > TeamsManager.vehicleLife * 20) { setDead(); } //Shooting, inventories, etc. //Decrement shell and gun timers if(shellDelay > 0) shellDelay--; if(gunDelay > 0) gunDelay--; if(toggleTimer > 0) toggleTimer--; if(soundPosition > 0) soundPosition--; //Aesthetics //Rotate the wheels if(hasEnoughFuel()) { wheelsAngle += throttle * 0.2F; } //Return the wheels to their resting position wheelsYaw *= 0.9F; //Limit wheel angles if(wheelsYaw > 20) wheelsYaw = 20; if(wheelsYaw < -20) wheelsYaw = -20; //Player is not driving this. Update its position from server update packets if(world.isRemote && !thePlayerIsDrivingThis) { //The driveable is currently moving towards its server position. Continue doing so. if(serverPositionTransitionTicker > 0) { moveTowardServerPosition(); } //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side driveable would, so continue } //Movement Vector3f amountToMoveCar = new Vector3f(); for(EntityWheel wheel : wheels) { if(wheel != null && world != null) { wheel.prevPosX = wheel.posX; wheel.prevPosY = wheel.posY; wheel.prevPosZ = wheel.posZ; } } for(EntityWheel wheel : wheels) { if(wheel == null) continue; //Hacky way of forcing the car to step up blocks onGround = true; wheel.onGround = true; //Update angles wheel.rotationYaw = axes.getYaw(); //Front wheels if(!type.tank && (wheel.getExpectedWheelID() == 2 || wheel.getExpectedWheelID() == 3)) { wheel.rotationYaw += wheelsYaw; } wheel.motionX *= 0.9F; wheel.motionY *= 0.9F; wheel.motionZ *= 0.9F; //Apply gravity wheel.motionY -= 0.98F / 20F; //Apply velocity EntityPlayer driver = getDriver(); if(canThrust(data, driver)) { if (!driverIsCreative()) { data.fuelInTank -= data.engine.fuelConsumption * Math.abs(throttle) * 0.05F; } if(getVehicleType().tank) { boolean left = wheel.getExpectedWheelID() == 0 || wheel.getExpectedWheelID() == 3; float turningDrag = 0.02F; wheel.motionX *= 1F - (Math.abs(wheelsYaw) * turningDrag); wheel.motionZ *= 1F - (Math.abs(wheelsYaw) * turningDrag); float velocityScale = 0.04F * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) * data.engine.engineSpeed; float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); float effectiveWheelSpeed = (throttle + (wheelsYaw * (left ? 1 : -1) * steeringScale)) * velocityScale; wheel.motionX += effectiveWheelSpeed * Math.cos(wheel.rotationYaw * 3.14159265F / 180F); wheel.motionZ += effectiveWheelSpeed * Math.sin(wheel.rotationYaw * 3.14159265F / 180F); } else { //if(getVehicleType().fourWheelDrive || wheel.ID == 0 || wheel.ID == 1) { float velocityScale = 0.1F * throttle * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) * data.engine.engineSpeed; wheel.motionX += Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; wheel.motionZ += Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; } //Apply steering if(wheel.getExpectedWheelID() == 2 || wheel.getExpectedWheelID() == 3) { float velocityScale = 0.01F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier) * (throttle > 0 ? 1 : -1); wheel.motionX -= wheel.getSpeedXZ() * Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; wheel.motionZ += wheel.getSpeedXZ() * Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; } else { wheel.motionX *= 0.9F; wheel.motionZ *= 0.9F; } } } if(type.floatOnWater && world.containsAnyLiquid(wheel.getEntityBoundingBox())) { wheel.motionY += type.buoyancy; } wheel.move(MoverType.PLAYER, wheel.motionX, wheel.motionY, wheel.motionZ); //Pull wheels towards car Vector3f targetWheelPos = axes .findLocalVectorGlobally(getVehicleType().wheelPositions[wheel.getExpectedWheelID()].position); Vector3f currentWheelPos = new Vector3f(wheel.posX - posX, wheel.posY - posY, wheel.posZ - posZ); Vector3f dPos = ((Vector3f)Vector3f.sub(targetWheelPos, currentWheelPos, null) .scale(getVehicleType().wheelSpringStrength)); if(dPos.length() > 0.001F) { wheel.move(MoverType.PLAYER, dPos.x, dPos.y, dPos.z); dPos.scale(0.5F); Vector3f.sub(amountToMoveCar, dPos, amountToMoveCar); } } move(MoverType.PLAYER, amountToMoveCar.x, amountToMoveCar.y, amountToMoveCar.z); if(wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { Vector3f frontAxleCentre = new Vector3f((wheels[2].posX + wheels[3].posX) / 2F, (wheels[2].posY + wheels[3].posY) / 2F, (wheels[2].posZ + wheels[3].posZ) / 2F); Vector3f backAxleCentre = new Vector3f((wheels[0].posX + wheels[1].posX) / 2F, (wheels[0].posY + wheels[1].posY) / 2F, (wheels[0].posZ + wheels[1].posZ) / 2F); Vector3f leftSideCentre = new Vector3f((wheels[0].posX + wheels[3].posX) / 2F, (wheels[0].posY + wheels[3].posY) / 2F, (wheels[0].posZ + wheels[3].posZ) / 2F); Vector3f rightSideCentre = new Vector3f((wheels[1].posX + wheels[2].posX) / 2F, (wheels[1].posY + wheels[2].posY) / 2F, (wheels[1].posZ + wheels[2].posZ) / 2F); float dx = frontAxleCentre.x - backAxleCentre.x; float dy = frontAxleCentre.y - backAxleCentre.y; float dz = frontAxleCentre.z - backAxleCentre.z; float drx = leftSideCentre.x - rightSideCentre.x; float dry = leftSideCentre.y - rightSideCentre.y; float drz = leftSideCentre.z - rightSideCentre.z; float dxz = (float)Math.sqrt(dx * dx + dz * dz); float drxz = (float)Math.sqrt(drx * drx + drz * drz); float yaw = (float)Math.atan2(dz, dx); float pitch = -(float)Math.atan2(dy, dxz); float roll = 0F; if(type.canRoll) { roll = -(float)Math.atan2(dry, drxz); } if(type.tank) { yaw = (float)Math.atan2(wheels[3].posZ - wheels[2].posZ, wheels[3].posX - wheels[2].posX) + (float)Math.PI / 2F; } axes.setAngles(yaw * 180F / 3.14159F, pitch * 180F / 3.14159F, roll * 180F / 3.14159F); } checkForCollisions(); //Sounds //Starting sound if(throttle > 0.01F && throttle < 0.2F && soundPosition == 0 && hasEnoughFuel()) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, type.startSound, false); soundPosition = type.startSoundLength; } //Flying sound if(throttle > 0.2F && soundPosition == 0 && hasEnoughFuel()) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, type.engineSound, false); soundPosition = type.engineSoundLength; } for(EntitySeat seat : getSeats()) { if(seat != null) seat.updatePosition(); } if(serverPosX != posX || serverPosY != posY || serverPosZ != posZ || serverYaw != axes.getYaw()) { //Calculate movement on the client and then send position, rotation etc to the server if(thePlayerIsDrivingThis) { FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); serverPosX = posX; serverPosY = posY; serverPosZ = posZ; serverYaw = axes.getYaw(); } } int animSpeed = 4; //Change animation speed based on our current throttle if((throttle > 0.05 && throttle <= 0.33) || (throttle < -0.05 && throttle >= -0.33)) { animSpeed = 3; } else if((throttle > 0.33 && throttle <= 0.66) || (throttle < -0.33 && throttle >= -0.66)) { animSpeed = 2; } else if((throttle > 0.66 && throttle <= 0.9) || (throttle < -0.66 && throttle >= -0.9)) { animSpeed = 1; } else if((throttle > 0.9 && throttle <= 1) || (throttle < -0.9 && throttle >= -1)) { animSpeed = 0; } if(throttle > 0.05) { animCount--; } else if(throttle < -0.05) { animCount++; } if(animCount <= 0) { animCount = animSpeed; animFrame++; } if(throttle < 0) { if(animCount >= animSpeed) { animCount = 0; animFrame--; } } //Cycle the animation frame, but only if we have anything to cycle if(type.animFrames != 0) { if(animFrame > type.animFrames) { animFrame = 0; } if(animFrame < 0) { animFrame = type.animFrames; } } PostUpdate(); } private boolean canThrust(DriveableData data, EntityPlayer driver) { return !TeamsManager.vehiclesNeedFuel || driverIsCreative() || (data.engine != null && data.fuelInTank > data.engine.fuelConsumption * throttle); } public void animateFancyTracks() { float funkypart = getVehicleType().trackLinkFix; boolean funk = getVehicleType().flipLinkFix; float funk2 = 0; for(int i = 0; i < trackLinksLeft.length; i++) { trackLinksLeft[i].prevPosition = trackLinksLeft[i].position; trackLinksLeft[i].prevZRot = trackLinksLeft[i].zRot; float speed = throttle * 1.5F - (wheelsYaw / 12); trackLinksLeft[i].progress += speed; if(trackLinksLeft[i].progress > leftTrack.getTrackLength()) trackLinksLeft[i].progress -= leftTrack.getTrackLength(); if(trackLinksLeft[i].progress < 0) trackLinksLeft[i].progress += leftTrack.getTrackLength(); trackLinksLeft[i].position = leftTrack.getPositionOnTrack(trackLinksLeft[i].progress); for(; trackLinksLeft[i].zRot > 180F; trackLinksLeft[i].zRot -= 360F) { } for(; trackLinksLeft[i].zRot <= -180F; trackLinksLeft[i].zRot += 360F) { } float newAngle = rotateTowards(leftTrack.points.get(leftTrack.getTrackPart(trackLinksLeft[i].progress)), trackLinksLeft[i].position); int part = leftTrack.getTrackPart(trackLinksLeft[i].progress); if(funk) funk2 = (speed < 0) ? 0 : 1; else funk2 = (speed < 0) ? -1 : 0; trackLinksLeft[i].zRot = Lerp(trackLinksLeft[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); } for(int i = 0; i < trackLinksRight.length; i++) { trackLinksRight[i].prevPosition = trackLinksRight[i].position; trackLinksRight[i].prevZRot = trackLinksRight[i].zRot; float speed = throttle * 1.5F + (wheelsYaw / 12); trackLinksRight[i].progress += speed; if(trackLinksRight[i].progress > rightTrack.getTrackLength()) trackLinksRight[i].progress -= leftTrack.getTrackLength(); if(trackLinksRight[i].progress < 0) trackLinksRight[i].progress += rightTrack.getTrackLength(); trackLinksRight[i].position = rightTrack.getPositionOnTrack(trackLinksRight[i].progress); float newAngle = rotateTowards(rightTrack.points.get(rightTrack.getTrackPart(trackLinksRight[i].progress)), trackLinksRight[i].position); int part = rightTrack.getTrackPart(trackLinksRight[i].progress); if(funk) funk2 = (speed < 0) ? 0 : 1; else funk2 = (speed < 0) ? -1 : 0; trackLinksRight[i].zRot = Lerp(trackLinksRight[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); } } public float rotateTowards(Vector3f point, Vector3f original) { float angle = (float)Math.atan2(point.y - original.y, point.x - original.x); return angle; } public float Lerp(float start, float end, float percent) { float result = (start + percent * (end - start)); return result; } public static float Clamp(float val, float min, float max) { return Math.max(min, Math.min(max, val)); } private float averageAngles(float a, float b) { FlansMod.log.debug("Pre " + a + " " + b); float pi = (float)Math.PI; for(; a > b + pi; a -= 2 * pi) ; for(; a < b - pi; a += 2 * pi) ; float avg = (a + b) / 2F; for(; avg > pi; avg -= 2 * pi) ; for(; avg < -pi; avg += 2 * pi) ; FlansMod.log.debug("Post " + a + " " + b + " " + avg); return avg; } private Vec3d subtract(Vec3d a, Vec3d b) { return new Vec3d(a.x - b.x, a.y - b.y, a.z - b.z); } private Vec3d crossProduct(Vec3d a, Vec3d b) { return new Vec3d(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } @Override public boolean landVehicle() { return true; } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { if(world.isRemote || isDead) return true; VehicleType type = getVehicleType(); if(damagesource.damageType.equals("player") && damagesource.getTrueSource().onGround && (getSeat(0) == null || getSeat(0).getControllingPassenger() == null)) { ItemStack vehicleStack = new ItemStack(type.item, 1, driveableData.paintjobID); NBTTagCompound tags = new NBTTagCompound(); vehicleStack.setTagCompound(tags); driveableData.writeToNBT(tags); entityDropItem(vehicleStack, 0.5F); setDead(); } return true; } public VehicleType getVehicleType() { return VehicleType.getVehicle(driveableType); } @Override public float getPlayerRoll() { return axes.getRoll(); } @Override protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part) { } @Override public String getBombInventoryName() { return "Mines"; } @Override public String getMissileInventoryName() { return "Shells"; } @Override public boolean hasMouseControlMode() { return false; } @Override @SideOnly(Side.CLIENT) public EntityLivingBase getCamera() { return null; } @Override public void setDead() { super.setDead(); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EntityWheel.java ================================================ package com.flansmod.common.driveables; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import com.flansmod.common.FlansMod; import com.flansmod.common.vector.Vector3f; public class EntityWheel extends Entity implements IEntityAdditionalSpawnData { /** * The vehicle this wheel is part of */ public EntityDriveable vehicle; /** * The ID of this wheel within the vehicle */ private int ID; /** * The ID of the vehicle this wheel is part of, for client-server syncing */ private int vehicleID; public EntityWheel(World world) { super(world); setSize(1F, 1F); stepHeight = 1.0F; } public EntityWheel(World world, EntityDriveable entity, int i) { this(world); vehicle = entity; vehicleID = entity.getEntityId(); ID = i; initPosition(); } public void initPosition() { Vector3f wheelVector = vehicle.axes.findLocalVectorGlobally(vehicle.getDriveableType().wheelPositions[ID].position); setPosition(vehicle.posX + wheelVector.x, vehicle.posY + wheelVector.y, vehicle.posZ + wheelVector.z); stepHeight = vehicle.getDriveableType().wheelStepHeight; prevPosX = posX; prevPosY = posY; prevPosZ = posZ; } @Override public void fall(float k, float l) { if(vehicle == null || k <= 0) return; int i = MathHelper.ceil(k - 3F); if(i > 0) vehicle.attackPart(vehicle.getDriveableType().wheelPositions[ID].part, DamageSource.FALL, i); } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { DriveableType type = DriveableType.getDriveable(tags.getString("DriveableType")); ID = tags.getInteger("Index"); if(type == null) { FlansMod.log.warn("Killing wheel due to invalid type tag"); reallySetDead(); return; } if(getRidingEntity() instanceof EntityDriveable) { vehicle = (EntityDriveable)getRidingEntity(); vehicle.registerWheel(this); } } @Override protected void writeEntityToNBT(NBTTagCompound tags) { if(vehicle != null) { tags.setString("DriveableType", vehicle.getDriveableType().shortName); tags.setInteger("Index", ID); } } @Override public void onUpdate() { if(vehicle == null || isDead) { if(getRidingEntity() instanceof EntityDriveable) { vehicle = (EntityDriveable)getRidingEntity(); vehicle.registerWheel(this); } return; } if(!addedToChunk) { world.spawnEntity(this); } } @Override public void setDead() { // No chance. You do not have the power } @Override public boolean canBeCollidedWith() { return !isDead; } public void reallySetDead() { super.setDead(); } public double getSpeedXZ() { return Math.sqrt(motionX * motionX + motionZ * motionZ); } @Override public void setPositionAndRotationDirect(double d, double d1, double d2, float f, float f1, int i, boolean b) { } @Override public void writeSpawnData(ByteBuf data) { data.writeInt(vehicleID); data.writeInt(ID); } @Override public void readSpawnData(ByteBuf data) { vehicleID = data.readInt(); ID = data.readInt(); if(world.getEntityByID(vehicleID) instanceof EntityDriveable) vehicle = (EntityDriveable)world.getEntityByID(vehicleID); setPosition(posX, posY, posZ); } public int getExpectedWheelID() { return ID; } @Override public void updateRidden() { if(!updateBlocked) onUpdate(); if(isRiding()) { getRidingEntity().updatePassenger(this); } } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EnumDriveablePart.java ================================================ package com.flansmod.common.driveables; import java.util.ArrayList; public enum EnumDriveablePart { //Plane parts tailWheel(new EnumDriveablePart[]{}, "tailWheel", "Wheel (Tail)"), tail(new EnumDriveablePart[]{tailWheel}, "tail", "Tail"), bay(new EnumDriveablePart[]{tail}, "bay", "Bay"), topWing(new EnumDriveablePart[]{}, "topWing", "Top Wing"), leftWingWheel(new EnumDriveablePart[]{}, "leftWingWheel", "Wheel (Left Wing)"), leftWing(new EnumDriveablePart[]{topWing, leftWingWheel}, "leftWing", "Left Wing"), rightWingWheel(new EnumDriveablePart[]{}, "rightWingWheel", "Wheel (Right Wing)"), rightWing(new EnumDriveablePart[]{topWing, rightWingWheel}, "rightWing", "Right Wing"), nose(new EnumDriveablePart[]{}, "nose", "Nose"), coreWheel(new EnumDriveablePart[]{}, "coreWheel", "Wheel (Core)"), //Helicopter parts skids(new EnumDriveablePart[]{}, "skids", "Skids"), blades(new EnumDriveablePart[]{}, "blades", "Blades"), //Vehicle parts turret(new EnumDriveablePart[]{}, "turret", "Turret"), backWheel(new EnumDriveablePart[]{}, "backWheel", "Back Wheel"), frontWheel(new EnumDriveablePart[]{}, "frontWheel", "Front Wheel"), backLeftWheel(new EnumDriveablePart[]{}, "backLeftWheel", "Back Left Wheel"), frontLeftWheel(new EnumDriveablePart[]{}, "frontLeftWheel", "Front Left Wheel"), backRightWheel(new EnumDriveablePart[]{}, "backRightWheel", "Back Right Wheel"), frontRightWheel(new EnumDriveablePart[]{}, "frontRightWheel", "Front Right Wheel"), leftTrack(new EnumDriveablePart[]{}, "leftTrack", "Left Track"), rightTrack(new EnumDriveablePart[]{}, "rightTrack", "Right Track"), trailer(new EnumDriveablePart[]{}, "trailer", "Trailer"), harvester(new EnumDriveablePart[]{}, "harvester", "Harvester"), //This is the drill bit, combine blades or excavator for utility vehicles //Mecha parts leftArm(new EnumDriveablePart[]{}, "leftArm", "Left Arm"), rightArm(new EnumDriveablePart[]{}, "rightArm", "Right Arm"), head(new EnumDriveablePart[]{}, "head", "Head"), hips(new EnumDriveablePart[]{}, "hips", "Hips"), barrel(new EnumDriveablePart[]{}, "barrel", "Barrel"), //Shared part core(new EnumDriveablePart[]{bay, leftWing, rightWing, nose, turret, coreWheel, leftArm, rightArm, head, hips, blades, skids, backWheel, frontWheel, backLeftWheel, frontLeftWheel, backRightWheel, frontRightWheel, leftTrack, rightTrack, trailer, harvester}, "core", "Core"); private String shortName; private String name; private EnumDriveablePart[] children; EnumDriveablePart(EnumDriveablePart[] parts, String s, String s2) { children = parts; shortName = s; name = s2; } /** * Used to determine what falls off when this part is broken */ public EnumDriveablePart[] getChildren() { return children; } /** * Used to determine when parts can be stuck back on */ public EnumDriveablePart[] getParents() { ArrayList parents = new ArrayList<>(); for(EnumDriveablePart part : values()) { for(EnumDriveablePart childPart : part.getChildren()) { if(childPart == this) parents.add(part); } } return parents.toArray(new EnumDriveablePart[parents.size()]); } public String getShortName() { return shortName; } public String getName() { return name; } /** * For reading parts from driveable files */ public static EnumDriveablePart getPart(String s) { for(EnumDriveablePart part : values()) if(part.getShortName().equals(s)) return part; return null; } public static boolean isWheel(EnumDriveablePart part) { return part == coreWheel || part == tailWheel || part == leftWingWheel || part == rightWingWheel; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EnumPlaneMode.java ================================================ package com.flansmod.common.driveables; public enum EnumPlaneMode { PLANE, VTOL, HELI; public static EnumPlaneMode getMode(String s) { if(s.toLowerCase().equals("vtol")) return VTOL; if(s.toLowerCase().equals("heli")) return HELI; return PLANE; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/EnumWeaponType.java ================================================ package com.flansmod.common.driveables; public enum EnumWeaponType { MISSILE, BOMB, SHELL, MINE, GUN, NONE } ================================================ FILE: src/main/java/com/flansmod/common/driveables/ItemPlane.java ================================================ package com.flansmod.common.driveables; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; public class ItemPlane extends Item implements IPaintableItem { public PlaneType type; public ItemPlane(PlaneType type1) { maxStackSize = 1; type = type1; type.item = this; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanDriveables); } @Override /** Make sure client and server side NBTtags update */ public boolean getShareTag() { return true; } private NBTTagCompound getTagCompound(ItemStack stack, World world) { if(stack.getTagCompound() == null) { if(!world.isRemote && stack.getItemDamage() != 0) stack.setTagCompound(getOldTagCompound(stack, world)); if(stack.getTagCompound() == null) { NBTTagCompound tags = new NBTTagCompound(); stack.setTagCompound(tags); tags.setString("Type", type.shortName); tags.setString("Engine", PartType.defaultEngines.get(EnumType.plane).shortName); } } return stack.getTagCompound(); } private NBTTagCompound getOldTagCompound(ItemStack stack, World world) { try { File file1 = world.getSaveHandler().getMapFileFromName("plane_" + stack.getItemDamage()); if(file1 != null && file1.exists()) { FileInputStream fileinputstream = new FileInputStream(file1); NBTTagCompound tags = CompressedStreamTools.readCompressed(fileinputstream).getCompoundTag("data"); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } fileinputstream.close(); return tags; } } catch(IOException e) { FlansMod.log.error("Failed to read old vehicle file"); FlansMod.log.throwing(e); } return null; } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { NBTTagCompound tags = getTagCompound(stack, world); String engineName = tags.getString("Engine"); PartType part = PartType.getPart(engineName); if(part != null) lines.add(part.name); } @Override public ActionResult onItemRightClick(World world, EntityPlayer entityplayer, EnumHand hand) { ItemStack itemstack = entityplayer.getHeldItem(hand); //Raytracing float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F); float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F); double length = 5D; Vec3d posVec = new Vec3d(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ); Vec3d lookVec = posVec.add(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length); RayTraceResult RayTraceResult = world.rayTraceBlocks(posVec, lookVec, type.placeableOnWater); //Result check if(RayTraceResult == null) { return new ActionResult<>(EnumActionResult.PASS, itemstack); } if(RayTraceResult.typeOfHit == Type.BLOCK) { BlockPos pos = RayTraceResult.getBlockPos(); Block block = world.getBlockState(pos).getBlock(); if(type.placeableOnLand || block instanceof BlockLiquid) { if(!world.isRemote) { DriveableData data = getPlaneData(itemstack, world); if(data != null) world.spawnEntity(new EntityPlane(world, (double)pos.getX() + 0.5F, (double)pos.getY() + 2.5F, (double)pos.getZ() + 0.5F, entityplayer, type, data)); } if(!entityplayer.capabilities.isCreativeMode) { itemstack.setCount(itemstack.getCount() - 1); } return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } } return new ActionResult<>(EnumActionResult.PASS, itemstack); } public Entity spawnPlane(World world, double x, double y, double z, ItemStack stack) { DriveableData data = getPlaneData(stack, world); if(data != null) { Entity entity = new EntityPlane(world, x, y, z, type, data); if(!world.isRemote) { world.spawnEntity(entity); } return entity; } return null; } public DriveableData getPlaneData(ItemStack itemstack, World world) { return new DriveableData(getTagCompound(itemstack, world), itemstack.getItemDamage()); } /** * Make sure that creatively spawned planes have nbt data */ @Override public void getSubItems(CreativeTabs tab, NonNullList items) { if(tab != FlansMod.tabFlanDriveables && tab != CreativeTabs.SEARCH) return; ItemStack planeStack = new ItemStack(this, 1, 0); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Type", type.shortName); if(PartType.defaultEngines.containsKey(EnumType.plane)) tags.setString("Engine", PartType.defaultEngines.get(EnumType.plane).shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } planeStack.setTagCompound(tags); items.add(planeStack); } @Override public InfoType getInfoType() { return type; } @Override public PaintableType GetPaintableType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/ItemVehicle.java ================================================ package com.flansmod.common.driveables; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemMapBase; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; public class ItemVehicle extends ItemMapBase implements IPaintableItem { public VehicleType type; public ItemVehicle(VehicleType type1) { maxStackSize = 1; type = type1; type.item = this; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanDriveables); } @Override /** Make sure client and server side NBTtags update */ public boolean getShareTag() { return true; } private NBTTagCompound getTagCompound(ItemStack stack, World world) { if(stack.getTagCompound() == null) { if(!world.isRemote && stack.getItemDamage() != 0) stack.setTagCompound(getOldTagCompound(stack, world)); if(stack.getTagCompound() == null) { NBTTagCompound tags = new NBTTagCompound(); stack.setTagCompound(tags); tags.setString("Type", type.shortName); tags.setString("Engine", PartType.defaultEngines.get(EnumType.vehicle).shortName); } } return stack.getTagCompound(); } private NBTTagCompound getOldTagCompound(ItemStack stack, World world) { try { File file1 = world.getSaveHandler().getMapFileFromName("vehicle_" + stack.getItemDamage()); FileInputStream fileinputstream = new FileInputStream(file1); NBTTagCompound tags = CompressedStreamTools.readCompressed(fileinputstream).getCompoundTag("data"); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } fileinputstream.close(); return tags; } catch(IOException e) { FlansMod.log.error("Failed to read old vehicle file"); FlansMod.log.throwing(e); return null; } } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } NBTTagCompound tags = getTagCompound(stack, world); String engineName = tags.getString("Engine"); PartType part = PartType.getPart(engineName); if(part != null) lines.add(part.name); } @Override public ActionResult onItemRightClick(World world, EntityPlayer entityplayer, EnumHand hand) { ItemStack itemstack = entityplayer.getHeldItem(hand); //Raytracing float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F); float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F); double length = 5D; Vec3d posVec = new Vec3d(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ); Vec3d lookVec = posVec.add(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length); RayTraceResult RayTraceResult = world.rayTraceBlocks(posVec, lookVec, type.placeableOnWater); //Result check if(RayTraceResult == null) { return new ActionResult<>(EnumActionResult.PASS, itemstack); } if(RayTraceResult.typeOfHit == Type.BLOCK) { BlockPos pos = RayTraceResult.getBlockPos(); Block block = world.getBlockState(pos).getBlock(); if(type.placeableOnLand || block instanceof BlockLiquid) { if(!world.isRemote) { world.spawnEntity(new EntityVehicle(world, (double)pos.getX() + 0.5F, (double)pos.getY() + 2.5F, (double)pos.getZ() + 0.5F, entityplayer, type, getData(itemstack, world))); } if(!entityplayer.capabilities.isCreativeMode) { itemstack.setCount(itemstack.getCount() - 1); } } return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } return new ActionResult<>(EnumActionResult.PASS, itemstack); } public Entity spawnVehicle(World world, double x, double y, double z, ItemStack stack) { Entity entity = new EntityVehicle(world, x, y, z, type, getData(stack, world)); if(!world.isRemote) { world.spawnEntity(entity); } return entity; } public DriveableData getData(ItemStack itemstack, World world) { return new DriveableData(getTagCompound(itemstack, world), itemstack.getItemDamage()); } /** * Make sure that creatively spawned planes have nbt data */ @Override public void getSubItems(CreativeTabs tab, NonNullList items) { if(tab != FlansMod.tabFlanDriveables && tab != CreativeTabs.SEARCH) return; ItemStack planeStack = new ItemStack(this, 1, 0); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Type", type.shortName); if(PartType.defaultEngines.containsKey(EnumType.vehicle)) tags.setString("Engine", PartType.defaultEngines.get(EnumType.vehicle).shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } planeStack.setTagCompound(tags); items.add(planeStack); } @Override public InfoType getInfoType() { return type; } @Override public PaintableType GetPaintableType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/PilotGun.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.guns.GunType; import com.flansmod.common.vector.Vector3f; public class PilotGun extends DriveablePosition { /** * The gun type used by this pilot gun */ public GunType type; public PilotGun(String[] split) { super(new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F), EnumDriveablePart.getPart(split[4])); type = GunType.getGun(split[5]); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/PlaneType.java ================================================ package com.flansmod.common.driveables; import java.util.ArrayList; import java.util.HashMap; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.client.model.ModelPlane; import com.flansmod.common.FlansMod; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.types.InfoType.ParseFunc; import com.flansmod.common.vector.Vector3f; public class PlaneType extends DriveableType { /** * What type of flying vehicle is this? */ public EnumPlaneMode mode = EnumPlaneMode.PLANE; /** * Pitch modifiers */ public float lookDownModifier = 1F, lookUpModifier = 1F; /** * Roll modifiers */ public float rollLeftModifier = 1F, rollRightModifier = 1F; /** * Yaw modifiers */ public float turnLeftModifier = 1F, turnRightModifier = 1F; /** * Co-efficient of lift which determines how the plane flies */ public float lift = 1F; /** * The point at which bomb entities spawn */ public Vector3f bombPosition; /** * The time in ticks between bullets fired by the nose / wing guns */ public int planeShootDelay; /** * The time in ticks between bombs dropped */ public int planeBombDelay; /** * The positions, parent parts and recipe items of the propellers, used to calculate forces and render the plane correctly */ public ArrayList propellers = new ArrayList<>(); /** * The positions, parent parts and recipe items of the helicopter propellers, used to calculate forces and render the plane correctly */ public ArrayList heliPropellers = new ArrayList<>(), heliTailPropellers = new ArrayList<>(); /** * Aesthetic features */ public boolean hasGear = false, hasDoor = false, hasWing = false; /** * Default pitch for when parked. Will implement better system soon */ public float restingPitch = 0F; /** * Whether the player can access the inventory while in the air */ public boolean invInflight = true; public static ArrayList types = new ArrayList<>(); private static HashMap> parsers = new HashMap<>(); static { // Plane / Heli Mode parsers.put("Mode", (split, d) -> d.mode = EnumPlaneMode.getMode(split[1])); // Yaw modifiers parsers.put("TurnLeftSpeed", (split, d) -> d.turnLeftModifier = Float.parseFloat(split[1])); parsers.put("TurnRightSpeed", (split, d) -> d.turnRightModifier = Float.parseFloat(split[1])); // Pitch modifiers parsers.put("LookUpSpeed", (split, d) -> d.lookUpModifier = Float.parseFloat(split[1])); parsers.put("LookDownSpeed", (split, d) -> d.lookDownModifier = Float.parseFloat(split[1])); // Roll modifiers parsers.put("RollLeftSpeed", (split, d) -> d.rollLeftModifier = Float.parseFloat(split[1])); parsers.put("RollRightSpeed", (split, d) -> d.rollRightModifier = Float.parseFloat(split[1])); // Lift parsers.put("Lift", (split, d) -> d.lift = Float.parseFloat(split[1])); // Armaments parsers.put("ShootDelay", (split, d) -> d.planeShootDelay = Integer.parseInt(split[1])); parsers.put("BombDelay", (split, d) -> d.planeBombDelay = Integer.parseInt(split[1])); // Propellers parsers.put("Propeller", (split, d) -> { Propeller propeller = new Propeller(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]), EnumDriveablePart.getPart(split[5]), PartType.getPart(split[6])); d.propellers.add(propeller); d.driveableRecipe.add(new ItemStack(propeller.itemType.item)); }); parsers.put("HeliPropeller", (split, d) -> { Propeller propeller = new Propeller(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]), EnumDriveablePart.getPart(split[5]), PartType.getPart(split[6])); d.heliPropellers.add(propeller); d.driveableRecipe.add(new ItemStack(propeller.itemType.item)); }); parsers.put("HeliTailPropeller", (split, d) -> { Propeller propeller = new Propeller(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]), EnumDriveablePart.getPart(split[5]), PartType.getPart(split[6])); d.heliTailPropellers.add(propeller); d.driveableRecipe.add(new ItemStack(propeller.itemType.item)); }); // Sound parsers.put("PropSoundLength", (split, d) -> d.engineSoundLength = Integer.parseInt(split[1])); parsers.put("PropSound", (split, d) -> { d.engineSound = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ShootSound", (split, d) -> { d.shootSoundPrimary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("BombSound", (split, d) -> { d.shootSoundSecondary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); // Aesthetics parsers.put("HasGear", (split, d) -> d.hasGear = Boolean.parseBoolean(split[1])); parsers.put("HasDoor", (split, d) -> d.hasDoor = Boolean.parseBoolean(split[1])); parsers.put("HasWing", (split, d) -> d.hasWing = Boolean.parseBoolean(split[1])); parsers.put("RestingPitch", (split, d) -> d.restingPitch = Float.parseFloat(split[1])); parsers.put("InflightInventory", (split, d) -> d.invInflight = Boolean.parseBoolean(split[1])); } @Override protected void read(String[] split, TypeFile file) { try { ParseFunc parser = parsers.get(split[0]); if(parser != null) { parser.Parse(split, this); } else { super.read(split, file); } } catch(Exception ignored) { } } public PlaneType(TypeFile file) { super(file); types.add(this); } @Override public void preRead(TypeFile file) { super.preRead(file); } @Override public int numEngines() { switch(mode) { case VTOL: return Math.max(propellers.size(), heliPropellers.size()); case PLANE: return propellers.size(); case HELI: return heliPropellers.size(); default: return 1; } } /** * Find the items needed to rebuild a part. The returned array is disconnected from the template items it has looked up */ @Override public ArrayList getItemsRequired(DriveablePart part, PartType engine) { //Get the list of items required by the driveable ArrayList stacks = super.getItemsRequired(part, engine); //Add the propellers and engines for(Propeller propeller : propellers) { if(propeller.planePart == part.type) { stacks.add(new ItemStack(propeller.itemType.item)); stacks.add(new ItemStack(engine.item)); } } return stacks; } public static PlaneType getPlane(String find) { for(PlaneType type : types) { if(type.shortName.equals(find)) return type; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelPlane.class); } @Override public EntityDriveable createDriveable(World world, double x, double y, double z, DriveableData data) { return new EntityPlane(world, x, y, z, this, data); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/Propeller.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.parts.PartType; import com.flansmod.common.vector.Vector3f; public class Propeller { /** * For crafting and plane destruction */ public PartType itemType; /** * For rendering propellers. Refers to the position in the propellerModel array */ public int ID; /** * Position of the propeller on the plane in model co-ordinates for thrust calculations */ public int x, y, z; /** * Part of the plane it is connected to, for partial plane destruction purposes */ public EnumDriveablePart planePart; public Propeller(int i, int x, int y, int z, EnumDriveablePart part, PartType type) { ID = i; this.x = x; this.y = y; this.z = z; planePart = part; itemType = type; } public Vector3f getPosition() { return new Vector3f(x / 16F, y / 16F, z / 16F); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/Seat.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.guns.GunType; import com.flansmod.common.vector.Vector3f; public class Seat { /** * The x, y and z positions of the seat within the plane in model co-ordinates * x is forwards, y is up and z is left */ public int x, y, z; /** * The id of this seat */ public int id; /** * Limits for the look vector of the seat. Range is -360 to 360. Thus any range should lie in here without having to wrap */ public float minYaw = -360F, maxYaw = 360F; /** * Limits for the look vector of the seat. Range is -90 to 90, but don't go beyond +/-89 or the view will mess up at the poles */ public float minPitch = -89F, maxPitch = 89F; /** * The gun this seat requires. As of 1.6.2, seats and planes will require specific guns as opposed to being completely open to anything */ public GunType gunType; /** * The name of the gun model this seat is connected to. Gun model names are specified in the model files */ public String gunName; /** * The part of the driveable this seat is connected to. */ public EnumDriveablePart part; /** * Auto assigned by driveable type. Indicates what ammo slot the gun should take from */ public int gunnerID; /** * For turret mounted seats on tanks, the seat will be positioned differently according to this offset and the yaw of the turret */ public Vector3f rotatedOffset = new Vector3f(); /** * Yaw/Pitch rotation speeds (Yaw/Pitch/z) where Z is ignored */ public Vector3f aimingSpeed = new Vector3f(1f, 1f, 0f); /** * Where the bullets come from */ public Vector3f gunOrigin = new Vector3f(); /** * Legacy aiming mode */ public boolean legacyAiming = false; /** * Traverse Yaw before pitching */ public boolean yawBeforePitch = false; /** * Pitches gun at the last second */ public boolean latePitch = true; /** * Does the turret have traverse sounds? */ public boolean traverseSounds = false; public String yawSound; public int yawSoundLength; public String pitchSound; public int pitchSoundLength; /** * Type file constructor. Line from type file should be of one of the following forms * Passenger ID x y z * Passenger ID x y z minYaw maxYaw minPitch maxPitch * Passenger ID x y z minYaw maxYaw minPitch maxPitch gunType.shortName gunName */ public Seat(String[] split) { id = Integer.parseInt(split[1]); x = Integer.parseInt(split[2]); y = Integer.parseInt(split[3]); z = Integer.parseInt(split[4]); gunOrigin = new Vector3f(x, y, z); part = EnumDriveablePart.getPart(split[5]); if(split.length > 6) { minYaw = Float.parseFloat(split[6]); maxYaw = Float.parseFloat(split[7]); minPitch = Float.parseFloat(split[8]); maxPitch = Float.parseFloat(split[9]); if(split.length > 10) { gunType = GunType.getGun(split[10]); gunName = split[11]; } } } /** * Type file driver seat constructor. Line from type file should be of one of the following forms * Driver x y z * Pilot x y z */ public Seat(int dx, int dy, int dz) { id = 0; x = dx; y = dy; z = dz; part = EnumDriveablePart.core; } /** * Type file driver seat constructor with yaw and pitch limiters */ public Seat(int dx, int dy, int dz, float y1, float y2, float p1, float p2) { id = 0; x = dx; y = dy; z = dz; part = EnumDriveablePart.core; minYaw = y1; maxYaw = y2; minPitch = p1; maxPitch = p2; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/ShootPoint.java ================================================ package com.flansmod.common.driveables; import com.flansmod.common.vector.Vector3f; public class ShootPoint { public DriveablePosition rootPos; public Vector3f offPos; public ShootPoint(DriveablePosition driverPos, Vector3f offsetPos) { rootPos = driverPos; offPos = offsetPos; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/VehicleType.java ================================================ package com.flansmod.common.driveables; import java.util.ArrayList; import java.util.HashMap; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.client.model.ModelVehicle; import com.flansmod.common.FlansMod; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.types.InfoType.ParseFunc; public class VehicleType extends DriveableType { /** * Movement modifiers */ public float turnLeftModifier = 1F, turnRightModifier = 1F; /** * If true, this will crush any living entity under the wheels */ public boolean squashMobs = false; /** * If this is true, the vehicle will drive from all wheels */ public boolean fourWheelDrive = false; /** * If true, then wheels will rotate as the vehicle drives */ public boolean rotateWheels = false; /** * Tank movement system. Uses track collision box for thrust, rather than the wheels */ public boolean tank = false; /** * Aesthetic door variable */ public boolean hasDoor = false; public int trackLinkFix = 5; public boolean flipLinkFix = false; public static ArrayList types = new ArrayList<>(); private static HashMap> parsers = new HashMap<>(); static { parsers.put("SquashMobs", (split, d) -> d.squashMobs = Boolean.parseBoolean(split[1])); parsers.put("FourWheelDrive", (split, d) -> d.fourWheelDrive = Boolean.parseBoolean(split[1])); parsers.put("Tank", (split, d) -> d.tank = Boolean.parseBoolean(split[1])); parsers.put("TankMode", (split, d) -> d.tank = Boolean.parseBoolean(split[1])); parsers.put("HasDoor", (split, d) -> d.hasDoor = Boolean.parseBoolean(split[1])); parsers.put("RotateWheels", (split, d) -> d.rotateWheels = Boolean.parseBoolean(split[1])); parsers.put("TurnLeftSpeed", (split, d) -> d.turnLeftModifier = Float.parseFloat(split[1])); parsers.put("TurnRightSpeed", (split, d) -> d.turnRightModifier = Float.parseFloat(split[1])); parsers.put("ShootDelay", (split, d) -> d.shootDelaySecondary = Integer.parseInt(split[1])); parsers.put("ShellDelay", (split, d) -> d.shootDelayPrimary = Integer.parseInt(split[1])); parsers.put("ShellSound", (split, d) -> { d.shootSoundSecondary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); parsers.put("ShootSound", (split, d) -> { d.shootSoundPrimary = split[1]; FlansMod.proxy.loadSound(d.contentPack, "driveables", split[1]); }); } public VehicleType(TypeFile file) { super(file); types.add(this); } @Override public void preRead(TypeFile file) { super.preRead(file); wheelPositions = new DriveablePosition[4]; } @Override protected void read(String[] split, TypeFile file) { try { ParseFunc parser = parsers.get(split[0]); if(parser != null) { parser.Parse(split, this); } else { super.read(split, file); } } catch(Exception ignored) { } } /** * Find the items needed to rebuild a part. The returned array is disconnected from the template items it has looked * up */ @Override public ArrayList getItemsRequired(DriveablePart part, PartType engine) { //Get the list of items required by the driveable ArrayList stacks = super.getItemsRequired(part, engine); //Add the propellers and engines if(EnumDriveablePart.core == part.type) { stacks.add(new ItemStack(engine.item)); } return stacks; } public static VehicleType getVehicle(String find) { for(VehicleType type : types) { if(type.shortName.equals(find)) return type; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelVehicle.class); } @Override public EntityDriveable createDriveable(World world, double x, double y, double z, DriveableData data) { return new EntityVehicle(world, x, y, z, this, data); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/collisions/CollisionPlane.java ================================================ package com.flansmod.common.driveables.collisions; import com.flansmod.common.vector.Vector3f; public class CollisionPlane { public float[] equation; public Vector3f normal; public Vector3f origin; public CollisionPlane(Vector3f origin, Vector3f normal) { this.origin = origin; this.normal = normal; equation = new float[4]; equation[0] = normal.x; equation[1] = normal.y; equation[2] = normal.z; equation[3] = -(normal.x*origin.x + normal.y*origin.y + normal.z*origin.z); } //Plane constructor using vertex co-ordinates of a triangle public CollisionPlane(Vector3f p1, Vector3f p2, Vector3f p3) { Vector3f edge1 = Vector3f.sub(p2, p1, null); Vector3f edge2 = Vector3f.sub(p3, p1, null); normal = Vector3f.cross(edge1, edge2, null); normal.normalise(); origin = p1; equation = new float[4]; equation[0] = normal.x; equation[1] = normal.y; equation[2] = normal.z; equation[3] = -(normal.x*origin.x + normal.y*origin.y + normal.z*origin.z); } //Which way are we facing? public boolean isFrontFacingTo(Vector3f direction) { double dot = Vector3f.dot(normal, direction); return (dot <= 0); } public double signedDistanceTo(Vector3f point) { return Vector3f.dot(point, normal) + equation[3]; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/collisions/CollisionShapeBox.java ================================================ package com.flansmod.common.driveables.collisions; import com.flansmod.common.vector.Vector3f; public class CollisionShapeBox { public Vector3f pos, size; public Vector3f p1,p2,p3,p4,p5,p6,p7,p8; public String part; public CollisionShapeBox(Vector3f position, Vector3f boxsize, Vector3f p1mod, Vector3f p2mod, Vector3f p3mod, Vector3f p4mod, Vector3f p5mod, Vector3f p6mod, Vector3f p7mod, Vector3f p8mod, String driveablePart) { this.pos = new Vector3f(position.x/16, -(position.y)/16 - (10F/16F), position.z/16); this.size = new Vector3f(boxsize.x/16, boxsize.y/16, boxsize.z/16); this.p1 = new Vector3f(p1mod.x/16, p1mod.y/16, p1mod.z/16); this.p2 = new Vector3f(p2mod.x/16, p2mod.y/16, p2mod.z/16); this.p3 = new Vector3f(p3mod.x/16, p3mod.y/16, p3mod.z/16); this.p4 = new Vector3f(p4mod.x/16, p4mod.y/16, p4mod.z/16); this.p5 = new Vector3f(p5mod.x/16, p5mod.y/16, p5mod.z/16); this.p6 = new Vector3f(p6mod.x/16, p6mod.y/16, p6mod.z/16); this.p7 = new Vector3f(p7mod.x/16, p7mod.y/16, p7mod.z/16); this.p8 = new Vector3f(p8mod.x/16, p8mod.y/16, p8mod.z/16); this.part = driveablePart; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/collisions/CollisionTest.java ================================================ package com.flansmod.common.driveables.collisions; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.vector.Vector3f; //Hi, I'm PrototypeTheta and welcome to jackass public class CollisionTest { //Radius vector set for the ellipsoid public Vector3f eRad; //Movement information in R3 (real) space public Vector3f R3Velocity; public Vector3f R3Position; //Movement information in ellipsoid space public Vector3f velocity; public Vector3f normalisedVelocity; public Vector3f basePoint; //Collision information public boolean didCollide; public double nearestDistance; public Vector3f intersectionPoint; public int collisionRecursiveDepth; public boolean isOnTop = false; public Vector3f collisionPlaneNormal; public EnumDriveablePart part; //Initial constructor, check triangles based on this. public CollisionTest(Vector3f ellipsoid, Vector3f origin, Vector3f motion) { this.eRad = ellipsoid; this.R3Velocity = motion; this.R3Position = origin; this.velocity = ConvertR3ToESpace(motion); this.normalisedVelocity = velocity.normalise(normalisedVelocity); this.basePoint = origin; } //I hope you like triangles, edgy comments and a metric fucktonne of maths. No apologies for the comments. public void checkTriangle(CollisionTest test, Vector3f p1, Vector3f p2, Vector3f p3) { CollisionPlane trianglePlane = new CollisionPlane(p1, p2, p3); //Is this triangle front facing to the velocity vector? If not, don't check it if(trianglePlane.isFrontFacingTo(test.normalisedVelocity)) { //Find interval of plane intersection double t0, t1; boolean embeddedInPlane = false; //Calculate signed distance from sphere position to triangle plane double signedDistToTrianglePlane = trianglePlane.signedDistanceTo(test.basePoint); float normalDotVelocity = Vector3f.dot(trianglePlane.normal, test.velocity); //If ellipsoid is travelling parallel to the triangular plane if(normalDotVelocity == 0.0F) { if(Math.abs(signedDistToTrianglePlane) >= 1.0F) { //Ellipsoid is not embedded in plane. No collision occurs return; } else { //Ellipsoid is embedded in plane. Fun. Intersects in the range [0..1] embeddedInPlane = true; t0 = 0.0; t1 = 1.0; } } else { //Movement is not parallel, calculate intersection interval t0 = (-1.0 - signedDistToTrianglePlane)/normalDotVelocity; t1 = (1.0 - signedDistToTrianglePlane)/normalDotVelocity; //Swap so t0 < t1 if(t0 > t1) { double temp = t1; t1 = t0; t0 = temp; } //Check that there is at least one possible result if(t0 > 1.0F || t1 < 0.0F) { //Both t values are outside of our range, no collision occurs return; } //Clamp to [0,1] There is probably a pre-built function for this but I forgot lol if(t0 < 0.0) t0 = 0.0; if(t1 < 0.0) t1 = 0.0; if(t0 > 1.0) t0 = 1.0; if(t1 > 1.0) t1 = 1.0; } //At this point we have the two time values t0 and t1 between which the swept sphere intersects the triangular plane. //All collision happens in this interval Vector3f collisionPoint = new Vector3f(0,0,0); boolean foundCollision = false; float t = 1.0F; //First check for collision inside the triangle. This must happen at t0 and only when the sphere is not embedded if(!embeddedInPlane) { Vector3f baseSubNormal = Vector3f.sub(this.basePoint, trianglePlane.normal, null); Vector3f planeIntersectionPoint = Vector3f.add(baseSubNormal, new Vector3f(t0*test.velocity.x, t0*test.velocity.y, t0*test.velocity.z), null); if(checkPointInTriangle(planeIntersectionPoint, p1, p2, p3)) { foundCollision = true; t = (float)t0; collisionPoint = planeIntersectionPoint; } } //If no collision found, sweep sphere against points and edges of the triangle if(!foundCollision) { Vector3f velocity = test.velocity; Vector3f base = test.basePoint; float velocitySquaredLength = velocity.lengthSquared(); float a,b,c; //Paramaters for equation float newT; //For each vertex or edge, a quadratic equation must be solved. Paramaterise this as a*t^2 + bt + c = 0 //Calculate paramaters for each case a = velocitySquaredLength; //P1 Vector3f baseSubP1 = Vector3f.sub(base, p1, null); b = 2*Vector3f.dot(velocity, baseSubP1); c = baseSubP1.lengthSquared() - 1; if(getLowestRoot(a,b,c,t) != 123456789) { t = getLowestRoot(a,b,c,t); foundCollision = true; collisionPoint = p1; } //P2 Vector3f baseSubP2 = Vector3f.sub(base, p2, null); b = 2*Vector3f.dot(velocity, baseSubP2); c = baseSubP2.lengthSquared(); if(getLowestRoot(a,b,c,t) != 123456789) { t = getLowestRoot(a,b,c,t); foundCollision = true; collisionPoint = p2; } //P3 Vector3f baseSubP3 = Vector3f.sub(base, p3, null); b = 2*Vector3f.dot(velocity, baseSubP3); c = baseSubP3.lengthSquared(); if(getLowestRoot(a,b,c,t) != 123456789) { t = getLowestRoot(a,b,c,t); foundCollision = true; collisionPoint = p3; } //Time to get edgy. By which I mean we check the edges for collisions. Put the razor blade down please. //P1 -> P2 Vector3f edge = Vector3f.sub(p2, p1, null); Vector3f baseToVertex = Vector3f.sub(p1, base, null); float edgeSquaredLength = edge.lengthSquared(); float edgeDotVelocity = Vector3f.dot(edge, velocity); float edgeDotBaseToVertex = Vector3f.dot(edge, baseToVertex); //CRAAAAAAAAAAWWWWWWWWWWWWWWWWLLLLLLLLLLLLLLLLLLLLLLIIIIIIIIIIIIIIIIINNNNNNNG IIIIIIIINNN MY SKIIIIIIIN //Now, calculate paramaters for the equation a = (edgeSquaredLength*(-velocitySquaredLength)) + (edgeDotVelocity*edgeDotVelocity); b = (edgeSquaredLength*(2*Vector3f.dot(velocity, baseToVertex)))-(2*edgeDotVelocity*edgeDotBaseToVertex); c = (edgeSquaredLength*(1-baseToVertex.lengthSquared())) + (edgeDotBaseToVertex*edgeDotBaseToVertex); //Does the swept sphere collide against the infinite edge of the comments section on a Linkin park video? if(getLowestRoot(a,b,c,t) != 123456789) { //Check if intersection is within line segment newT = getLowestRoot(a,b,c,t); float f = (edgeDotVelocity * newT - edgeDotBaseToVertex)/edgeSquaredLength; if(f >= 0.0 && f <= 1.0) { //Intersection took place within segment t = newT; foundCollision = true; collisionPoint = Vector3f.add(p1, new Vector3f(f*edge.x, f*edge.y, f*edge.z), null); } } //THEEESE WOUNDS THEY WIIIILLL NO HEEAAAAAAAAL //P2 -> P3 edge = Vector3f.sub(p3, p2, null); baseToVertex = Vector3f.sub(p2, base, null); edgeSquaredLength = edge.lengthSquared(); edgeDotVelocity = Vector3f.dot(edge, velocity); edgeDotBaseToVertex = Vector3f.dot(edge, baseToVertex); //Recalculate paramaters; a = (edgeSquaredLength*(-velocitySquaredLength)) + (edgeDotVelocity*edgeDotVelocity); b = (edgeSquaredLength*(2*Vector3f.dot(velocity, baseToVertex)))-(2*edgeDotVelocity*edgeDotBaseToVertex); c = (edgeSquaredLength*(1-baseToVertex.lengthSquared())) + (edgeDotBaseToVertex*edgeDotBaseToVertex); if(getLowestRoot(a,b,c,t) != 123456789) { //Check if intersection is within line segment newT = getLowestRoot(a,b,c,t); float f = (edgeDotVelocity * newT - edgeDotBaseToVertex)/edgeSquaredLength; if(f >= 0.0 && f <= 1.0) { //Intersection took place within segment t = newT; foundCollision = true; collisionPoint = Vector3f.add(p2, new Vector3f(f*edge.x, f*edge.y, f*edge.z), null); } } //FEAR IS HOW I FAAAAAAAAAAAAALLLLLLLLLL (still not apologising) //P3 -> P1 edge = Vector3f.sub(p1, p3, null); baseToVertex = Vector3f.sub(p3, base, null); edgeSquaredLength = edge.lengthSquared(); edgeDotVelocity = Vector3f.dot(edge, velocity); edgeDotBaseToVertex = Vector3f.dot(edge, baseToVertex); //Recalculate paramaters; a = (edgeSquaredLength*(-velocitySquaredLength)) + (edgeDotVelocity*edgeDotVelocity); b = (edgeSquaredLength*(2*Vector3f.dot(velocity, baseToVertex)))-(2*edgeDotVelocity*edgeDotBaseToVertex); c = (edgeSquaredLength*(1-baseToVertex.lengthSquared())) + (edgeDotBaseToVertex*edgeDotBaseToVertex); if(getLowestRoot(a,b,c,t) != 123456789) { //Check if intersection is within line segment newT = getLowestRoot(a,b,c,t); float f = (edgeDotVelocity * newT - edgeDotBaseToVertex)/edgeSquaredLength; if(f >= 0.0 && f <= 1.0) { //Intersection took place within segment t = newT; foundCollision = true; collisionPoint = Vector3f.add(p3, new Vector3f(f*edge.x, f*edge.y, f*edge.z), null); } } } //Set the result if(foundCollision) { //Distance to collision where t is the time of collision float distToCollision = t*test.velocity.length(); if(!test.didCollide || distToCollision < test.nearestDistance) { test.nearestDistance = distToCollision; test.intersectionPoint = collisionPoint; test.didCollide = true; } } } } public float getLowestRoot(float a, float b, float c, float maxR) { //Check if a solution exists float determinant = (b*b) - 4.0F*a*c; //If determinant is negative no solutions exist if(determinant < 0.0F) return 123456789; //Calculate the two roots float sqrtD = (float)Math.sqrt(determinant); float r1 = (-b - sqrtD)/(2*a); float r2 = (-b + sqrtD)/(2*a); //Sort so x1 <= x2 if(r1 > r2) { float temp = r2; r2 = r1; r1 = temp; } if(r1 > 0 && r1 < maxR) return r1; //It is possible we need x2, this can happen if x1 < 0 if(r2 > 0 && r2 < maxR) return r2; //If no valid solution, return a value of 123456789 as our failed number. If this actually is a valid solution then fuck me IDK what to do. return 123456789; } public boolean checkPointInTriangle(Vector3f point, Vector3f p1, Vector3f p2, Vector3f p3) { Vector3f edge1 = Vector3f.sub(p2, p1, null); Vector3f edge2 = Vector3f.sub(p3, p1, null); float a = Vector3f.dot(edge1, edge1); float b = Vector3f.dot(edge1, edge2); float c = Vector3f.dot(edge2, edge2); float acSUBbb = (a*c)-(b*b); Vector3f vp = new Vector3f(point.x - p1.x, point.y - p1.y, point.z - p1.z); float d = Vector3f.dot(vp, edge1); float e = Vector3f.dot(vp, edge2); float x = (d*c)-(e*b); float y = (e*a)-(d*b); float z = (x+y)-acSUBbb; return (z < 0 && x >= 0 && y >= 0); } public Vector3f ConvertR3ToESpace(Vector3f r3) { return new Vector3f((1/eRad.x)*r3.x,(1/eRad.y)*r3.y, (1/eRad.z)*r3.z); } public Vector3f ConvertESpaceToR3(Vector3f esp) { return new Vector3f(esp.x/(1/eRad.x),esp.y/(1/eRad.y), esp.z/(1/eRad.z)); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/collisions/RidingEntityPosition.java ================================================ package com.flansmod.common.driveables.collisions; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.vector.Vector3f; public class RidingEntityPosition { public Vector3f contactPos; public int contactSurface; public float distance; public EnumDriveablePart part; public RidingEntityPosition(float hitX, float hitY, float hitZ, int surface, double length, EnumDriveablePart type) { contactPos = new Vector3f(hitX, hitY, hitZ); contactSurface = surface; distance = (float)length; } public float length(Vector3f pos1, Vector3f pos2) { float result = (float)Math.sqrt(((pos1.x - pos2.x)*(pos1.x - pos2.x)) + ((pos1.y - pos2.y)*(pos1.y - pos2.y)) + ((pos1.z - pos2.z)*(pos1.z - pos2.z))); return result; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/ContainerMechaInventory.java ================================================ package com.flansmod.common.driveables.mechas; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class ContainerMechaInventory extends Container { public InventoryPlayer inventory; public World world; public EntityMecha mecha; public int numItems; public int maxScroll; public int scroll; public ContainerMechaInventory(InventoryPlayer inv, World w, EntityMecha em) { inventory = inv; world = w; mecha = em; numItems = mecha.getDriveableType().numCargoSlots; int numRows = ((numItems + 7) / 8); maxScroll = (numRows > 3 ? numRows - 3 : 0); int startSlot = mecha.driveableData.getCargoInventoryStart(); for(int row = 0; row < numRows; row++) { int yPos = -1000; if(row < 3 + scroll && row >= scroll) yPos = 25 + 19 * (row - scroll); for(int col = 0; col < ((row + scroll + 1) * 8 <= numItems ? 8 : numItems % 8); col++) { addSlotToContainer(new Slot(mecha.driveableData, startSlot + row * 8 + col, 186 + 18 * col, yPos)); } } //Equipment Slots addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.legs, 84, 128)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.hips, 60, 128)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.leftArm, 36, 80)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.leftTool, 36, 56)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.leftShoulder, 60, 32)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.head, 84, 32)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.feet, 108, 128)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.rightArm, 132, 80)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.rightTool, 132, 56)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.rightShoulder, 108, 32)); //Upgrade Slots addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.u1, 10, 32)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.u2, 10, 56)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.u3, 10, 80)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.u4, 10, 104)); addSlotToContainer(new SlotMecha(mecha.inventory, EnumMechaSlotType.u5, 10, 128)); //Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventory, col + row * 9 + 9, 182 + col * 18, 98 + row * 18)); } } //Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventory, col, 182 + col * 18, 156)); } } @Override public void onContainerClosed(EntityPlayer par1EntityPlayer) { super.onContainerClosed(par1EntityPlayer); mecha.couldNotFindFuel = false; } public void updateScroll(int scrololol) { scroll = scrololol; int m = ((numItems + 7) / 8); for(int row = 0; row < m; row++) { int yPos = -1000; if(row < 3 + scroll && row >= scroll) yPos = 25 + 19 * (row - scroll); for(int col = 0; col < ((row + 1) * 8 < numItems ? 8 : numItems % 8); col++) { inventorySlots.get(row * 8 + col).yPos = yPos; } } } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); ///if(stack.getItem() instanceof ItemMechaAddon) // { //((ItemMechaAddon)stack.getItem()).type; //} if(slotID >= numItems) { if(!mergeItemStack(slotStack, 0, numItems, false)) { return ItemStack.EMPTY.copy(); } } else { if(!mergeItemStack(slotStack, numItems, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return ItemStack.EMPTY.copy(); } currentSlot.onTake(player, slotStack); } return stack; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/EntityMecha.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.ArrayList; import java.util.Optional; import io.netty.buffer.ByteBuf; import io.vavr.Tuple; import io.vavr.Tuple3; import io.vavr.collection.List; import io.vavr.control.Option; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.MoverType; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.world.GameType; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.client.model.GunAnimations; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.FireableGun; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.InventoryHelper; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGrenade; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.network.PacketDriveableDamage; import com.flansmod.common.network.PacketDriveableGUI; import com.flansmod.common.network.PacketMechaControl; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; import com.flansmod.common.vector.Vector3i; import static com.flansmod.common.util.BlockUtil.destroyBlock; public class EntityMecha extends EntityDriveable { private int ticksSinceUsed; public int toggleTimer = 0; protected float moveX = 0; protected float moveZ = 0; public RotatedAxes legAxes; public float prevLegsYaw = 0F; private int jumpDelay = 0; public MechaInventory inventory; public float legSwing = 0; /** * Used for shooting guns */ public float shootDelayLeft = 0, shootDelayRight = 0; /** * Used for gun sounds */ public int soundDelayLeft = 0, soundDelayRight = 0; /** * The coords of the blocks being destroyed */ public Vector3i breakingBlock = null; /** * Progress made towards breaking each block */ public float breakingProgress = 0F; /** * Timer for the RocketPack Sound */ private float rocketTimer = 0F; private int diamondTimer = 0; /** * Gun animations */ public GunAnimations leftAnimations = new GunAnimations(), rightAnimations = new GunAnimations(); boolean couldNotFindFuel; public EntityPlayer placer; public float yOffset; public EntityMecha(World world) { super(world); setSize(2F, 3F); stepHeight = 3; legAxes = new RotatedAxes(); inventory = new MechaInventory(this); } public EntityMecha(World world, double x, double y, double z, MechaType type, DriveableData data, NBTTagCompound tags) { super(world, type, data); legAxes = new RotatedAxes(); setSize(2F, 3F); stepHeight = 3; setPosition(x, y, z); initType(type, true, false); inventory = new MechaInventory(this, tags); } public EntityMecha(World world, double x, double y, double z, EntityPlayer placer, MechaType type, DriveableData data, NBTTagCompound tags) { this(world, x, y, z, type, data, tags); rotateYaw(placer.rotationYaw + 90F); legAxes.rotateGlobalYaw(placer.rotationYaw + 90F); prevLegsYaw = legAxes.getYaw(); this.placer = placer; } @Override protected void initType(DriveableType type, boolean firstTime, boolean clientSide) { super.initType(type, firstTime, clientSide); setSize(((MechaType)type).width, ((MechaType)type).height); stepHeight = ((MechaType)type).stepHeight; } @Override protected void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); tag.setFloat("LegsYaw", legAxes.getYaw()); tag.setTag("Inventory", inventory.writeToNBT(new NBTTagCompound())); } @Override protected void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); legAxes.setAngles(tag.getFloat("LegsYaw"), 0, 0); inventory.readFromNBT(tag.getCompoundTag("Inventory")); } @Override public void writeSpawnData(ByteBuf data) { super.writeSpawnData(data); ByteBufUtils.writeTag(data, inventory.writeToNBT(new NBTTagCompound())); } @Override public void readSpawnData(ByteBuf data) { super.readSpawnData(data); legAxes.rotateGlobalYaw(axes.getYaw()); prevLegsYaw = legAxes.getYaw(); inventory.readFromNBT(ByteBufUtils.readTag(data)); } @Override public double getYOffset() { return yOffset; } @Override public void onMouseMoved(int deltaX, int deltaY) { } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) { if(isDead) return false; if(world.isRemote) return false; //If they are using a repair tool, don't put them in ItemStack currentItem = entityplayer.getHeldItemMainhand(); if(currentItem != null && currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables) return true; MechaType type = getMechaType(); //Check each seat in order to see if the player can sit in it for(int i = 0; i <= type.numPassengers; i++) { if(getSeat(i) != null && getSeat(i).processInitialInteract(entityplayer, hand)) return true; } return false; } public MechaType getMechaType() { return MechaType.getMecha(driveableType); } @Override @SideOnly(Side.CLIENT) public boolean pressKey(int key, EntityPlayer player, boolean isOnEvent) { MechaType type = getMechaType(); DriveableData data = getDriveableData(); //send keys which require server side updates to the server switch(key) { case 4: //Jump { boolean canThrustCreatively = getSeat(0) != null && getSeat(0).getControllingPassenger() instanceof EntityPlayer && ((EntityPlayer)getSeat(0).getControllingPassenger()).capabilities.isCreativeMode; if(onGround && (jumpDelay == 0) && (canThrustCreatively || data.fuelInTank > data.engine.fuelConsumption) && isPartIntact(EnumDriveablePart.hips)) { jumpDelay = 20; motionY += type.jumpVelocity; if(!canThrustCreatively) data.fuelInTank -= data.engine.fuelConsumption; } return true; } case 7: //Inventory { FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(4)); ((EntityPlayer)getSeat(0).getControllingPassenger()).openGui(FlansMod.INSTANCE, 10, world, chunkCoordX, chunkCoordY, chunkCoordZ); return true; } default: { return super.pressKey(key, player, isOnEvent); } } } protected boolean creative() { return !(getSeat(0).getControllingPassenger() instanceof EntityPlayer) || ((EntityPlayer)getSeat(0).getControllingPassenger()).capabilities.isCreativeMode; } protected boolean useItem(boolean left) { if(left ? isPartIntact(EnumDriveablePart.leftArm) : isPartIntact(EnumDriveablePart.rightArm)) { ItemStack heldStack = left ? inventory.getStackInSlot(EnumMechaSlotType.leftTool) : inventory.getStackInSlot(EnumMechaSlotType.rightTool); if(heldStack == null || heldStack.isEmpty()) return false; Item heldItem = heldStack.getItem(); MechaType mechaType = getMechaType(); if(heldItem instanceof ItemMechaAddon) { MechaItemType toolType = ((ItemMechaAddon)heldItem).type; float reach = toolType.reach * mechaType.reach; Vector3f lookOrigin = new Vector3f( (float)mechaType.seats[0].x / 16F, (float)mechaType.seats[0].y / 16F + getSeat(0).getControllingPassenger().getMountedYOffset(), (float)mechaType.seats[0].z / 16F); lookOrigin = axes.findLocalVectorGlobally(lookOrigin); Vector3f.add(lookOrigin, new Vector3f(posX, posY, posZ), lookOrigin); Vector3f lookVector = axes.findLocalVectorGlobally(getSeat(0).looking.findLocalVectorGlobally(new Vector3f(reach, 0F, 0F))); if(FlansMod.DEBUG && world.isRemote) world.spawnEntity(new EntityDebugVector(world, lookOrigin, lookVector, 20)); Vector3f lookTarget = Vector3f.add(lookVector, lookOrigin, null); RayTraceResult hit = world.rayTraceBlocks(lookOrigin.toVec3(), lookTarget.toVec3()); //RayTraceResult hit = ((EntityLivingBase)seats[0].riddenByEntity).rayTrace(reach, 1F); if(hit != null && hit.typeOfHit == Type.BLOCK) { BlockPos pos = hit.getBlockPos(); if(breakingBlock == null || breakingBlock.x != pos.getX() || breakingBlock.y != pos.getY() || breakingBlock.z != pos.getZ()) breakingProgress = 0F; breakingBlock = new Vector3i(pos.getX(), pos.getY(), pos.getZ()); } } else if(heldItem instanceof ItemGun) { ItemGun gunItem = (ItemGun)heldItem; GunType gunType = gunItem.GetType(); //Get the correct shoot delay float delay = left ? shootDelayLeft : shootDelayRight; //If we can shoot if(delay <= 0) { //Go through the bullet stacks in the gun and see if any of them are not null int bulletID = 0; ItemStack bulletStack = null; for(; bulletID < gunType.numAmmoItemsInGun; bulletID++) { ItemStack checkingStack = gunItem.getBulletItemStack(heldStack, bulletID); if(checkingStack != null && !checkingStack.isEmpty() && checkingStack.getItemDamage() < checkingStack.getMaxDamage()) { bulletStack = checkingStack; break; } } //If no bullet stack was found, reload if(bulletStack == null || bulletStack.isEmpty()) { gunItem.Reload(heldStack, world, this, driveableData, left ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND, true, true, (infiniteAmmo() || creative())); } //A bullet stack was found, so try shooting with it else if(bulletStack.getItem() instanceof ItemBullet || bulletStack.getItem() instanceof ItemGrenade) { //Shoot shoot(heldStack, gunType, bulletStack, creative(), left); //Apply animations to 3D modelled guns //TODO this doesn't work if(left) { leftAnimations.doShoot(gunType.getPumpDelay(), gunType.getPumpTime()); } else { rightAnimations.doShoot(gunType.getPumpDelay(), gunType.getPumpTime()); } //Damage the bullet item bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); //Update the stack in the gun gunItem.setBulletItemStack(heldStack, bulletStack, bulletID); } } } } return true; } private void shoot(ItemStack stack, GunType gunType, ItemStack bulletStack, boolean creative, boolean left) { EntitySeat seat = getSeat(0); if(seat == null) return; MechaType mechaType = getMechaType(); ShootableType bulletType = ((ItemShootable)bulletStack.getItem()).type; RotatedAxes a = new RotatedAxes(); Vector3f armVector = new Vector3f(mechaType.armLength, 0F, 0F); Vector3f gunVector = new Vector3f(mechaType.armLength + 1.2F * mechaType.heldItemScale, 0.5F * mechaType.heldItemScale, 0F); Vector3f armOrigin = left ? mechaType.leftArmOrigin : mechaType.rightArmOrigin; a.rotateGlobalYaw(axes.getYaw()); armOrigin = a.findLocalVectorGlobally(armOrigin); a.rotateLocalPitch(-seat.looking.getPitch()); gunVector = a.findLocalVectorGlobally(gunVector); armVector = a.findLocalVectorGlobally(armVector); Vector3f bulletOrigin = Vector3f.add(armOrigin, gunVector, null); bulletOrigin = Vector3f.add(new Vector3f(posX, posY, posZ), bulletOrigin, null); if(!world.isRemote) { ShootableType shootableType = ((ItemShootable)bulletStack.getItem()).type; if (shootableType instanceof BulletType) { FireableGun fireableGun = new FireableGun(gunType, gunType.getDamage(stack), gunType.getSpread(stack), gunType.getBulletSpeed(stack), gunType.getSpreadPattern(stack)); FiredShot shot = new FiredShot(fireableGun, (BulletType)shootableType, this, (EntityPlayerMP) getDriver()); ShotHandler.fireGun(world, shot, gunType.numBullets*bulletType.numBullets, bulletOrigin, armVector); } else if (shootableType instanceof GrenadeType) { double yaw = Math.atan2(armVector.z, armVector.x); double pitch = Math.atan2(Math.sqrt(armVector.z * armVector.z + armVector.x * armVector.x), armVector.y) - Math.PI/2; Optional ent = Optional.of(this); Optional player = Optional.ofNullable(getDriver()); EntityGrenade grenade = new EntityGrenade(world, bulletOrigin, (GrenadeType) shootableType, (float)Math.toDegrees(pitch), (float)Math.toDegrees(yaw + Math.PI*1.5), player, ent); world.spawnEntity(grenade); } } if(left) shootDelayLeft = gunType.mode == EnumFireMode.SEMIAUTO ? Math.max(gunType.GetShootDelay(stack), 5) : gunType.GetShootDelay(stack); else shootDelayRight = gunType.mode == EnumFireMode.SEMIAUTO ? Math.max(gunType.GetShootDelay(stack), 5) : gunType.GetShootDelay(stack); if(bulletType.dropItemOnShoot != null && !creative) ItemGun.dropItem(world, this, bulletType.dropItemOnShoot); // Play a sound if the previous sound has finished if((left ? soundDelayLeft : soundDelayRight) <= 0 && gunType.shootSound != null) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gunType.shootSound, gunType.distortSound); if(left) soundDelayLeft = gunType.shootSoundLength; else soundDelayRight = gunType.shootSoundLength; } } @Override public void fall(float f, float l) { attackEntityFrom(DamageSource.FALL, f); } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { if(world.isRemote || isDead) return true; MechaType type = getMechaType(); if(damagesource.getDamageType().equals("fall")) { boolean takeFallDamage = type.takeFallDamage && !stopFallDamage(); boolean damageBlocksFromFalling = type.damageBlocksFromFalling || breakBlocksUponFalling(); byte wouldBeNegativeDamage; if(((i * type.fallDamageMultiplier * vulnerability()) - 2) < 0) { wouldBeNegativeDamage = 0; } else { wouldBeNegativeDamage = 1; } float damageToInflict = takeFallDamage ? i * ((type.fallDamageMultiplier * vulnerability())) * wouldBeNegativeDamage : 0; float blockDamageFromFalling = damageBlocksFromFalling ? i * (type.blockDamageFromFalling) / 10F : 0; driveableData.parts.get(EnumDriveablePart.hips).attack(damageToInflict, false); checkParts(); FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); if(blockDamageFromFalling > 1) { world.createExplosion(this, posX, posY, posZ, blockDamageFromFalling, TeamsManager.explosions); } } else if(damagesource.damageType.equals("player") && damagesource.getTrueSource().onGround && (getSeat(0) == null || getSeat(0).getControllingPassenger() == null)) { ItemStack mechaStack = new ItemStack(type.item, 1, driveableData.paintjobID); NBTTagCompound tags = new NBTTagCompound(); mechaStack.setTagCompound(tags); driveableData.writeToNBT(tags); inventory.writeToNBT(tags); entityDropItem(mechaStack, 0.5F); setDead(); } else { driveableData.parts.get(EnumDriveablePart.core).attack(i * vulnerability(), damagesource.isFireDamage()); } return true; } @Override public void onUpdate() { super.onUpdate(); if(!readyForUpdates) return; EntitySeat driverSeat = getSeat(0); Entity driver = driverSeat == null ? null : driverSeat.getControllingPassenger(); EntityLivingBase livingDriver = driver instanceof EntityLivingBase ? (EntityLivingBase)driver : null; EntityPlayer playerDriver = driver instanceof EntityPlayer ? (EntityPlayer)driver : null; boolean isCreative = playerDriver != null && playerDriver.isCreative(); //Decrement delay variables updateDelays(); //If the player left the driver's seat, stop digging / whatever if(!world.isRemote && (driverSeat == null || driver == null)) primaryShootHeld = secondaryShootHeld = false; //Update gun animations leftAnimations.update(); rightAnimations.update(); //Get Mecha Type MechaType type = this.getMechaType(); DriveableData data = getDriveableData(); if(type == null) { FlansMod.log.warn("Mecha type null. Not ticking mecha"); return; } prevLegsYaw = legAxes.getYaw(); // Abilities autoRepair(playerDriver, isCreative, data); detectDiamonds(playerDriver); updateHeight(type); updateDespawn(driver); //Work out of this is client side and the player is driving boolean thePlayerIsDrivingThis = world.isRemote && FlansMod.proxy.isThePlayer(playerDriver); //Player is not driving this. Update its position from server update packets if(world.isRemote && !thePlayerIsDrivingThis) { //The driveable is currently moving towards its server position. Continue doing so. if(serverPositionTransitionTicker > 0) { moveTowardServerPosition(); } //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side driveable would, so continue } //Movement updateHeadPosition(driverSeat, livingDriver, playerDriver, type); moveX = 0; moveZ = 0; float jetPackPower = jetPackPower(); if(!onGround && thePlayerIsDrivingThis && FlansMod.proxy.isKeyDown(4) && shouldFly() && (isCreative || data.fuelInTank >= (10F * jetPackPower))) { motionY *= 0.95; motionY += (0.07 * jetPackPower); fallDistance = 0; if(!isCreative) { data.fuelInTank -= (10F * jetPackPower); } if(rocketTimer <= 0 && rocketPack().soundEffect != null) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, rocketPack().soundEffect, false); rocketTimer = rocketPack().soundTime; } } if(isInWater() && shouldFloat()) { motionY *= 0.89; motionY += 0.1; } Vector3f actualMotion = new Vector3f(0F, motionY - (16F / 400F), 0F); if(livingDriver != null) { if(thePlayerIsDrivingThis) { if(FlansMod.proxy.isKeyDown(0)) moveX = 1; if(FlansMod.proxy.isKeyDown(1)) moveX = -1; if(FlansMod.proxy.isKeyDown(2)) moveZ = -1; if(FlansMod.proxy.isKeyDown(3)) moveZ = 1; } else if(playerDriver == null) { moveZ = 1; } Vector3f intent = new Vector3f(moveX, 0, moveZ); if(Math.abs(intent.lengthSquared()) > 0.1) { intent.normalise(); ++legSwing; intent = axes.findLocalVectorGlobally(intent); Vector3f intentOnLegAxes = legAxes.findGlobalVectorLocally(intent); float intentAngle = (float)Math.atan2(intent.z, intent.x) * 180F / 3.14159265F; float angleBetween = intentAngle - legAxes.getYaw(); if(angleBetween > 180F) angleBetween -= 360F; if(angleBetween < -180F) angleBetween += 360F; float signBetween = Math.signum(angleBetween); angleBetween = Math.abs(angleBetween); if(angleBetween > 0.1) { legAxes.rotateGlobalYaw(Math.min(angleBetween, type.rotateSpeed) * signBetween); } intent.scale((type.moveSpeed * data.engine.engineSpeed * speedMultiplier()) * (4.3F / 20F)); if((isCreative || data.fuelInTank > data.engine.fuelConsumption) && isPartIntact(EnumDriveablePart.hips)) { if(!onGround && shouldFly() && (isCreative || data.fuelInTank > 10F * jetPackPower + data.engine.fuelConsumption)) { intent.scale(jetPackPower); if(!isCreative) data.fuelInTank -= 10F * jetPackPower; } //Move! Vector3f.add(actualMotion, intent, actualMotion); //If we can't thrust creatively, we must thrust using fuel. Nom. if(!isCreative) data.fuelInTank -= data.engine.fuelConsumption * 0.5F; } } //Block breaking if(!world.isRemote) { //Use left and right items on the server side if(primaryShootHeld) useItem(true); if(secondaryShootHeld) useItem(false); //Check the left block being mined mineBlock(driver, playerDriver, isCreative, type, data); } } else moveAI(actualMotion); motionY = actualMotion.y; move(MoverType.SELF, actualMotion.x, actualMotion.y, actualMotion.z); setPosition(posX, posY, posZ); //Calculate movement on the client and then send position, rotation etc to the server if(serverPosX != posX || serverPosY != posY || serverPosZ != posZ || serverYaw != axes.getYaw()) { if(thePlayerIsDrivingThis) { FlansMod.getPacketHandler().sendToServer(new PacketMechaControl(this)); serverPosX = posX; serverPosY = posY; serverPosZ = posZ; serverYaw = axes.getYaw(); } } for(EntitySeat seat : getSeats()) { if(seat != null) seat.updatePosition(); } if(livingDriver == null || thePlayerIsDrivingThis) legSwing = legSwing / type.legSwingLimit; PostUpdate(); } private void mineBlock(Entity driver, EntityPlayer playerDriver, boolean isCreative, MechaType type, DriveableData data) { if(breakingBlock != null) { //Get block and material IBlockState state = world.getBlockState(new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z)); Block blockHit = state.getBlock(); Material material = state.getMaterial(); //Get the itemstacks in each hand ItemStack leftStack = inventory.getStackInSlot(EnumMechaSlotType.leftTool); ItemStack rightStack = inventory.getStackInSlot(EnumMechaSlotType.rightTool); //Work out if we are actually breaking blocks boolean leftStackIsTool = leftStack != null && leftStack.getItem() instanceof ItemMechaAddon; boolean rightStackIsTool = rightStack != null && rightStack.getItem() instanceof ItemMechaAddon; boolean breakingBlocks = (primaryShootHeld && leftStackIsTool) || (secondaryShootHeld && rightStackIsTool); //If we are not breaking blocks, reset everything if(!breakingBlocks) { breakingBlock = null; } else { //Get the block hardness float blockHardness = state.getBlockHardness(world, new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z)); //Calculate the mine speed float mineSpeed = 1F; boolean atLeastOneEffectiveTool = false; if(leftStackIsTool) { MechaItemType leftType = ((ItemMechaAddon)leftStack.getItem()).type; if(leftType.function.effectiveAgainst(material) && leftType.toolHardness > blockHardness) { mineSpeed *= leftType.speed; atLeastOneEffectiveTool = true; } } if(rightStackIsTool) { MechaItemType rightType = ((ItemMechaAddon)rightStack.getItem()).type; if(rightType.function.effectiveAgainst(material) && rightType.toolHardness > blockHardness) { mineSpeed *= rightType.speed; atLeastOneEffectiveTool = true; } } //If this block is immortal, do not break it if(blockHardness < -0.01F) mineSpeed = 0F; //If this block's hardness is zero-ish, then the tool's power is OVER 9000!!!! else if(Math.abs(blockHardness) < 0.01F) mineSpeed = 9001F; else { mineSpeed /= state.getBlockHardness(world, new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z)); } //Add block digging overlay breakingProgress += 0.1F * mineSpeed; if(breakingProgress >= 1F) { boolean cancelled = false; if(playerDriver instanceof EntityPlayerMP) { int eventOutcome = ForgeHooks .onBlockBreakEvent(world, isCreative ? GameType.CREATIVE : playerDriver.capabilities.allowEdit ? GameType.SURVIVAL : GameType.ADVENTURE, (EntityPlayerMP)playerDriver, new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z)); cancelled = eventOutcome == -1; } if(!cancelled) { if(canVacuumItems()) { vacuumItems(isCreative, type, data, state, blockHit); } //Destroy block if(!world.isRemote) { WorldServer worldServer = (WorldServer)world; BlockPos pos = new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z); boolean dropBlocks = atLeastOneEffectiveTool && !canVacuumItems(); destroyBlock(worldServer, pos, driver, dropBlocks); } } } } } } private void vacuumItems(boolean isCreative, MechaType type, DriveableData data, IBlockState state, Block blockHit) { NonNullList drops = NonNullList.create(); blockHit.getDrops(drops, world, new BlockPos(breakingBlock.x, breakingBlock.y, breakingBlock.z), state, 0); for(ItemStack stack : drops) { //Check for iron regarding refining boolean fuelCheck = (data.fuelInTank >= 5F || isCreative); if(fuelCheck && refineIron() && stack.getItem() instanceof ItemBlock && ((ItemBlock)stack.getItem()).getBlock() == Blocks.IRON_ORE) { stack = (new ItemStack(Items.IRON_INGOT, 1, 0)); if(!isCreative) data.fuelInTank -= 5F; } //Check for waste to be compacted fuelCheck = (data.fuelInTank >= 0.1F || isCreative); if(fuelCheck && wasteCompact() && stack.getItem() instanceof ItemBlock && (((ItemBlock)stack.getItem()).getBlock() == Blocks.COBBLESTONE || ((ItemBlock)stack.getItem()).getBlock() == Blocks.DIRT || ((ItemBlock)stack.getItem()).getBlock() == Blocks.SAND)) { stack.setCount(0); if(!isCreative) data.fuelInTank -= 0.1F; } //Check for item multipliers List> itemsToFuelUsageAndMultiplier = List.of( Tuple.of(Items.DIAMOND, 3F, diamondMultiplier()), Tuple.of(Items.REDSTONE, 2F, redstoneMultiplier()), Tuple.of(Items.COAL, 2F, coalMultiplier()), Tuple.of(Items.EMERALD, 2F, emeraldMultiplier()), Tuple.of(Items.IRON_INGOT, 2F, ironMultiplier())); for(Tuple3 itemToFuelUsageAndMultiplier : itemsToFuelUsageAndMultiplier) { Item item = itemToFuelUsageAndMultiplier._1; float fuelUsage = itemToFuelUsageAndMultiplier._2; float multiplier = itemToFuelUsageAndMultiplier._3; fuelCheck = (data.fuelInTank >= fuelUsage * multiplier || isCreative); if(fuelCheck && stack.getItem() == item) { stack.setCount(stack.getCount() * ( MathHelper.floor(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0))); if(!isCreative) data.fuelInTank -= fuelUsage * multiplier; } } //Check for auto coal consumption if(autoCoal() && (stack.getItem() == Items.COAL) && (data.fuelInTank + 250F < type.fuelTankSize)) { data.fuelInTank = Math.min(data.fuelInTank + 1000F, type.fuelTankSize); couldNotFindFuel = false; stack.setCount(0); } //Add the itemstack to mecha inventory if(!InventoryHelper.addItemStackToInventory(driveableData, stack, isCreative) && !world.isRemote && world.getGameRules().getBoolean("doTileDrops")) { world.spawnEntity(new EntityItem(world, breakingBlock.x + 0.5F, breakingBlock.y + 0.5F, breakingBlock.z + 0.5F, stack)); } } } private void updateHeadPosition( EntitySeat driverSeat, EntityLivingBase livingDriver, EntityPlayer playerDriver, MechaType type) { if(driverSeat != null) { if(livingDriver != null && playerDriver == null) { axes.setAngles(livingDriver.renderYawOffset + 90F, 0F, 0F); } else { //Function to limit Head Movement Left/Right if(type.limitHeadTurn) { float axesLegs = legAxes.getYaw(); float axesBody = axes.getYaw(); double dYaw = axesBody - axesLegs; if(dYaw > 180) axesBody -= 360F; if(dYaw < -180) axesBody += 360F; if(axesLegs + type.limitHeadTurnValue < axesBody) axes.setAngles(axesLegs + type.limitHeadTurnValue, 0F, 0F); if(axesLegs - type.limitHeadTurnValue > axesBody) axes.setAngles(axesLegs - type.limitHeadTurnValue, 0F, 0F); } float yaw = driverSeat.looking.getYaw(); axes.rotateGlobalYaw(yaw); driverSeat.looking.rotateGlobalYaw(-yaw); driverSeat.playerLooking.rotateGlobalYaw(-yaw); } } } private void updateDespawn(Entity driver) { ticksSinceUsed++; if(!world.isRemote && driver != null) ticksSinceUsed = 0; if(!world.isRemote && TeamsManager.mechaLove > 0 && ticksSinceUsed > TeamsManager.mechaLove * 20) { setDead(); } } private void updateHeight(MechaType type) { //TODO better implement this if(isPartIntact(EnumDriveablePart.hips)) { setSize(type.width, type.height); yOffset = type.yOffset; } else { setSize(type.width, type.height - type.chassisHeight); yOffset = type.yOffset - type.chassisHeight; } } private void detectDiamonds(EntityPlayer playerDriver) { if(canDetectDiamonds() && diamondTimer == 0 && world.isRemote && FlansMod.proxy.isThePlayer(playerDriver)) { float sqDistance = 901; for(float i = -30; i <= 30; i++) { for(float j = -30; j <= 30; j++) { for(float k = -30; k <= 30; k++) { int x = MathHelper.floor(i + posX); int y = MathHelper.floor(j + posY); int z = MathHelper.floor(k + posZ); if(i * i + j * j + k * k < sqDistance && world.getBlockState(new BlockPos(x, y, z)).getBlock() == (Blocks.DIAMOND_ORE)) { sqDistance = i * i + j * j + k * k; } } } } if(sqDistance < 901) { MechaItemType detectionItem = getDiamondDetectingUpgrade().get(); PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, detectionItem.detectSound, false); diamondTimer = 1 + 2 * MathHelper.floor(MathHelper.sqrt(sqDistance)); } } } private void autoRepair(EntityPlayer playerDriver, boolean isCreative, DriveableData data) { if(toggleTimer == 0 && canAutoRepair()) { for(EnumDriveablePart part : EnumDriveablePart.values()) { DriveablePart thisPart = data.parts.get(part); boolean hasCreativePlayer = playerDriver != null && isCreative; if(thisPart != null && thisPart.health != 0 && thisPart.health < thisPart.maxHealth && (hasCreativePlayer || data.fuelInTank >= 10F)) { thisPart.health += 1; if(!hasCreativePlayer) data.fuelInTank -= 10F; } } toggleTimer = 20; } } private void updateDelays() { if(jumpDelay > 0) jumpDelay--; if(shootDelayLeft > 0) shootDelayLeft--; if(shootDelayRight > 0) shootDelayRight--; if(soundDelayLeft > 0) soundDelayLeft--; if(soundDelayRight > 0) soundDelayRight--; if(diamondTimer > 0) --diamondTimer; if(toggleTimer > 0) toggleTimer--; if(rocketTimer > 0) rocketTimer--; } protected void moveAI(Vector3f actualMotion) { } private float tailFloat(float f) { return f - MathHelper.floor(f); } /** This is a series of iterators which check all upgrades * for various triggers and multipliers */ /** * Stop fall damage? */ public boolean stopFallDamage() { for(MechaItemType type : getUpgradeTypes()) { if(type.stopMechaFallDamage) return true; } return false; } /** * Force fall to break blocks? */ public boolean breakBlocksUponFalling() { for(MechaItemType type : getUpgradeTypes()) { if(type.forceBlockFallDamage) return true; } return false; } /** * Vacuum items? */ public boolean canVacuumItems() { for(MechaItemType type : getUpgradeTypes()) { if(type.vacuumItems) return true; } return false; } /** * Refine iron? */ public boolean refineIron() { for(MechaItemType type : getUpgradeTypes()) { if(type.refineIron) return true; } return false; } /** * Detect Diamonds? */ public boolean canDetectDiamonds() { for(MechaItemType type : getUpgradeTypes()) { if(type.diamondDetect) return true; } return false; } public Option getDiamondDetectingUpgrade() { for(MechaItemType type : getUpgradeTypes()) { if(type.diamondDetect) return Option.some(type); } return Option.none(); } /** * Compact Waste? */ public Boolean wasteCompact() { for(MechaItemType type : getUpgradeTypes()) { if(type.wasteCompact) return true; } return false; } /** * Diamond yield multiplier */ public float diamondMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.fortuneDiamond; } return multiplier; } /** * Movement speed multiplier */ public float speedMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.speedMultiplier; } return multiplier; } /** * Coal yield multiplier */ public float coalMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.fortuneCoal; } return multiplier; } /** * Redstone yield multiplier */ public float redstoneMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.fortuneRedstone; } return multiplier; } /** * Vulnerability */ public float vulnerability() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= (1 - type.damageResistance); } return multiplier; } /** * Emerald yield multiplier */ public float emeraldMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.fortuneEmerald; } return multiplier; } /** * Iron yield multiplier */ public float ironMultiplier() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.fortuneIron; } return multiplier; } /** * Light Level */ public int lightLevel() { int level = 0; for(MechaItemType type : getUpgradeTypes()) { level = Math.max(level, type.lightLevel); } return level; } /** * Force Darkness */ public boolean forceDark() { for(MechaItemType type : getUpgradeTypes()) { if(type.forceDark) return true; } return false; } /** * Convert coal to fuel? */ public boolean autoCoal() { for(MechaItemType type : getUpgradeTypes()) { if(type.autoCoal) return true; } return false; } /** * Automatically repair damage? */ public boolean canAutoRepair() { for(MechaItemType type : getUpgradeTypes()) { if(type.autoRepair) return true; } return false; } /** * Float in water? */ public boolean shouldFloat() { for(MechaItemType type : getUpgradeTypes()) { if(type.floater) return true; } return false; } /** * Have infinite ammo? */ public boolean infiniteAmmo() { for(MechaItemType type : getUpgradeTypes()) { if(type.infiniteAmmo) return true; } return false; } /** * Have a Rocket Pack? */ public MechaItemType rocketPack() { for(MechaItemType type : getUpgradeTypes()) { if(type.rocketPack) return type; } return null; } public boolean shouldFly() { return rocketPack() != null; } /** * Jetpack multiplier */ public float jetPackPower() { float multiplier = 1F; for(MechaItemType type : getUpgradeTypes()) { multiplier *= type.rocketPower; } return multiplier; } public ArrayList getUpgradeTypes() { ArrayList types = new ArrayList<>(); for(ItemStack stack : inventory.stacks.values()) { if(stack != null && stack.getItem() instanceof ItemMechaAddon) { types.add(((ItemMechaAddon)stack.getItem()).type); } } return types; } @SideOnly(Side.CLIENT) @Override public boolean showInventory(int seat) { return seat != 0; } @Override protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part) { if(part.type == EnumDriveablePart.core) { for(int i = 0; i < inventory.getSizeInventory(); i++) { if(inventory.getStackInSlot(i) != null) world.spawnEntity(new EntityItem(world, posX + midpoint.x, posY + midpoint.y, posZ + midpoint.z, inventory.getStackInSlot(i))); } } } @Override public boolean hasMouseControlMode() { return false; } @Override public String getBombInventoryName() { return ""; } @Override public String getMissileInventoryName() { return ""; } @Override @SideOnly(Side.CLIENT) public EntityLivingBase getCamera() { return null; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/EnumMechaItemType.java ================================================ package com.flansmod.common.driveables.mechas; public enum EnumMechaItemType { upgrade, tool, armUpgrade, legUpgrade, headUpgrade, shoulderUpgrade, feetUpgrade, hipsUpgrade, nothing; public static EnumMechaItemType getToolType(String s) { for(EnumMechaItemType type : values()) { if(type.toString().equals(s)) return type; } return nothing; } public EnumMechaSlotType[] getValidSlots() { switch(this) { case upgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.u1, EnumMechaSlotType.u2, EnumMechaSlotType.u3, EnumMechaSlotType.u4, EnumMechaSlotType.u5}; case tool: return new EnumMechaSlotType[]{EnumMechaSlotType.leftTool, EnumMechaSlotType.rightTool}; case armUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.leftArm, EnumMechaSlotType.rightArm}; case legUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.legs}; case headUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.head}; case shoulderUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.leftShoulder, EnumMechaSlotType.rightShoulder}; case feetUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.feet}; case hipsUpgrade: return new EnumMechaSlotType[]{EnumMechaSlotType.hips}; default: return new EnumMechaSlotType[]{}; } } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/EnumMechaSlotType.java ================================================ package com.flansmod.common.driveables.mechas; public enum EnumMechaSlotType { leftTool, rightTool, leftArm, rightArm, head, leftShoulder, rightShoulder, hips, legs, feet, u1, u2, u3, u4, u5; public boolean accepts(EnumMechaItemType type) { switch(this) { case leftTool: case rightTool: return type == EnumMechaItemType.tool; case leftArm: case rightArm: return type == EnumMechaItemType.armUpgrade; case head: return type == EnumMechaItemType.headUpgrade; case leftShoulder: case rightShoulder: return type == EnumMechaItemType.shoulderUpgrade; case legs: return type == EnumMechaItemType.legUpgrade; case hips: return type == EnumMechaItemType.hipsUpgrade; case feet: return type == EnumMechaItemType.feetUpgrade; case u1: case u2: case u3: case u4: case u5: return type == EnumMechaItemType.upgrade; } return false; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/EnumMechaToolType.java ================================================ package com.flansmod.common.driveables.mechas; import net.minecraft.block.material.Material; public enum EnumMechaToolType { pickaxe, axe, shovel, shears, sword; public static EnumMechaToolType getToolType(String s) { for(EnumMechaToolType type : values()) { if(type.toString().equals(s)) return type; } return sword; } public boolean effectiveAgainst(Material material) { switch(this) { case pickaxe: return material == Material.IRON || material == Material.ANVIL || material == Material.ROCK || material == Material.ICE; case axe: return material == Material.WOOD || material == Material.PLANTS || material == Material.VINE; case shovel: return material == Material.GRASS || material == Material.GROUND || material == Material.SPONGE || material == Material.SAND || material == Material.SNOW || material == Material.CRAFTED_SNOW || material == Material.CLAY; case shears: return material == Material.LEAVES || material == Material.VINE || material == Material.CLOTH || material == Material.CARPET; case sword: return material == Material.WEB; } return false; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/ItemMecha.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.Collections; import java.util.List; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; public class ItemMecha extends Item implements IPaintableItem { public MechaType type; public ItemMecha(MechaType type1) { maxStackSize = 1; type = type1; type.item = this; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanMechas); } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } NBTTagCompound tags = getTagCompound(stack, world); String engineName = tags.getString("Engine"); PartType part = PartType.getPart(engineName); if(part != null) lines.add(part.name); } @Override /** Make sure client and server side NBTtags update */ public boolean getShareTag() { return true; } private NBTTagCompound getTagCompound(ItemStack stack, World world) { if(stack.getTagCompound() == null) { if(stack.getTagCompound() == null) { NBTTagCompound tags = new NBTTagCompound(); stack.setTagCompound(tags); tags.setString("Type", type.shortName); tags.setString("Engine", PartType.defaultEngines.get(EnumType.mecha).shortName); } } return stack.getTagCompound(); } @Override public ActionResult onItemRightClick(World world, EntityPlayer entityplayer, EnumHand hand) { ItemStack itemstack = entityplayer.getHeldItem(hand); //Raytracing float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F); float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F); double length = 5D; Vec3d posVec = new Vec3d(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ); Vec3d lookVec = posVec.add(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length); RayTraceResult RayTraceResult = world.rayTraceBlocks(posVec, lookVec, true); //Result check if(RayTraceResult == null) { return new ActionResult<>(EnumActionResult.PASS, itemstack); } if(RayTraceResult.typeOfHit == Type.BLOCK) { BlockPos pos = RayTraceResult.getBlockPos(); if(!world.isRemote) { world.spawnEntity(new EntityMecha(world, (double)pos.getX() + 0.5F, (double)pos.getY() + 1.5F + type.yOffset, (double)pos.getZ() + 0.5F, entityplayer, type, getData(itemstack, world), getTagCompound(itemstack, world))); } if(!entityplayer.capabilities.isCreativeMode) { itemstack.setCount(itemstack.getCount() - 1); } return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } return new ActionResult<>(EnumActionResult.PASS, itemstack); } public DriveableData getData(ItemStack itemstack, World world) { return new DriveableData(getTagCompound(itemstack, world), itemstack.getItemDamage()); } @Override public void getSubItems(CreativeTabs tab, NonNullList items) { if(tab != FlansMod.tabFlanMechas && tab != CreativeTabs.SEARCH) return; ItemStack mechaStack = new ItemStack(this, 1, 0); NBTTagCompound tags = new NBTTagCompound(); tags.setString("Type", type.shortName); if(PartType.defaultEngines.containsKey(EnumType.mecha)) tags.setString("Engine", PartType.defaultEngines.get(EnumType.mecha).shortName); for(EnumDriveablePart part : EnumDriveablePart.values()) { tags.setInteger(part.getShortName() + "_Health", type.health.get(part) == null ? 0 : type.health.get(part).health); tags.setBoolean(part.getShortName() + "_Fire", false); } mechaStack.setTagCompound(tags); items.add(mechaStack); } @Override public InfoType getInfoType() { return type; } @Override public PaintableType GetPaintableType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/ItemMechaAddon.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.Collections; import java.util.List; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class ItemMechaAddon extends Item implements IFlanItem { public MechaItemType type; public ItemMechaAddon(MechaItemType type1) { type = type1; setMaxStackSize(1); type.item = this; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanMechas); } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } } @Override public InfoType getInfoType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/MechaInventory.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.HashMap; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.text.ITextComponent; import com.flansmod.common.guns.ItemBullet; import com.flansmod.common.guns.ItemGun; public class MechaInventory implements IInventory { public EntityMecha mecha; public HashMap stacks; public MechaInventory(EntityMecha m) { mecha = m; stacks = new HashMap<>(); for(EnumMechaSlotType type : EnumMechaSlotType.values()) { stacks.put(type, null); } } public MechaInventory(EntityMecha m, NBTTagCompound tags) { this(m); readFromNBT(tags); } public void readFromNBT(NBTTagCompound tags) { if(tags == null) return; for(EnumMechaSlotType type : EnumMechaSlotType.values()) { stacks.put(type, new ItemStack(tags.getCompoundTag(type.toString()))); } } public NBTTagCompound writeToNBT(NBTTagCompound tags) { if(tags == null) return null; for(EnumMechaSlotType type : EnumMechaSlotType.values()) { if(stacks.get(type) != null) tags.setTag(type.toString(), stacks.get(type).writeToNBT(new NBTTagCompound())); } return tags; } @Override public int getSizeInventory() { return EnumMechaSlotType.values().length; } @Override public ItemStack getStackInSlot(int i) { return stacks.get(EnumMechaSlotType.values()[i]); } public ItemStack getStackInSlot(EnumMechaSlotType e) { return stacks.get(e); } @Override public ItemStack decrStackSize(int i, int j) { markDirty(); ItemStack slot = getStackInSlot(i); if(slot == null) return ItemStack.EMPTY.copy(); int numToTake = Math.min(j, slot.getCount()); ItemStack returnStack = slot.copy(); returnStack.setCount(numToTake); slot.setCount(slot.getCount() - numToTake); if(slot.getCount() <= 0) slot = ItemStack.EMPTY.copy(); setInventorySlotContents(i, slot); return returnStack; } @Override public void setInventorySlotContents(int i, ItemStack itemstack) { setInventorySlotContents(EnumMechaSlotType.values()[i], itemstack); } public void setInventorySlotContents(EnumMechaSlotType e, ItemStack itemstack) { markDirty(); stacks.put(e, itemstack); } @Override public int getInventoryStackLimit() { return 64; } @Override public void markDirty() { if(mecha != null) mecha.couldNotFindFuel = false; } @Override public boolean isItemValidForSlot(int i, ItemStack itemstack) { Item item = itemstack.getItem(); if(item == null) return true; switch(EnumMechaSlotType.values()[i]) { case leftTool: case rightTool: return item instanceof ItemGun || item instanceof ItemMechaAddon; case leftArm: case rightArm: return item instanceof ItemBullet; default: return false; } } @Override public String getName() { return "Mecha"; } @Override public boolean hasCustomName() { return true; } @Override public ITextComponent getDisplayName() { return null; } @Override public void openInventory(EntityPlayer player) { } @Override public void closeInventory(EntityPlayer player) { } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { } @Override public boolean isEmpty() { return false; } @Override public ItemStack removeStackFromSlot(int index) { return ItemStack.EMPTY.copy(); } @Override public boolean isUsableByPlayer(EntityPlayer player) { return mecha != null && player.getDistanceSq(mecha) <= 10D * 10D; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/MechaItemType.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.ArrayList; import net.minecraft.client.model.ModelBase; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelMechaTool; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class MechaItemType extends InfoType { public static ArrayList types = new ArrayList<>(); /** * The type of item */ public EnumMechaItemType type; /** * If this is a tool, then what type of tool is this? Axe? Pick? */ public EnumMechaToolType function = EnumMechaToolType.sword; /** * How quickly this tool works */ public float speed = 1F; /** * The maximum block hardness you can break with this tool */ public float toolHardness = 1F; /** * This is multiplied by the mecha reach to calculate the total reach */ public float reach = 1F; /** * This makes the mecha float towards the surface when underwater, because apparently people prefer limited functionality */ public boolean floater = false; /** * This allows an upgrade to affect the mecha's move speed */ public float speedMultiplier = 1F; /** * This allows upgrades to reduce incoming damage */ public float damageResistance = 0F; /** * This allows a sound to be played upon use (RocketPack only for the moment) */ public String soundEffect = ""; public String detectSound = ""; public float soundTime = 0; public int energyShield = 0; public int lightLevel = 0; /** * The following are a ton of upgrade flags and modifiers. The mecha will iterate over all upgrades in its * inventory multiplying multipliers and looking for true booleans in order to decide if things should happen * or what certain values should take */ public boolean stopMechaFallDamage = false, forceBlockFallDamage = false, vacuumItems = false, refineIron = false, autoCoal = false, autoRepair = false, rocketPack = false, diamondDetect = false, infiniteAmmo = false, forceDark = false, wasteCompact = false, flameBurst = false; /** * The drop rate of these items are multiplied by this float. They stack between items too. * Once dropRate has been calculated, each block then gives floor(dropRate) items with a * dropRate - floor(dropRate) chance of getting one more */ public float fortuneDiamond = 1F, fortuneRedstone = 1F, fortuneCoal = 1F, fortuneEmerald = 1F, fortuneIron = 1F; /** * The power of any attached jet pack is multiplied by this float */ public float rocketPower = 1F; /** * The model */ @SideOnly(Side.CLIENT) public ModelMechaTool model; public MechaItemType(TypeFile file) { super(file); types.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) model = FlansMod.proxy.loadModel(split[1], shortName, ModelMechaTool.class); if(split[0].equals("Type")) type = EnumMechaItemType.getToolType(split[1]); if(split[0].equals("ToolType")) function = EnumMechaToolType.getToolType(split[1]); if(split[0].equals("Speed")) speed = Float.parseFloat(split[1]); if(split[0].equals("ToolHardness")) toolHardness = Float.parseFloat(split[1]); if(split[0].equals("Reach")) reach = Float.parseFloat(split[1]); /** The following are the upgrade booleans and multipliers, which * are alphabetised. Mess with the order at your peril*/ if(split[0].equals("AutoFuel")) autoCoal = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("Armour")) damageResistance = Float.parseFloat(split[1]); if(split[0].equals("CoalMultiplier")) fortuneCoal = Float.parseFloat(split[1]); if(split[0].equals("DetectSound")) { detectSound = split[1]; FlansMod.proxy.loadSound(contentPack, shortName, split[1]); } if(split[0].equals("DiamondDetect")) diamondDetect = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("DiamondMultiplier")) fortuneDiamond = Float.parseFloat(split[1]); if(split[0].equals("EmeraldMultiplier")) fortuneEmerald = Float.parseFloat(split[1]); if(split[0].equals("FlameBurst")) flameBurst = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("Floatation")) floater = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("ForceBlockFallDamage")) forceBlockFallDamage = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("ForceDark")) forceDark = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("InfiniteAmmo")) infiniteAmmo = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("IronMultiplier")) fortuneIron = Float.parseFloat(split[1]); if(split[0].equals("IronRefine")) refineIron = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("ItemVacuum")) vacuumItems = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("LightLevel")) lightLevel = Integer.parseInt(split[1]); if(split[0].equals("Nanorepair")) autoRepair = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("RedstoneMultiplier")) fortuneRedstone = Float.parseFloat(split[1]); if(split[0].equals("RocketPack")) rocketPack = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("RocketPower")) rocketPower = Float.parseFloat(split[1]); if(split[0].equals("SoundEffect")) soundEffect = split[1]; if(split[0].equals("SoundTime")) soundTime = Float.parseFloat(split[1]); if(split[0].equals("SpeedMultiplier")) speedMultiplier = Float.parseFloat(split[1]); if(split[0].equals("StopMechaFallDamage")) stopMechaFallDamage = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("WasteCompact")) wasteCompact = Boolean.parseBoolean(split[1].toLowerCase()); } catch(Exception ignored) { } } public static MechaItemType getTool(String find) { for(MechaItemType type : types) { if(type.shortName.equals(find)) return type; } return null; } public void reloadModel() { if(modelString != null) model = FlansMod.proxy.loadModel(modelString, shortName, ModelMechaTool.class); } @Override protected void preRead(TypeFile file) { } @Override protected void postRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/MechaType.java ================================================ package com.flansmod.common.driveables.mechas; import java.util.ArrayList; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import com.flansmod.client.model.ModelMecha; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveableData; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.vector.Vector3f; public class MechaType extends DriveableType { /** * Movement modifiers */ public float turnLeftModifier = 1F, turnRightModifier = 1F, moveSpeed = 1F; /** * If true, this will crush any living entity under the wheels */ public boolean squashMobs = false; /** * How many blocks can be stepped up when walking */ public int stepHeight = 0; /** * Jump Height (set 0 for no jump) */ public float jumpHeight = 1F; public float jumpVelocity = 1F; /** * Speed of Rotation */ public float rotateSpeed = 10F; /** * Origin of the mecha arms */ public Vector3f leftArmOrigin, rightArmOrigin; /** * Length of the mecha arms and legs */ public float armLength = 1F, legLength = 1F, RearlegLength = legLength, FrontlegLength = legLength, LegTrans = 0F, RearLegTrans = 0F, FrontLegTrans = 0F; /** * The amount to scale the held items / tools by when rendering */ public float heldItemScale = 1F; /** * Height and Width of the world collision box */ public float height = 3F, width = 2F; /** * The height of chassis above the ground; for use when legs are gone */ public float chassisHeight = 1F; /** * The default reach of tools. Tools can multiply this base reach as they wish */ public float reach = 10F; //Falling /** * Whether the mecha damages blocks when falling. Can be overriden by upgrades */ public boolean damageBlocksFromFalling = true; /** * The size of explosion to cause, per fall damage */ public float blockDamageFromFalling = 1F; /** * Whether the mecha takes fall damage. Can be overriden by upgrades */ public boolean takeFallDamage = true; /** * How much fall damage the mecha takes by default */ public float fallDamageMultiplier = 1F; /** * Leg Swing Limit */ public float legSwingLimit = 2F; // Limiting head turning public boolean limitHeadTurn = false; public float limitHeadTurnValue = 90F; // Speed of Leg movement public float legSwingTime = 5; // Upper/Lower Arm Limit public float upperArmLimit = 90; public float lowerArmLimit = 90; // Modifier for Weapons in Hand public float leftHandModifierX = 0; public float leftHandModifierY = 0; public float leftHandModifierZ = 0; public float rightHandModifierX = 0; public float rightHandModifierY = 0; public float rightHandModifierZ = 0; public static ArrayList types = new ArrayList<>(); public MechaType(TypeFile file) { super(file); types.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { //Movement modifiers if(split[0].equals("TurnLeftSpeed")) turnLeftModifier = Float.parseFloat(split[1]); if(split[0].equals("TurnRightSpeed")) turnRightModifier = Float.parseFloat(split[1]); if(split[0].equals("MoveSpeed")) moveSpeed = Float.parseFloat(split[1]); if(split[0].equals("SquashMobs")) squashMobs = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("StepHeight")) stepHeight = Integer.parseInt(split[1]); if(split[0].equals("JumpHeight")) { jumpHeight = Float.parseFloat(split[1]); jumpVelocity = (float)Math.sqrt(Math.abs(9.81F * (jumpHeight + 0.2F) / 200F)); } if(split[0].equals("RotateSpeed")) rotateSpeed = Float.parseFloat(split[1]); if(split[0].equals("LeftArmOrigin")) leftArmOrigin = new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F); if(split[0].equals("RightArmOrigin")) rightArmOrigin = new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F); if(split[0].equals("ArmLength")) armLength = Float.parseFloat(split[1]) / 16F; if(split[0].equals("LegLength")) legLength = Float.parseFloat(split[1]) / 16F; if(split[0].equals("LegTrans")) LegTrans = Float.parseFloat(split[1]) / 16F; if(split[0].equals("RearLegLength")) RearlegLength = Float.parseFloat(split[1]) / 16F; if(split[0].equals("FrontLegLength")) FrontlegLength = Float.parseFloat(split[1]) / 16F; if(split[0].equals("RearLegTrans")) RearLegTrans = Float.parseFloat(split[1]) / 16F; if(split[0].equals("FrontLegTrans")) FrontLegTrans = Float.parseFloat(split[1]) / 16F; if(split[0].equals("HeldItemScale")) heldItemScale = Float.parseFloat(split[1]); if(split[0].equals("Height")) height = (Float.parseFloat(split[1]) / 16F); if(split[0].equals("Width")) width = (Float.parseFloat(split[1]) / 16F); if(split[0].equals("ChassisHeight")) chassisHeight = (Integer.parseInt(split[1])) / 16F; if(split[0].equals("FallDamageMultiplier")) fallDamageMultiplier = Float.parseFloat(split[1]); if(split[0].equals("BlockDamageFromFalling")) blockDamageFromFalling = Float.parseFloat(split[1]); if(split[0].equals("Reach")) reach = Float.parseFloat(split[1]); if(split[0].equals("TakeFallDamage")) takeFallDamage = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("DamageBlocksFromFalling")) damageBlocksFromFalling = Boolean.parseBoolean(split[1].toLowerCase()); if(split[0].equals("LegSwingLimit")) legSwingLimit = Float.parseFloat(split[1]); if(split[0].equals("LimitHeadTurn")) { limitHeadTurn = Boolean.parseBoolean(split[1].toLowerCase()); limitHeadTurnValue = Float.parseFloat(split[2]); } if(split[0].equals("LegSwingTime")) legSwingTime = Float.parseFloat(split[1]); if(split[0].equals("UpperArmLimit")) upperArmLimit = Float.parseFloat(split[1]); if(split[0].equals("LowerArmLimit")) lowerArmLimit = Float.parseFloat(split[1]); if(split[0].equals("LeftHandModifier")) { leftHandModifierX = Float.parseFloat(split[1]) / 16F; leftHandModifierY = Float.parseFloat(split[2]) / 16F; leftHandModifierZ = Float.parseFloat(split[3]) / 16F; } if(split[0].equals("RightHandModifier")) { rightHandModifierX = Float.parseFloat(split[1]) / 16F; rightHandModifierY = Float.parseFloat(split[2]) / 16F; rightHandModifierZ = Float.parseFloat(split[3]) / 16F; } } catch(Exception ignored) { } } /** * Find the items needed to rebuild a part. The returned array is disconnected from the template items it has looked up */ @Override public ArrayList getItemsRequired(DriveablePart part, PartType engine) { //Get the list of items required by the driveable ArrayList stacks = super.getItemsRequired(part, engine); //Add the propellers and engines if(EnumDriveablePart.core == part.type) { stacks.add(new ItemStack(engine.item)); } return stacks; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelMecha.class); } public static MechaType getMecha(String find) { for(MechaType type : types) { if(type.shortName.equals(find)) return type; } return null; } @Override public EntityDriveable createDriveable(World world, double x, double y, double z, DriveableData data) { return new EntityMecha(world, x, y, z, this, data, new NBTTagCompound()); } } ================================================ FILE: src/main/java/com/flansmod/common/driveables/mechas/SlotMecha.java ================================================ package com.flansmod.common.driveables.mechas; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import com.flansmod.common.guns.ItemGun; public class SlotMecha extends Slot { private EnumMechaSlotType slotType; public SlotMecha(IInventory inv, EnumMechaSlotType e, int x, int y) { super(inv, e.ordinal(), x, y); slotType = e; } @Override public boolean isItemValid(ItemStack stack) { if(stack == null || stack.isEmpty()) return true; EnumMechaItemType itemType = null; Item item = stack.getItem(); if(item instanceof ItemGun && ((ItemGun)item).GetType().usableByMechas) itemType = EnumMechaItemType.tool; else if(item instanceof ItemMechaAddon) itemType = ((ItemMechaAddon)item).type.type; else return false; return slotType.accepts(itemType); } @Override public void putStack(ItemStack stack) { if(!isItemValid(stack)) return; inventory.setInventorySlotContents(slotType.ordinal(), stack); onSlotChanged(); } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentDuelist.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.Enchantment.Rarity; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentDuelist extends Enchantment { protected EnchantmentDuelist() { super(Rarity.COMMON, EnchantmentModule.OFF_HAND, new EntityEquipmentSlot[] { EntityEquipmentSlot.OFFHAND } ); } @Override public int getMaxLevel() { return 3; } @Override public boolean canApplyTogether(Enchantment ench) { if(ench instanceof EnchantmentSharpshooter) return false; if(ench instanceof EnchantmentLumberjack) return false; if(ench instanceof EnchantmentDuelist) return false; return true; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentJuggernaut.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentDamage; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.enchantment.Enchantment.Rarity; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentJuggernaut extends Enchantment { protected EnchantmentJuggernaut() { super(Rarity.VERY_RARE, EnumEnchantmentType.ARMOR, new EntityEquipmentSlot[] { EntityEquipmentSlot.HEAD, EntityEquipmentSlot.CHEST, EntityEquipmentSlot.LEGS, EntityEquipmentSlot.FEET, } ); } @Override public int getMaxLevel() { return 1; } @Override public boolean isTreasureEnchantment() { return true; } @Override public int getMinEnchantability(int enchantmentLevel) { return enchantmentLevel * 25; } @Override public int getMaxEnchantability(int enchantmentLevel) { return this.getMinEnchantability(enchantmentLevel) + 50; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentLumberjack.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentDamage; import net.minecraft.enchantment.Enchantment.Rarity; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentLumberjack extends Enchantment { protected EnchantmentLumberjack() { super(Rarity.COMMON, EnchantmentModule.OFF_HAND, new EntityEquipmentSlot[] { EntityEquipmentSlot.OFFHAND } ); } @Override public int getMaxLevel() { return 3; } @Override public boolean canApplyTogether(Enchantment ench) { if(ench instanceof EnchantmentSharpshooter) return false; if(ench instanceof EnchantmentLumberjack) return false; if(ench instanceof EnchantmentDuelist) return false; return true; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentModule.java ================================================ package com.flansmod.common.enchantments; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.FireableGun; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.ItemAxe; import net.minecraft.item.ItemShield; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemSword; import net.minecraft.util.math.MathHelper; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.EnumHelper; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class EnchantmentModule { public static final EnumEnchantmentType SHIELDS = EnumHelper.addEnchantmentType("shields", (item)->(item instanceof ItemShield)); public static final EnumEnchantmentType GLOVES = EnumHelper.addEnchantmentType("gloves", (item)->(item instanceof ItemGlove)); public static final EnumEnchantmentType OFF_HAND = EnumHelper.addEnchantmentType("offHand", (item)->(item instanceof ItemGlove || item instanceof ItemShield)); public static Enchantment STEADY_ENCHANT, NIMBLE_ENCHANT, LUMBERJACK_ENCHANT, DUELIST_ENCHANT, SHARPSHOOTER_ENCHANT, JUGGERNAUT_ENCHANT; public EnchantmentModule() { } public void PreInit() { MinecraftForge.EVENT_BUS.register(this); STEADY_ENCHANT = new EnchantmentSteady().setRegistryName("enchantment_steady").setName("enchantment_steady"); NIMBLE_ENCHANT = new EnchantmentNimble().setRegistryName("enchantment_nimble").setName("enchantment_nimble"); LUMBERJACK_ENCHANT = new EnchantmentLumberjack().setRegistryName("enchantment_lumberjack").setName("enchantment_lumberjack"); DUELIST_ENCHANT = new EnchantmentDuelist().setRegistryName("enchantment_duelist").setName("enchantment_duelist"); SHARPSHOOTER_ENCHANT = new EnchantmentSharpshooter().setRegistryName("enchantment_sharpshooter").setName("enchantment_sharpshooter"); JUGGERNAUT_ENCHANT = new EnchantmentJuggernaut().setRegistryName("enchantment_juggernaut").setName("enchantment_juggernaut"); } public void Init() { } public void PostInit() { } @SubscribeEvent public void RegisterEnchants(RegistryEvent.Register event) { event.getRegistry().register(STEADY_ENCHANT); event.getRegistry().register(NIMBLE_ENCHANT); event.getRegistry().register(LUMBERJACK_ENCHANT); event.getRegistry().register(DUELIST_ENCHANT); event.getRegistry().register(SHARPSHOOTER_ENCHANT); event.getRegistry().register(JUGGERNAUT_ENCHANT); } @SubscribeEvent public void AttackEvent(LivingHurtEvent event) { Entity trueSource = event.getSource().getTrueSource(); if(trueSource != null && trueSource instanceof EntityLivingBase) { EntityLivingBase attacker = (EntityLivingBase)trueSource; ItemStack weaponStack = attacker.getHeldItemMainhand(); ItemStack offHandStack = attacker.getHeldItemOffhand(); // Apply lumberjack offhand effect if(weaponStack.getItem() instanceof ItemAxe) { int lumberjackLevel = EnchantmentHelper.getEnchantmentLevel(LUMBERJACK_ENCHANT, offHandStack); // Add 10% damage for each level of Lumberjack on the glove (multiplicative) for(int i = 0; i < lumberjackLevel; i++) event.setAmount(event.getAmount() * 1.10f); if(lumberjackLevel > 0) offHandStack.damageItem(1, attacker); } // Apply duelist offhand effect if(weaponStack.getItem() instanceof ItemSword) { int duelistLevel = EnchantmentHelper.getEnchantmentLevel(DUELIST_ENCHANT, offHandStack); // Add 10% damage for each level of Duelist on the glove (multiplicative) for(int i = 0; i < duelistLevel; i++) event.setAmount(event.getAmount() * 1.10f); if(duelistLevel > 0) offHandStack.damageItem(1, attacker); } // Then apply juggernaut effects int juggernautLevel = 0; for(ItemStack armour : event.getEntityLiving().getArmorInventoryList()) { juggernautLevel += EnchantmentHelper.getEnchantmentLevel(JUGGERNAUT_ENCHANT, armour); } if(juggernautLevel > 0) { final float minPercent = 0.25f; // With all 4 armour pieces enchanted, we drop to 25% max damage per hit final float exponent = (float)Math.log(minPercent) / 4f; // 4 because that's the theoretical max level of the enchant float maxDamageAsPercentOfHP = (float)Math.exp(exponent * juggernautLevel); float maxHP = event.getEntityLiving().getMaxHealth() + event.getEntityLiving().getTotalArmorValue(); if(event.getAmount() > maxHP * maxDamageAsPercentOfHP) { float absorbedDmg = event.getAmount() - maxHP * maxDamageAsPercentOfHP; // Don't want to just annihalate the armour in edge cases. That would be :( if(absorbedDmg > 256.0f) absorbedDmg = 256.0f; for(ItemStack armour : event.getEntityLiving().getArmorInventoryList()) { if(EnchantmentHelper.getEnchantmentLevel(JUGGERNAUT_ENCHANT, armour) > 0) { armour.damageItem(MathHelper.floor(absorbedDmg), event.getEntityLiving()); } } FlansMod.log.info("Juggernaut applied to incoming damage of " + event.getAmount() + " over the threshold of " + (maxHP * maxDamageAsPercentOfHP)); event.setAmount(maxHP * maxDamageAsPercentOfHP); } } } } public static void ModifyGun(FireableGun fireableGun, EntityLivingBase entity, ItemStack otherHand) { if(!FlansMod.enchantmentModuleEnabled) return; int steadyLevel = EnchantmentHelper.getEnchantmentLevel(STEADY_ENCHANT, otherHand); // Cut 25% of spread for each level of Steady on the glove (multiplicative) for(int i = 0; i < steadyLevel; i++) fireableGun.MultiplySpread(0.75f); int sharpshooterLevel = EnchantmentHelper.getEnchantmentLevel(SHARPSHOOTER_ENCHANT, otherHand); // Add 10% damage for each level of Sharpshooter on the glove (multiplicative) for(int i = 0; i < sharpshooterLevel; i++) fireableGun.MultiplyDamage(1.10f); if(steadyLevel > 0 || sharpshooterLevel > 0) otherHand.damageItem(1, entity); } public static float ModifyReloadTime(float reloadTime, EntityLivingBase entity, ItemStack otherHand) { if(!FlansMod.enchantmentModuleEnabled) return reloadTime; int nimbleLevel = EnchantmentHelper.getEnchantmentLevel(NIMBLE_ENCHANT, otherHand); // Cut 15% of reload time for each level of Nimble on the glove (multiplicative) for(int i = 0; i < nimbleLevel; i++) reloadTime *= 0.85f; if(nimbleLevel > 0) otherHand.damageItem(1, entity); return reloadTime; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentNimble.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentNimble extends Enchantment { protected EnchantmentNimble() { super(Rarity.UNCOMMON, EnchantmentModule.GLOVES, new EntityEquipmentSlot[] { EntityEquipmentSlot.OFFHAND } ); } @Override public int getMaxLevel() { return 3; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentSharpshooter.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentDamage; import net.minecraft.enchantment.Enchantment.Rarity; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentSharpshooter extends Enchantment { protected EnchantmentSharpshooter() { super(Rarity.COMMON, EnchantmentModule.OFF_HAND, new EntityEquipmentSlot[] { EntityEquipmentSlot.OFFHAND } ); } @Override public int getMaxLevel() { return 3; } @Override public boolean canApplyTogether(Enchantment ench) { if(ench instanceof EnchantmentSharpshooter) return false; if(ench instanceof EnchantmentLumberjack) return false; if(ench instanceof EnchantmentDuelist) return false; return true; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/EnchantmentSteady.java ================================================ package com.flansmod.common.enchantments; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.inventory.EntityEquipmentSlot; public class EnchantmentSteady extends Enchantment { protected EnchantmentSteady() { super(Rarity.COMMON, EnchantmentModule.OFF_HAND, new EntityEquipmentSlot[] { EntityEquipmentSlot.OFFHAND }); } @Override public int getMaxLevel() { return 3; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/GloveType.java ================================================ package com.flansmod.common.enchantments; import java.util.ArrayList; import java.util.HashMap; import com.flansmod.client.model.ModelDriveable; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePosition; import com.flansmod.common.driveables.DriveableType; import com.flansmod.common.driveables.Seat; import com.flansmod.common.parts.PartType; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.types.InfoType.ParseFunc; import net.minecraftforge.fml.common.FMLCommonHandler; public class GloveType extends InfoType { public static ArrayList gloves = new ArrayList<>(); private static HashMap> parsers = new HashMap<>(); static { // BASICS ///////////////////////////////////////////////////////////////////////////// parsers.put("Enchantability", (split, d) -> d.Enchantability = Integer.parseInt(split[1])); parsers.put("Durability", (split, d) -> d.Durability = Integer.parseInt(split[1])); } public int Enchantability = 20; public int Durability = 200; public GloveType(TypeFile file) { super(file); } @Override public void preRead(TypeFile file) { super.preRead(file); gloves.add(this); } @Override protected void read(String[] split, TypeFile file) { try { ParseFunc parser = parsers.get(split[0]); if(parser != null) { parser.Parse(split, this); } else { super.read(split, file); } } catch(Exception e) { FlansMod.log.error("Errored reading " + file.name); FlansMod.log.throwing(e); } } @Override public void postRead(TypeFile file) { super.postRead(file); } public static GloveType getGlove(String s) { for(GloveType glove : gloves) { if(glove.shortName.equals(s)) return glove; } return null; } } ================================================ FILE: src/main/java/com/flansmod/common/enchantments/ItemGlove.java ================================================ package com.flansmod.common.enchantments; import java.util.List; import javax.annotation.Nullable; import com.flansmod.common.FlansMod; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class ItemGlove extends Item implements IFlanItem { private GloveType mType; public ItemGlove(GloveType glove) { mType = glove; maxStackSize = 1; glove.item = this; setMaxDamage(mType.Durability); setRegistryName(glove.shortName); setTranslationKey(glove.shortName); setCreativeTab(FlansMod.tabFlanTeams); } @Override public InfoType getInfoType() { return mType; } @Override public int getItemEnchantability() { return mType.Enchantability; } @SideOnly(Side.CLIENT) @Override public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { tooltip.add("\u00a73Improves gun, sword or axe handling when enchanted and held in off hand"); tooltip.add("\u00a73Works with two-handed guns"); } } ================================================ FILE: src/main/java/com/flansmod/common/eventhandlers/PlayerDeathEventListener.java ================================================ package com.flansmod.common.eventhandlers; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerHandler; import com.flansmod.common.guns.EntityDamageSourceFlan; import com.flansmod.common.network.PacketKillMessage; import com.flansmod.common.teams.Team; public class PlayerDeathEventListener { public PlayerDeathEventListener() { MinecraftForge.EVENT_BUS.register(this); } @EventHandler @SubscribeEvent public void PlayerDied(LivingDeathEvent event) { if (event.getEntity().world.isRemote) return; if (event.getSource() instanceof EntityDamageSourceFlan && event.getEntity() instanceof EntityPlayer) { EntityDamageSourceFlan source = (EntityDamageSourceFlan) event.getSource(); EntityPlayer died = (EntityPlayer) event.getEntity(); Team killedTeam = PlayerHandler.getPlayerData(died).team; if(source.getCausedPlayer() != null) { Team killerTeam = PlayerHandler.getPlayerData(source.getCausedPlayer()).team; FlansMod.getPacketHandler().sendToDimension(new PacketKillMessage(source.isHeadshot(), source.getWeapon(), (killedTeam == null ? "f" : killedTeam.textColour) + died.getName(), (killerTeam == null ? "f" : killerTeam.textColour) + source.getCausedPlayer().getName()), died.dimension); } } } } ================================================ FILE: src/main/java/com/flansmod/common/guns/AAGunType.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import java.util.List; import net.minecraft.client.model.ModelBase; import net.minecraft.item.ItemStack; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelAAGun; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class AAGunType extends InfoType { /** * The ammo types used by this gun */ public List ammo = new ArrayList<>(); public int reloadTime; public int recoil = 5; public int accuracy; public int damage; public int shootDelay; public int numBarrels; public boolean fireAlternately; public int health; public int gunnerX, gunnerY, gunnerZ; public String shootSound; public String reloadSound; public ModelAAGun model; public float topViewLimit = 75F; public float bottomViewLimit = 0F; public int[] barrelX, barrelY, barrelZ; /** * Sentry mode. If target players is true then it either targets everyone on the other team, or everyone other than the owner when not playing with teams */ public boolean targetMobs = false, targetPlayers = false, targetVehicles = false, targetPlanes = false, targetMechas = false; /** * Targeting radius */ public float targetRange = 10F; /** * If true, then all barrels share the same ammo slot */ public boolean shareAmmo = false; public static List infoTypes = new ArrayList<>(); public AAGunType(TypeFile file) { super(file); infoTypes.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) { model = FlansMod.proxy.loadModel(split[1], shortName, ModelAAGun.class); } damage = Read(split, "Damage", damage); reloadTime = Read(split, "ReloadTime", reloadTime); recoil = Read(split, "Recoil", recoil); accuracy = Read(split, "Accuracy", accuracy); shootDelay = Read(split, "ShootDelay", shootDelay); fireAlternately = Read(split, "FireAlternately", fireAlternately); health = Read(split, "Health", health); topViewLimit = Read(split, "TopViewLimit", topViewLimit); bottomViewLimit = Read(split, "BottomViewLimit", bottomViewLimit); targetMobs = Read(split, "TargetMobs", targetMobs); targetPlayers = Read(split, "TargetPlayers", targetPlayers); targetVehicles = Read(split, "TargetVehicles", targetVehicles); targetPlanes = Read(split, "TargetPlanes", targetPlanes); targetMechas = Read(split, "TargetMechas", targetMechas); shareAmmo = Read(split, "ShareAmmo", shareAmmo); targetRange = Read(split, "TargetRange", targetRange); bottomViewLimit = Read(split, "BottomViewLimit", bottomViewLimit); if(split[0].equals("TargetDriveables")) targetMechas = targetPlanes = targetVehicles = Boolean.parseBoolean(split[1]); if(split[0].equals("ShootSound")) { shootSound = split[1]; FlansMod.proxy.loadSound(contentPack, "aaguns", split[1]); } if(split[0].equals("ReloadSound")) { reloadSound = split[1]; FlansMod.proxy.loadSound(contentPack, "aaguns", split[1]); } if(split[0].equals("NumBarrels")) { numBarrels = Integer.parseInt(split[1]); barrelX = new int[numBarrels]; barrelY = new int[numBarrels]; barrelZ = new int[numBarrels]; } if(split[0].equals("Barrel")) { int id = Integer.parseInt(split[1]); barrelX[id] = Integer.parseInt(split[2]); barrelY[id] = Integer.parseInt(split[3]); barrelZ[id] = Integer.parseInt(split[4]); } if(split[0].equals("Health")) { health = Integer.parseInt(split[1]); } if(split[0].equals("Ammo")) { BulletType type = BulletType.getBullet(split[1]); if(type != null) { ammo.add(type); } } if(split[0].equals("GunnerPos")) { gunnerX = Integer.parseInt(split[1]); gunnerY = Integer.parseInt(split[2]); gunnerZ = Integer.parseInt(split[3]); } } catch(Exception e) { FlansMod.log.error("" + e); } } public boolean isAmmo(BulletType type) { return ammo.contains(type); } public boolean isAmmo(ItemStack stack) { if(stack == null || stack.isEmpty()) return false; return stack.getItem() instanceof ItemBullet && isAmmo(((ItemBullet)stack.getItem()).type); } public static AAGunType getAAGun(String s) { for(AAGunType gun : infoTypes) { if(gun.shortName.equals(s)) return gun; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelAAGun.class); } @Override public void addLoot(LootTableLoadEvent event) { //Do not add AA guns to dungeon chests. That would be so op. } @Override protected void preRead(TypeFile file) { } @Override protected void postRead(TypeFile file) { if(numBarrels > 16) { FlansMod.log.warn("Detected AA Gun type with ludicrous number of barrels " + numBarrels); numBarrels = 16; } } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/AttachmentType.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import net.minecraft.client.model.ModelBase; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelAttachment; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.types.TypeFile; public class AttachmentType extends PaintableType implements IScope { public static ArrayList attachments = new ArrayList<>(); /** * The type of attachment. Each gun can have one barrel, one scope, one * grip, one stock and some number of generics up to a limit set by the gun */ public EnumAttachmentType type = EnumAttachmentType.generic; /** * This variable controls whether or not bullet sounds should be muffled */ public boolean silencer = false; /** * If true, then this attachment will act like a flashlight */ public boolean flashlight = false; /** * Flashlight range. How far away it lights things up */ public float flashlightRange = 10F; /** * Flashlight strength between 0 and 15 */ public int flashlightStrength = 12; // Gun behaviour modifiers /** * These stack between attachments and apply themselves to the gun's default * spread */ public float spreadMultiplier = 1F; /** * Likewise these stack and affect recoil */ public float recoilMultiplier = 1F; /** * Another stacking variable for damage */ public float damageMultiplier = 1F; /** * Melee damage modifier */ public float meleeDamageMultiplier = 1F; /** * Bullet speed modifier */ public float bulletSpeedMultiplier = 1F; public float shootDelayMultiplier = 1f; /** * This modifies the reload time, which is then rounded down to the nearest * tick */ public float reloadTimeMultiplier = 1F; /** * If set to anything other than null, then this attachment will override * the weapon's default firing mode */ public EnumFireMode modeOverride = null; public EnumSpreadPattern spreadPattern = null; // Scope variables (These variables only come into play for scope // attachments) /** * The zoomLevel of this scope */ public float zoomLevel = 1F; /** * The FOV zoom level of this scope */ public float FOVZoomLevel = 1F; /** * The overlay to render when using this scope */ public String zoomOverlay; /** * Whether to overlay a texture or not */ public boolean hasScopeOverlay = false; @SideOnly(Side.CLIENT) /** Model. Only applicable when the attachment is added to 3D guns */ public ModelAttachment model; // Some more mundane variables /** * The max stack size in the inventory */ public int maxStackSize = 1; public AttachmentType(TypeFile file) { super(file); attachments.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(split[0].equals("AttachmentType")) type = EnumAttachmentType.get(split[1]); else if(FMLCommonHandler.instance().getSide().isClient() && (split[0].equals("Model"))) model = FlansMod.proxy.loadModel(split[1], shortName, ModelAttachment.class); else if(split[0].equals("Silencer")) silencer = Boolean.parseBoolean(split[1].toLowerCase()); // Flashlight settings else if(split[0].equals("Flashlight")) flashlight = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("FlashlightRange")) flashlightRange = Float.parseFloat(split[1]); else if(split[0].equals("FlashlightStrength")) flashlightStrength = Integer.parseInt(split[1]); // Mode override else if(split[0].equals("ModeOverride")) modeOverride = EnumFireMode.getFireMode(split[1]); // Multipliers else if(split[0].equals("MeleeDamageMultiplier")) meleeDamageMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("DamageMultiplier")) damageMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("SpreadMultiplier")) spreadMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("RecoilMultiplier")) recoilMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("BulletSpeedMultiplier")) bulletSpeedMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("ShootDelayMultiplier")) shootDelayMultiplier = Float.parseFloat(split[1]); else if(split[0].equals("ReloadTimeMultiplier")) reloadTimeMultiplier = Float.parseFloat(split[1]); if(split[0].equals("SpreadPattern")) spreadPattern = EnumSpreadPattern.get(split[1]); // Scope Variables else if(split[0].equals("ZoomLevel")) zoomLevel = Float.parseFloat(split[1]); else if(split[0].equals("FOVZoomLevel")) FOVZoomLevel = Float.parseFloat(split[1]); else if(split[0].equals("ZoomOverlay")) { hasScopeOverlay = true; if(split[1].equals("None")) hasScopeOverlay = false; else zoomOverlay = split[1]; } } catch(Exception e) { FlansMod.log.error("Reading attachment file failed."); FlansMod.log.throwing(e); } } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelAttachment.class); } public static AttachmentType getFromNBT(NBTTagCompound tags) { ItemStack stack = new ItemStack(tags); if(stack != null && stack.getItem() instanceof ItemAttachment) return ((ItemAttachment)stack.getItem()).type; return null; } @Override public float getZoomFactor() { return zoomLevel; } @Override public boolean hasZoomOverlay() { return hasScopeOverlay; } @Override public String getZoomOverlay() { return zoomOverlay; } @Override public float getFOVFactor() { return FOVZoomLevel; } public static AttachmentType getAttachment(String s) { for(AttachmentType attachment : attachments) { if(attachment.shortName.equals(s)) return attachment; } return null; } @Override public void preRead(TypeFile file) { super.preRead(file); } @Override public void postRead(TypeFile file) { super.postRead(file); } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } @Override public float GetRecommendedScale() { return 100.0f; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/BulletType.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import java.util.List; import net.minecraft.client.model.ModelBase; import net.minecraft.item.Item; import net.minecraft.potion.PotionEffect; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EnumWeaponType; import com.flansmod.common.types.TypeFile; public class BulletType extends ShootableType { /** * The number of flak particles to spawn upon exploding */ public int flak = 0; /** * The type of flak particles to spawn */ public String flakParticles = "largesmoke"; /** * If true then this bullet will burn entites it hits */ public boolean setEntitiesOnFire = false; /** * Exclusively for driveable usage. Replaces old isBomb and isShell booleans with something more flexible */ public EnumWeaponType weaponType = EnumWeaponType.NONE; public String hitSound; public float hitSoundRange = 50; public boolean hasLight = false; public float penetratingPower = 1F; /** * Lock on variables. If true, then the bullet will search for a target at the moment it is fired */ public boolean lockOnToPlanes = false, lockOnToVehicles = false, lockOnToMechas = false, lockOnToPlayers = false, lockOnToLivings = false; /** * Lock on maximum angle for finding a target */ public float maxLockOnAngle = 45F; /** * Lock on force that pulls the bullet towards its prey */ public float lockOnForce = 1F; public String trailTexture = "defaultBulletTrail"; public ArrayList hitEffects = new ArrayList<>(); /** * The static bullets list */ public static List bullets = new ArrayList<>(); public BulletType(TypeFile file) { super(file); texture = "defaultBullet"; bullets.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(split[0].equals("FlakParticles")) flak = Integer.parseInt(split[1]); else if(split[0].equals("FlakParticleType")) flakParticles = split[1]; else if(split[0].equals("SetEntitiesOnFire")) setEntitiesOnFire = Boolean.parseBoolean(split[1]); else if(split[0].equals("HitSound")) { hitSound = split[1]; FlansMod.proxy.loadSound(contentPack, "sound", split[1]); } else if(split[0].equals("HitSoundRange")) hitSoundRange = Float.parseFloat(split[1]); else if(split[0].equals("Penetrates")) penetratingPower = (Boolean.parseBoolean(split[1].toLowerCase()) ? 1F : 0.25F); else if(split[0].equals("Penetration") || split[0].equals("PenetratingPower")) penetratingPower = Float.parseFloat(split[1]); else if(split[0].equals("Bomb")) weaponType = EnumWeaponType.BOMB; else if(split[0].equals("Shell")) weaponType = EnumWeaponType.SHELL; else if(split[0].equals("Missile")) weaponType = EnumWeaponType.MISSILE; else if(split[0].equals("WeaponType")) weaponType = EnumWeaponType.valueOf(split[1].toUpperCase()); else if(split[0].equals("TrailTexture")) trailTexture = split[1]; else if(split[0].equals("HasLight")) hasLight = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToDriveables")) lockOnToPlanes = lockOnToVehicles = lockOnToMechas = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToVehicles")) lockOnToVehicles = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToPlanes")) lockOnToPlanes = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToMechas")) lockOnToMechas = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToPlayers")) lockOnToPlayers = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("LockOnToLivings")) lockOnToLivings = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("MaxLockOnAngle")) maxLockOnAngle = Float.parseFloat(split[1]); else if(split[0].equals("LockOnForce") || split[0].equals("TurningForce")) lockOnForce = Float.parseFloat(split[1]); else if(split[0].equals("PotionEffect")) hitEffects.add(getPotionEffect(split)); } catch(Exception e) { FlansMod.log.error("Reading bullet file failed."); FlansMod.log.throwing(e); } } public static BulletType getBullet(String s) { for(BulletType bullet : bullets) { if(bullet.shortName.equals(s)) return bullet; } return null; } public static BulletType getBullet(Item item) { for(BulletType bullet : bullets) { if(bullet.item == item) return bullet; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelBase.class); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ContainerGunModTable.java ================================================ package com.flansmod.common.guns; import com.flansmod.common.FlansMod; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; public class ContainerGunModTable extends Container { private InventoryGunModTable inventory; public InventoryPlayer playerInv; public World world; public ContainerGunModTable(InventoryPlayer i, World w) { playerInv = i; inventory = new InventoryGunModTable(); world = w; //Gun slot SlotGun gunSlot = new SlotGun(inventory, 0, 80, 110, null); addSlotToContainer(gunSlot); //Attachment Slots addSlotToContainer(new SlotGun(inventory, 1, 54, 110, gunSlot)); addSlotToContainer(new SlotGun(inventory, 2, 80, 84, gunSlot)); addSlotToContainer(new SlotGun(inventory, 3, 106, 110, gunSlot)); addSlotToContainer(new SlotGun(inventory, 4, 80, 136, gunSlot)); for(int row = 0; row < 4; row++) { for(int col = 0; col < 2; col++) { addSlotToContainer(new SlotGun(inventory, 5 + row * 2 + col, 10 + col * 18, 83 + row * 18, gunSlot)); } } //Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(playerInv, col + row * 9 + 9, 8 + col * 18, 176 + row * 18)); } } //Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(playerInv, col, 8 + col * 18, 234)); } } @Override public void onContainerClosed(EntityPlayer player) { if(inventory.getStackInSlot(0) != null) player.dropItem(inventory.getStackInSlot(0), false); } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); Slot gunSlot = inventorySlots.get(0); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); // gun slot, 4 attach slots and 8 generics if(slotID >= 13) { if(slotStack.getItem() instanceof ItemGun && !gunSlot.getHasStack()) { gunSlot.putStack(slotStack); currentSlot.putStack(ItemStack.EMPTY.copy()); } if(slotStack.getItem() instanceof ItemAttachment) { for(int i = 1; i < 12; i++) { Slot attachmentSlot = inventorySlots.get(i); if(!attachmentSlot.getHasStack() && attachmentSlot.isItemValid(slotStack)) { attachmentSlot.putStack(slotStack); currentSlot.putStack(ItemStack.EMPTY.copy()); break; } } } return ItemStack.EMPTY.copy(); } else { if(!mergeItemStack(slotStack, 13, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return ItemStack.EMPTY.copy(); } currentSlot.onTake(player, slotStack); } return stack; } public void pressButton(boolean paint, boolean left) { //Nope. } public void clickPaintjob(int i) { ItemStack gunStack = inventory.getStackInSlot(0); if(gunStack != null && gunStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)gunStack.getItem()).GetType(); clickPaintjob(gunType.getPaintjob(i)); } } public void clickPaintjob(Paintjob paintjob) { ItemStack gunStack = inventory.getStackInSlot(0); if(gunStack != null && gunStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)gunStack.getItem()).GetType(); int numDyes = paintjob.dyesNeeded.length; boolean legendary = false; for(int n = 0; n < numDyes; n++) { if(paintjob.dyesNeeded[n].getItem() == FlansMod.rainbowPaintcan) { legendary = true; } } if(!playerInv.player.capabilities.isCreativeMode) { //Calculate which dyes we have in our inventory for(int n = 0; n < numDyes; n++) { int amountNeeded = paintjob.dyesNeeded[n].getCount(); boolean lookingForRainbow = paintjob.dyesNeeded[n].getItem() == FlansMod.rainbowPaintcan; for(int s = 0; s < playerInv.getSizeInventory(); s++) { ItemStack stack = playerInv.getStackInSlot(s); if(lookingForRainbow) { if(stack.getItem() == FlansMod.rainbowPaintcan) amountNeeded -= stack.getCount(); } else { if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == paintjob.dyesNeeded[n].getItemDamage()) amountNeeded -= stack.getCount(); } } //We don't have enough of this dye if(amountNeeded > 0) return; } for(int n = 0; n < numDyes; n++) { int amountNeeded = paintjob.dyesNeeded[n].getCount(); for(int s = 0; s < playerInv.getSizeInventory(); s++) { if(amountNeeded <= 0) continue; ItemStack stack = playerInv.getStackInSlot(s); boolean lookingForRainbow = paintjob.dyesNeeded[n].getItem() == FlansMod.rainbowPaintcan; if(lookingForRainbow) { if(stack.getItem() == FlansMod.rainbowPaintcan) { ItemStack consumed = playerInv.decrStackSize(s, amountNeeded); amountNeeded -= stack.getCount(); } } else { if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == paintjob.dyesNeeded[n].getItemDamage()) { ItemStack consumed = playerInv.decrStackSize(s, amountNeeded); amountNeeded -= consumed.getCount(); } } } } } //Paint the gun. This line is only reached if the player is in creative or they have had their dyes taken already //gunStack.getTagCompound().setString("Paint", paintjob.iconName); gunStack.setItemDamage(paintjob.ID); if(legendary) { if(!gunStack.hasTagCompound()) { gunStack.setTagCompound(new NBTTagCompound()); } if(!gunStack.getTagCompound().hasKey("display")) { gunStack.getTagCompound().setTag("display", new NBTTagCompound()); } if(!gunStack.getTagCompound().getCompoundTag("display").hasKey("Name")) { gunStack.getTagCompound().getCompoundTag("display").setString("Name", "\u00a7e" + playerInv.player.getName() + "'s " + gunStack.getDisplayName()); } gunStack.getTagCompound().setString("LegendaryCrafter", playerInv.player.getName()); } } } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityAAGun.java ================================================ package com.flansmod.common.guns; import org.lwjgl.input.Mouse; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.network.PacketAAGunAngles; import com.flansmod.common.network.PacketMGFire; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.vector.Vector3f; public class EntityAAGun extends Entity implements IEntityAdditionalSpawnData { private int sUpdateTime; private double sPosX; private double sPosY; private double sPosZ; private double sYaw; private double sPitch; private double field_9388_j; private double field_9387_k; private double field_9386_l; private int health; private int shootDelay; /** * Gun angles */ public float gunYaw, gunPitch; /** * Prev gun angles */ public float prevGunYaw, prevGunPitch; public float barrelRecoil[]; public AAGunType type; public Entity towedByEntity; public ItemStack[] ammo; // One per barrel public int reloadTimer; public int currentBarrel; // For cycling through firing each barrel public boolean mouseHeld; public boolean wasShooting; //Sentry stuff /** * Stops the sentry shooting whoever placed it or their teammates */ public EntityPlayer placer = null; /** * For getting the placer after a reload */ public String placerName = null; /** * The sentry's current target */ public Entity target = null; /** * How often to check for new targets */ public static final float targetAcquireInterval = 10; public int ticksSinceUsed = 0; private float yOffset; public EntityAAGun(World world) { super(world); preventEntitySpawning = true; setSize(2.0F, 2.0F); yOffset = 0F; gunYaw = 0; gunPitch = 0; shootDelay = 0; } public EntityAAGun(World world, AAGunType type1, double d, double d1, double d2, EntityPlayer p) { this(world); placer = p; placerName = p.getName(); type = type1; initType(); setPosition(d, d1, d2); } @Override public void setPosition(double d, double d1, double d2) { posX = d; posY = d1; posZ = d2; float f = width / 2.0F; float f1 = height; setEntityBoundingBox(new AxisAlignedBB(d - f, (d1 - yOffset), d2 - f, d + f, (d1 - yOffset) + f1, d2 + f)); } @Override public void setPositionAndRotationDirect(double d, double d1, double d2, float f, float f1, int i, boolean b) { sPosX = d; sPosY = d1; sPosZ = d2; sYaw = f; sPitch = f1; sUpdateTime = i; } public void initType() { health = type.health; barrelRecoil = new float[type.numBarrels]; ammo = new ItemStack[type.numBarrels]; for(int i = 0; i < type.numBarrels; i++) { ammo[i] = ItemStack.EMPTY.copy(); } } @Override protected void entityInit() { } @Override public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) { } @Override public void applyEntityCollision(Entity entity) { //if(entity != riddenByEntity) //super.applyEntityCollision(entity); } @Override public AxisAlignedBB getCollisionBox(Entity entity) { return entity.getEntityBoundingBox(); } @Override public boolean canBePushed() { return false; } @Override public double getMountedYOffset() { return 0D; } public void setMouseHeld(boolean held) { mouseHeld = held; } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { if(damagesource.damageType.equals("player")) { Entity player = damagesource.getTrueSource(); if(isRidingOrBeingRiddenBy(player)) { } else if(isBeingRidden()) { return getPassengers().get(0).attackEntityFrom(damagesource, i); } else if(TeamsManager.canBreakGuns) { setDead(); } } else { //setBeenAttacked(); health -= i; if(!world.isRemote && health <= 0) setDead(); } return true; } public Vec3d rotate(double x, double y, double z) { double cosYaw = Math.cos(180F - gunYaw * 3.14159265F / 180F); double sinYaw = Math.sin(180F - gunYaw * 3.14159265F / 180F); double cosPitch = Math.cos(gunPitch * 3.14159265F / 180F); double sinPitch = Math.sin(gunPitch * 3.14159265F / 180F); double newX = x * cosYaw + (y * sinPitch + z * cosPitch) * sinYaw; double newY = y * cosPitch - z * sinPitch; double newZ = -x * sinYaw + (y * sinPitch + z * cosPitch) * cosYaw; return new Vec3d(newX, newY, newZ); } @Override public boolean canBeCollidedWith() { return !isDead; } @Override public void onUpdate() { super.onUpdate(); prevGunYaw = gunYaw; prevGunPitch = gunPitch; ticksSinceUsed++; if(TeamsManager.aaLife > 0 && ticksSinceUsed > TeamsManager.aaLife * 20) { setDead(); } if(getControllingPassenger() != null) { ticksSinceUsed = 0; gunYaw = getControllingPassenger().rotationYaw - 90; gunPitch = getControllingPassenger().rotationPitch; } if(gunPitch > type.bottomViewLimit) gunPitch = type.bottomViewLimit; if(gunPitch < -type.topViewLimit) gunPitch = -type.topViewLimit; for(int i = 0; i < type.numBarrels; i++) barrelRecoil[i] *= 0.9F; if(shootDelay > 0) shootDelay--; // Sentry stuff if(isSentry()) { if(target != null && target.isDead) target = null; //Find a new target if we don't currently have one if(target == null && ticksExisted % targetAcquireInterval == 0) { target = getValidTarget(); } if(target != null) { double dX = target.posX - posX; double dY = target.posY - (posY + 1.5F); double dZ = target.posZ - posZ; double distanceToTarget = Math.sqrt(dX * dX + dY * dY + dZ * dZ); if(distanceToTarget > type.targetRange) target = null; else { float newYaw = 180F + (float)Math.atan2(dZ, dX) * 180F / 3.14159F; float newPitch = -(float)Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180F / 3.14159F; float turnSpeed = 0.25F; gunYaw += (newYaw - gunYaw) * turnSpeed; gunPitch += (newPitch - gunPitch) * turnSpeed; } } } // apply gravity if(!onGround && !world.isRemote) motionY -= 9.8D / 400D; // update motion motionX *= 0.5; motionZ *= 0.5; move(MoverType.SELF, motionX, motionY, motionZ); if(world.isRemote && getControllingPassenger() != null && getControllingPassenger() == FMLClientHandler.instance().getClient().player) { checkForShooting(); } if(world.isRemote) { if(sUpdateTime > 0) { double d1 = posX + (sPosX - posX) / sUpdateTime; double d5 = posY + (sPosY - posY) / sUpdateTime; double d9 = posZ + (sPosZ - posZ) / sUpdateTime; double d12; for(d12 = sYaw - rotationYaw; d12 < -180D; d12 += 360D) { } for(; d12 >= 180D; d12 -= 360D) { } rotationYaw += d12 / sUpdateTime; rotationPitch += (sPitch - rotationPitch) / sUpdateTime; sUpdateTime--; setPosition(d1, d5, d9); setRotation(rotationYaw, rotationPitch); } return; } if(getControllingPassenger() != null && getControllingPassenger().isDead) { removePassengers(); } // Decrement the reload timer and reload if(reloadTimer > 0) reloadTimer--; //If it is 0 or less, go ahead and reload else { for(int i = 0; i < type.numBarrels; i++) { if(ammo[i] != null && !ammo[i].isEmpty() && ammo[i].getItemDamage() == ammo[i].getMaxDamage()) { ammo[i] = ItemStack.EMPTY.copy(); // Scrap metal output? } if((ammo[i] == null || ammo[i].isEmpty()) && getControllingPassenger() != null && getControllingPassenger() instanceof EntityPlayer) { int slot = findAmmo(((EntityPlayer)getControllingPassenger())); if(slot >= 0) { ammo[i] = ((EntityPlayer)getControllingPassenger()).inventory.getStackInSlot(slot); if(!((EntityPlayer)getControllingPassenger()).capabilities.isCreativeMode) ((EntityPlayer)getControllingPassenger()).inventory.decrStackSize(slot, 1); reloadTimer = type.reloadTime; PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, type.reloadSound, true); } } } } if(!world.isRemote && reloadTimer <= 0 && shootDelay <= 0) { Boolean shootPlayer = mouseHeld && getControllingPassenger() instanceof EntityPlayerMP; if (target != null || shootPlayer) { EntityPlayerMP player = shootPlayer ? (EntityPlayerMP)getControllingPassenger() : null; for(int j = 0; j < type.numBarrels; j++) { int ammoSlot = j; if(type.shareAmmo) ammoSlot = 0; if(shootDelay <= 0 && ammo[ammoSlot] != null && !ammo[ammoSlot].isEmpty() && (!type.fireAlternately || type.fireAlternately && currentBarrel == j)) { // Fire BulletType bullet = BulletType.getBullet(ammo[ammoSlot].getItem()); if(shootPlayer) { if(!player.capabilities.isCreativeMode) ammo[ammoSlot].damageItem(1, player); } else { ammo[ammoSlot].setItemDamage(ammo[ammoSlot].getItemDamage() + 1); } shootDelay = type.shootDelay; barrelRecoil[j] = type.recoil; Vec3d origin = rotate(type.barrelX[currentBarrel] / 16D - type.barrelZ[currentBarrel] / 16D, type.barrelY[currentBarrel] / 16D, type.barrelX[currentBarrel] / 16D + type.barrelZ[currentBarrel] / 16D).add(posX, posY, posZ); Double radianYaw = Math.toRadians(gunYaw + 90F); Double radianPitch = Math.toRadians(gunPitch); Vector3f shootingDirection = new Vector3f(-Math.sin(radianYaw), Math.cos(radianYaw)*-Math.sin(radianPitch), Math.cos(radianYaw)*Math.cos(radianPitch)); FireableGun weapon = new FireableGun(type, (float)type.damage, (float)type.accuracy, (float)type.damage, EnumSpreadPattern.circle); FiredShot shot = new FiredShot(weapon, bullet, this, player); //TODO use Vec3d ShotHandler.fireGun(world, shot, bullet.numBullets, new Vector3f(origin), shootingDirection); PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, type.shootSound, true); } } currentBarrel = (currentBarrel + 1) % type.numBarrels; } } if(!world.isRemote) { FlansMod.getPacketHandler().sendToAllAround(new PacketAAGunAngles(this), posX, posY, posZ, 50F, dimension); } } public boolean isSentry() { return type.targetMobs || type.targetPlayers; } public Entity getValidTarget() { if(world.isRemote) return null; if(placer == null && placerName != null) placer = world.getPlayerEntityByName(placerName); for(Object obj : world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().expand(type.targetRange, type.targetRange, type.targetRange))) { Entity candidateEntity = (Entity)obj; if((type.targetMobs && candidateEntity instanceof EntityMob) || (type.targetPlayers && candidateEntity instanceof EntityPlayer)) { //Check that this entity is actually in range and visible if(candidateEntity.getDistanceSq(this) < type.targetRange * type.targetRange) { if(candidateEntity instanceof EntityPlayer) { if(candidateEntity == placer || candidateEntity.getName().equals(placerName)) continue; if(TeamsManager.enabled && TeamsManager.getInstance().currentRound != null && placer != null) { PlayerData placerData = PlayerHandler.getPlayerData(placer, world.isRemote ? Side.CLIENT : Side.SERVER); PlayerData candidateData = PlayerHandler.getPlayerData((EntityPlayer)candidateEntity, world.isRemote ? Side.CLIENT : Side.SERVER); if(candidateData.team == Team.spectators || candidateData.team == null) continue; if(!TeamsManager.getInstance().currentRound.gametype.playerCanAttack((EntityPlayerMP)placer, placerData.team, (EntityPlayerMP)candidateEntity, candidateData.team)) continue; } } return candidateEntity; } } } return null; } @SideOnly(Side.CLIENT) private void checkForShooting() { //Send a packet! if(Mouse.isButtonDown(0) && !wasShooting && !FlansMod.proxy.isScreenOpen()) { FlansMod.getPacketHandler().sendToServer(new PacketMGFire(true)); wasShooting = true; } else if(!Mouse.isButtonDown(0) && wasShooting) { FlansMod.getPacketHandler().sendToServer(new PacketMGFire(false)); wasShooting = false; } } @Override public void setDead() { super.setDead(); // Drop gun if(world.isRemote) return; dropItem(type.getItem(), 1); // Drop ammo boxes for(ItemStack stack : ammo) { if(stack != null && !stack.isEmpty()) entityDropItem(stack, 0.5F); } } @Override public void updatePassenger(Entity passenger) { double x = type.gunnerX / 16D; double y = type.gunnerY / 16D; double z = type.gunnerZ / 16D; double cosYaw = Math.cos((-gunYaw / 180D) * 3.1415926535897931D); double sinYaw = Math.sin((-gunYaw / 180D) * 3.1415926535897931D); double cosPitch = Math.cos((gunPitch / 180D) * 3.1415926535897931D); double sinPitch = Math.sin((gunPitch / 180D) * 3.1415926535897931D); double x2 = x * cosYaw + z * sinYaw; double z2 = -x * sinYaw + z * cosYaw; passenger.setPosition(posX + x2, posY + y, posZ + z2); } @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { nbttagcompound.setString("Type", type.shortName); nbttagcompound.setInteger("Health", health); nbttagcompound.setFloat("RotationYaw", rotationYaw); nbttagcompound.setFloat("RotationPitch", rotationPitch); for(int i = 0; i < type.numBarrels; i++) { if(ammo[i] != null) nbttagcompound.setTag("Ammo " + i, ammo[i].writeToNBT(new NBTTagCompound())); } if (placer != null) { nbttagcompound.setString("Placer", placer.getName()); } else if (placerName != null) { nbttagcompound.setString("Placer", placerName); } } @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { type = AAGunType.getAAGun(nbttagcompound.getString("Type")); initType(); health = nbttagcompound.getInteger("Health"); rotationYaw = nbttagcompound.getFloat("RotationYaw"); rotationPitch = nbttagcompound.getFloat("RotationPitch"); for(int i = 0; i < type.numBarrels; i++) { ammo[i] = new ItemStack(nbttagcompound.getCompoundTag("Ammo " + i)); } placerName = nbttagcompound.getString("Placer"); } @Override public boolean processInitialInteract(EntityPlayer entityplayer, EnumHand hand) //interact : change back when Forge updates { // Player right clicked on gun // Mount gun if(getControllingPassenger() != null && (getControllingPassenger() instanceof EntityPlayer) && getControllingPassenger() != entityplayer) { return true; } if(!world.isRemote) { if(getControllingPassenger() == entityplayer) { entityplayer.dismountRidingEntity(); return true; } if(!isSentry()) entityplayer.startRiding(this); for(int i = 0; i < (type.shareAmmo ? 1 : type.numBarrels); i++) { if(ammo[i] == null || ammo[i].isEmpty()) { int slot = findAmmo(entityplayer); if(slot >= 0) { ammo[i] = entityplayer.inventory.getStackInSlot(slot).copy(); ammo[i].setCount(1); if(!entityplayer.capabilities.isCreativeMode) entityplayer.inventory.decrStackSize(slot, 1); reloadTimer = type.reloadTime; world.playSound(posX, posY, posZ, FlansModResourceHandler.getSoundEvent(type.reloadSound), SoundCategory.PLAYERS, 1.0F, 1.0F / (rand.nextFloat() * 0.4F + 0.8F), true); } } } } return true; } //TODO aa are accepting any ammo for any weapon public int findAmmo(EntityPlayer player) { for(int i = 0; i < player.inventory.getSizeInventory(); i++) { ItemStack stack = player.inventory.getStackInSlot(i); if(type.isAmmo(stack)) { return i; } } return -1; } @Override public void writeSpawnData(ByteBuf data) { ByteBufUtils.writeUTF8String(data, type.shortName); } @Override public void readSpawnData(ByteBuf data) { try { type = AAGunType.getAAGun(ByteBufUtils.readUTF8String(data)); initType(); } catch(Exception e) { FlansMod.log.error("Failed to retreive AA gun type from server."); super.setDead(); FlansMod.log.throwing(e); } } @Override public boolean canRiderInteract() { return false; } @Override public ItemStack getPickedResult(RayTraceResult target) { return new ItemStack(type.item, 1, 0); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityBullet.java ================================================ package com.flansmod.common.guns; import java.util.List; import java.util.UUID; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.particle.Particle; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTUtil; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.FlansModClient; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.guns.raytracing.FlansModRaytracer; import com.flansmod.common.guns.raytracing.FlansModRaytracer.BulletHit; import com.flansmod.common.types.InfoType; import com.flansmod.common.vector.Vector3f; import io.netty.buffer.ByteBuf; public class EntityBullet extends EntityShootable implements IEntityAdditionalSpawnData { private static final DataParameter BULLET_TYPE = EntityDataManager.createKey(EntityBullet.class, DataSerializers.STRING); private static int bulletLife = 600; // Kill bullets after 30 seconds public int ticksInAir; private FiredShot shot; /** * For homing missiles */ public Entity lockedOnTo; private float currentPenetratingPower; @SideOnly(Side.CLIENT) private boolean playedFlybySound; /** * These values are used to store the UUIDs until the next entity update is performed. This prevents issues caused by the loading order */ private UUID playeruuid; private UUID shooteruuid; private boolean checkforuuids; public EntityBullet(World world) { super(world); setSize(0.5F, 0.5F); } public EntityBullet(World world, FiredShot shot, Vec3d origin, Vec3d direction) { this(world); ticksInAir = 0; this.shot = shot; this.dataManager.set(BULLET_TYPE, shot.getBulletType().shortName); setPosition(origin.x, origin.y, origin.z); motionX = direction.x; motionY = direction.y; motionZ = direction.z; setArrowHeading(motionX, motionY, motionZ, shot.getFireableGun().getGunSpread() * shot.getBulletType().bulletSpread, shot.getFireableGun().getBulletSpeed()); currentPenetratingPower = shot.getBulletType().penetratingPower; } @Override protected void entityInit() { this.dataManager.register(BULLET_TYPE, null); } public void setArrowHeading(double d, double d1, double d2, float spread, float speed) { spread /= 5F; float f2 = MathHelper.sqrt(d * d + d1 * d1 + d2 * d2); d /= f2; d1 /= f2; d2 /= f2; d *= speed; d1 *= speed; d2 *= speed; d += rand.nextGaussian() * 0.005D * spread * speed; d1 += rand.nextGaussian() * 0.005D * spread * speed; d2 += rand.nextGaussian() * 0.005D * spread * speed; motionX = d; motionY = d1; motionZ = d2; float f3 = MathHelper.sqrt(d * d + d2 * d2); prevRotationYaw = rotationYaw = (float)((Math.atan2(d, d2) * 180D) / 3.1415927410125732D); prevRotationPitch = rotationPitch = (float)((Math.atan2(d1, f3) * 180D) / 3.1415927410125732D); getLockOnTarget(); } /** * Find the entity nearest to the missile's trajectory, anglewise */ private void getLockOnTarget() { BulletType type = shot.getBulletType(); if(type.lockOnToPlanes || type.lockOnToVehicles || type.lockOnToMechas || type.lockOnToLivings || type.lockOnToPlayers) { Vector3f motionVec = new Vector3f(motionX, motionY, motionZ); Entity closestEntity = null; float closestAngle = type.maxLockOnAngle * 3.14159265F / 180F; for(Object obj : world.loadedEntityList) { Entity entity = (Entity)obj; if((type.lockOnToMechas && entity instanceof EntityMecha) || (type.lockOnToVehicles && entity instanceof EntityVehicle) || (type.lockOnToPlanes && entity instanceof EntityPlane) || (type.lockOnToPlayers && entity instanceof EntityPlayer) || (type.lockOnToLivings && entity instanceof EntityLivingBase)) { Vector3f relPosVec = new Vector3f(entity.posX - posX, entity.posY - posY, entity.posZ - posZ); float angle = Math.abs(Vector3f.angle(motionVec, relPosVec)); if(angle < closestAngle) { closestEntity = entity; closestAngle = angle; } } } if(closestEntity != null) lockedOnTo = closestEntity; } } @Override public void setVelocity(double d, double d1, double d2) { motionX = d; motionY = d1; motionZ = d2; if(prevRotationPitch == 0.0F && prevRotationYaw == 0.0F) { float f = MathHelper.sqrt(d * d + d2 * d2); prevRotationYaw = rotationYaw = (float)((Math.atan2(d, d2) * 180D) / 3.1415927410125732D); prevRotationPitch = rotationPitch = (float)((Math.atan2(d1, f) * 180D) / 3.1415927410125732D); setLocationAndAngles(posX, posY, posZ, rotationYaw, rotationPitch); } } @Override public void onUpdate() { super.onUpdate(); try { //This checks if the shooter and/or player can be found. If they are loaded/online they will be included in the FiredShot data, if not this data will be deleted/ignored if (checkforuuids) { EntityPlayerMP player = null; Entity shooter = null; if (playeruuid != null) { for (Entity entity : world.loadedEntityList) { if (entity.getUniqueID().equals(playeruuid) && entity instanceof EntityPlayerMP) { player = (EntityPlayerMP)entity; break; } } playeruuid = null; } if (shooteruuid != null) { if (player != null && shooteruuid.equals(player.getUniqueID())) { shooter = player; } else { for (Entity entity : world.loadedEntityList) { if (entity.getUniqueID().equals(shooteruuid)) { shooter = entity; break; } } } shooteruuid = null; } if (shooter != null) { shot = new FiredShot(shot.getFireableGun(), shot.getBulletType(), shooter, player); } checkforuuids = false; } BulletType type = this.getFiredShot().getBulletType(); // Movement dampening variables float drag = 0.99F; float gravity = 0.02F; // If the bullet is in water, spawn particles and increase the drag if(isInWater()) { if (world.isRemote) { for(int i = 0; i < 4; i++) { float bubbleMotion = 0.25F; world.spawnParticle(EnumParticleTypes.WATER_BUBBLE, posX - motionX * bubbleMotion, posY - motionY * bubbleMotion, posZ - motionZ * bubbleMotion, motionX, motionY, motionZ); } } drag = 0.8F; } motionX *= drag; motionY *= drag; motionZ *= drag; motionY -= gravity * type.fallSpeed; // Apply motion this.setPosition(posX + motionX, posY + motionY, posZ + motionZ); // Recalculate the angles from the new motion float motionXZ = MathHelper.sqrt(motionX * motionX + motionZ * motionZ); rotationYaw = (float)((Math.atan2(motionX, motionZ) * 180D) / 3.1415927410125732D); rotationPitch = (float)((Math.atan2(motionY, motionXZ) * 180D) / 3.1415927410125732D); // Reset the range of the angles for(; rotationPitch - prevRotationPitch < -180F; prevRotationPitch -= 360F) { } for(; rotationPitch - prevRotationPitch >= 180F; prevRotationPitch += 360F) { } for(; rotationYaw - prevRotationYaw < -180F; prevRotationYaw -= 360F) { } for(; rotationYaw - prevRotationYaw >= 180F; prevRotationYaw += 360F) { } rotationPitch = prevRotationPitch + (rotationPitch - prevRotationPitch) * 0.2F; rotationYaw = prevRotationYaw + (rotationYaw - prevRotationYaw) * 0.2F; if(world.isRemote) { onUpdateClient(); return; } if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugVector(world, new Vector3f(posX, posY, posZ), new Vector3f(motionX, motionY, motionZ), 20)); // Check the fuse to see if the bullet should explode ticksInAir++; if(ticksInAir > type.fuse && type.fuse > 0 && !isDead) { setDead(); } if(ticksExisted > bulletLife) { setDead(); } if(isDead) return; Vector3f origin = new Vector3f(posX, posY, posZ); Vector3f motion = new Vector3f(motionX, motionY, motionZ); if(!world.isRemote) { Entity ignore = shot.getPlayerOptional().isPresent() ? shot.getPlayerOptional().get() : shot.getShooterOptional().orElse(null); Integer ping = 0; if (shot.getPlayerOptional().isPresent()) ping = shot.getPlayerOptional().get().ping; List hits = FlansModRaytracer.Raytrace(world, ignore, ticksInAir > 20, this, origin, motion, ping, 0f); // We hit something if(!hits.isEmpty()) { for(BulletHit bulletHit : hits) { Vector3f hitPos = new Vector3f(origin.x + motion.x * bulletHit.intersectTime, origin.y + motion.y * bulletHit.intersectTime, origin.z + motion.z * bulletHit.intersectTime); currentPenetratingPower = ShotHandler.OnHit(world, hitPos, motion, shot, bulletHit, currentPenetratingPower); if (currentPenetratingPower <= 0f) { ShotHandler.onDetonate(world, shot, hitPos); setDead(); break; } } } } //TODO Client homing fix // Apply homing action if(lockedOnTo != null) { double dX = lockedOnTo.posX - posX; double dY = lockedOnTo.posY - posY; double dZ = lockedOnTo.posZ - posZ; double dXYZ = dX * dX + dY * dY + dZ * dZ; Vector3f relPosVec = new Vector3f(dX, dY, dZ); float angle = Math.abs(Vector3f.angle(motion, relPosVec)); double lockOnPull = (angle) * type.lockOnForce; lockOnPull = lockOnPull * lockOnPull; motionX *= 0.95f; motionY *= 0.95f; motionZ *= 0.95f; motionX += lockOnPull * dX / dXYZ; motionY += lockOnPull * dY / dXYZ; motionZ += lockOnPull * dZ / dXYZ; } } catch (Exception ex) { ex.printStackTrace(); super.setDead(); } } @SideOnly(Side.CLIENT) private void onUpdateClient() { // Particles if(shot.getBulletType().trailParticles) { spawnParticles(); } if(getDistanceSq(Minecraft.getMinecraft().player) < 5 && !playedFlybySound) { playedFlybySound = true; FMLClientHandler.instance().getClient().getSoundHandler() .playSound(new PositionedSoundRecord(FlansModResourceHandler.getSoundEvent("bulletFlyby"), SoundCategory.HOSTILE, 10F, 1.0F / (rand.nextFloat() * 0.4F + 0.8F), (float)posX, (float)posY, (float)posZ)); } } @SideOnly(Side.CLIENT) private void spawnParticles() { double dX = (posX - prevPosX) / 10; double dY = (posY - prevPosY) / 10; double dZ = (posZ - prevPosZ) / 10; float spread = 0.1F; for(int i = 0; i < 10; i++) { Particle particle = FlansModClient.getParticle(shot.getBulletType().trailParticleType, world, prevPosX + dX * i + rand.nextGaussian() * spread, prevPosY + dY * i + rand.nextGaussian() * spread, prevPosZ + dZ * i + rand.nextGaussian() * spread); // TODO: [1.12] once again, render distance //if (particle != null && Minecraft.getMinecraft().gameSettings.fancyGraphics) // particle.renderDistanceWeight = 100D; // world.spawnEntity(particle); } } @Override public void setDead() { if(isDead) return; super.setDead(); } @Override public void writeEntityToNBT(NBTTagCompound tag) { tag.setString("type", shot.getBulletType().shortName); FireableGun gun = shot.getFireableGun(); //this data will only be present and saved on the server side if (gun != null) { NBTTagCompound fireablegun = new NBTTagCompound(); fireablegun.setInteger("infotype", gun.getInfoType().shortName.hashCode()); fireablegun.setFloat("spread", gun.getGunSpread()); fireablegun.setFloat("speed", gun.getBulletSpeed()); fireablegun.setFloat("damage", gun.getDamage()); fireablegun.setFloat("vehicledamage", gun.getDamageAgainstVehicles()); tag.setTag("fireablegun",fireablegun); shot.getPlayerOptional().ifPresent((EntityPlayerMP player) -> { NBTTagCompound compound = NBTUtil.createUUIDTag(player.getUniqueID()); tag.setTag("player", compound); }); shot.getShooterOptional().ifPresent((Entity shooter) -> { NBTTagCompound compound = NBTUtil.createUUIDTag(shooter.getUniqueID()); tag.setTag("shooter", compound); }); } } @Override public void readEntityFromNBT(NBTTagCompound tag) { FireableGun fireablegun = null; String shortName = tag.getString("type"); BulletType type = BulletType.getBullet(shortName); this.dataManager.set(BULLET_TYPE, shortName); if (tag.hasKey("fireablegun")) { NBTTagCompound gun = tag.getCompoundTag("fireablegun"); fireablegun = new FireableGun(InfoType.getType(gun.getInteger("infotype")), gun.getFloat("damage"), gun.getFloat("vehicledamage"), gun.getFloat("spread"), gun.getFloat("speed"), EnumSpreadPattern.circle); } if (tag.hasKey("player")) { playeruuid = NBTUtil.getUUIDFromTag(tag.getCompoundTag("player")); checkforuuids = true; } if (tag.hasKey("shooter")) { shooteruuid = NBTUtil.getUUIDFromTag(tag.getCompoundTag("shooter")); checkforuuids = true; } shot = new FiredShot(fireablegun, type); } @Override public void writeSpawnData(ByteBuf data) { data.writeDouble(motionX); data.writeDouble(motionY); data.writeDouble(motionZ); } @Override public void readSpawnData(ByteBuf data) { try { motionX = data.readDouble(); motionY = data.readDouble(); motionZ = data.readDouble(); } catch(Exception e) { FlansMod.log.error("Failed to read bullet owner from server."); super.setDead(); FlansMod.log.throwing(e); } } @Override public boolean isBurning() { return false; } @Override public boolean canBePushed() { return false; } public FiredShot getFiredShot() { if (shot == null) { //we dont have this object, therefore we are on the client side and need to construct it shot = new FiredShot(null, BulletType.getBullet(this.dataManager.get(BULLET_TYPE))); } return shot; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityDamageSourceFlan.java ================================================ package com.flansmod.common.guns; import javax.annotation.Nullable; import com.flansmod.common.PlayerHandler; import com.flansmod.common.types.InfoType; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EntityDamageSourceIndirect; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; public class EntityDamageSourceFlan extends EntityDamageSourceIndirect{ private InfoType weapon; private EntityPlayer shooter; private boolean headshot; /** * @param s Name of the damage source (Usually the shortName of the gun) * @param entity The Entity causing the damage (e.g. Grenade). Can be the same as 'player' * @param player The Player responsible for the damage * @param wep The InfoType of weapon used */ public EntityDamageSourceFlan(String s, Entity entity, EntityPlayer player, InfoType wep) { this(s, entity, player, wep, false); } /** * @param s Name of the damage source (Usually the shortName of the gun) * @param entity The Entity causing the damage (e.g. Grenade). Can be the same as 'player' * @param player The Player responsible for the damage * @param wep The InfoType of weapon used * @param headshot True if this was a headshot, false if not */ public EntityDamageSourceFlan(String s, Entity entity, EntityPlayer player, InfoType wep, boolean headshot) { super(s, entity, player); weapon = wep; shooter = player; this.headshot = headshot; } @Override public ITextComponent getDeathMessage(EntityLivingBase living) { if(!(living instanceof EntityPlayer) || shooter == null || PlayerHandler.getPlayerData(shooter) == null) { if(shooter == null) { return new TextComponentString(living.getName() + " was shot"); } else return new TextComponentString(living.getName() + " was shot by " + shooter.getName()); } return new TextComponentString("#flansmod"); } /** * @return The weapon (InfoType) used to cause this damage */ public InfoType getWeapon() { return weapon; } /** * @return The Player responsible for this damage */ public EntityPlayer getCausedPlayer() { return shooter; } /** * @return True if this is a headshot, false if not */ public boolean isHeadshot() { return headshot; } @Override @Nullable public Vec3d getDamageLocation() { if(damageSourceEntity == null) return new Vec3d(0d, 0d, 0d); return super.getDamageLocation(); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityGrenade.java ================================================ package com.flansmod.common.guns; import java.util.List; import java.util.Optional; import io.netty.buffer.ByteBuf; import net.minecraft.block.material.Material; import net.minecraft.client.particle.Particle; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.FlansModExplosion; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.network.PacketFlak; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.ItemTeamArmour; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.types.InfoType; import com.flansmod.common.util.BlockUtil; import com.flansmod.common.vector.Vector3f; public class EntityGrenade extends EntityShootable implements IEntityAdditionalSpawnData { public GrenadeType type; /** * Contains the player who is responsible for the thrown grenade */ private Optional player = Optional.empty(); /** * The Entity who has thrown the grenade */ private Optional thrower = Optional.empty(); /** * This is to avoid players grenades teamkilling after they switch team */ public Team teamOfThrower; /** * Yeah, I want my grenades to have fancy physics */ public RotatedAxes axes = new RotatedAxes(); public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); public float prevRotationRoll = 0F; /** * Set to the smoke amount when the grenade detonates and decremented every tick after that */ public int smokeTime = 0; /** * Set to true when smoke grenade detonates */ public boolean smoking = false; /** * Set to true when a sticky grenade sticks. Impedes further movement */ public boolean stuck = false; /** * Stores the position of the block this grenade is stuck to. Used to determine when to unstick */ public int stuckToX, stuckToY, stuckToZ; /** * Stop repeat detonations */ public boolean detonated = false; /** * For deployable bags */ public int numUsesRemaining = 0; public EntityGrenade(World w) { super(w); } /** * General constructor. Example usecase: grenades spawned via console command * * @param w World in which the grenade will spawn in * @param pos Position the grenade will spawn at * @param g GrenadeType of the grenade * @param rotationPitch Pitch of the direction the grenade will fly * @param rotationYaw Yaw of the direction the grenade will fly */ public EntityGrenade(World w, Vector3f pos, GrenadeType g, float rotationPitch, float rotationYaw) { this(w); setPosition(pos.getX(), pos.getY(), pos.getZ()); type = g; numUsesRemaining = type.numUses; setSize(g.hitBoxSize, g.hitBoxSize); //Set the grenade to be facing the way the Pitch and Yaw variables define axes.setAngles(rotationYaw + 90F, g.spinWhenThrown ? rotationPitch : 0F, 0F); this.rotationYaw = prevRotationYaw = g.spinWhenThrown ? rotationYaw + 90F : 0F; this.rotationPitch = prevRotationPitch = rotationPitch; //Give the grenade velocity in the direction the player is looking float speed = 0.5F * type.throwSpeed; motionX = axes.getXAxis().x * speed; motionY = axes.getXAxis().y * speed; motionZ = axes.getXAxis().z * speed; if(type.spinWhenThrown) angularVelocity = new Vector3f(0F, 0F, 10F); if(type.throwSound != null) PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.throwSound, true); } /** * General constructor for entitys throwing grenades. This should not be used when a player throws the grenade * * @param entity Entity throwing the grenade * @param g GrenadeType of the grenade */ public EntityGrenade(EntityLivingBase entity, GrenadeType g) { this(entity.world, new Vector3f(entity.getPositionVector().add(new Vec3d(0, entity.getEyeHeight(), 0))), g, entity.rotationPitch, entity.rotationYaw); this.thrower = Optional.of(entity); } /** * When a player throws a grenade directly this constructor should be used * * @param player Player throwing the grenade * @param g GrenadeType of the grenade */ public EntityGrenade(EntityPlayer player, GrenadeType g) { this((EntityLivingBase)player, g); this.player = Optional.of(player); } /** * Constructor for grenades thrown where a player and/or a entity can be associated with. * E.g. mecha using a grenade launcher. In this case the 'entity' is the mecha and the 'player' the player controlling the mecha * * @param w World in which the grenade will spawn in * @param pos Position the grenade will spawn at * @param g GrenadeType of the grenade * @param rotationPitch Pitch of the direction the grenade will fly * @param rotationYaw Yaw of the direction the grenade will fly * @param player The player that is responsible for throwing the grenade * @param entity The entity throwing the grenade. Can be the same as 'player' */ public EntityGrenade(World w, Vector3f pos, GrenadeType g, float rotationPitch, float rotationYaw, Optional player, Optional entity) { this(w, pos, g, rotationPitch, rotationYaw); this.thrower = entity; this.player = player; } @Override public void onUpdate() { super.onUpdate(); //Quiet despawning if(type == null || (type.despawnTime > 0 && ticksExisted > type.despawnTime)) { detonated = true; setDead(); return; } //Visuals if(world.isRemote) { if(type.trailParticles) { double dX = (posX - prevPosX) / 10; double dY = (posY - prevPosY) / 10; double dZ = (posZ - prevPosZ) / 10; for(int i = 0; i < 10; i++) { Particle particle = FlansModClient.getParticle(type.trailParticleType, world, prevPosX + dX * i, prevPosY + dY * i, prevPosZ + dZ * i); // TODO: [1.12] Particles //if(particle != null && Minecraft.getMinecraft().gameSettings.fancyGraphics) // particle.renderDistanceWeight = 100D; //world.spawnEntity(particle); } } } //Smoke if(smoking) { //Send flak packet to spawn particles FlansMod.getPacketHandler().sendToAllAround(new PacketFlak(posX, posY, posZ, 50, type.smokeParticleType), posX, posY, posZ, 30, dimension); // List list = world.getEntitiesWithinAABB(EntityLivingBase.class, getEntityBoundingBox().expand(type.smokeRadius, type.smokeRadius, type.smokeRadius)); for(Object obj : list) { EntityLivingBase entity = ((EntityLivingBase)obj); if(entity.getDistanceSq(this) < type.smokeRadius * type.smokeRadius) { //Do some checks first boolean smokeThem = true; for(int i = 0; i < EntityEquipmentSlot.values().length; i++) { //If any currently equipped item has smoke protection (gas masks), stop the effects ItemStack stack = entity.getItemStackFromSlot(EntityEquipmentSlot.values()[i]); if(stack != null && stack.getItem() instanceof ItemTeamArmour) { if(((ItemTeamArmour)stack.getItem()).type.smokeProtection) smokeThem = false; } } if(smokeThem) for(PotionEffect effect : type.smokeEffects) entity.addPotionEffect(new PotionEffect(effect)); } } smokeTime--; if(smokeTime == 0) setDead(); } //Detonation conditions if(!world.isRemote) { if(ticksExisted > type.fuse && type.fuse > 0) detonate(); //If this grenade has a proximity trigger, check for living entities within it's range if(type.livingProximityTrigger > 0 || type.driveableProximityTrigger > 0) { float checkRadius = Math.max(type.livingProximityTrigger, type.driveableProximityTrigger); List list = world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().expand(checkRadius, checkRadius, checkRadius)); for(Object obj : list) { if(obj == thrower && ticksExisted < 10) continue; if(obj instanceof EntityLivingBase && getDistanceSq((Entity)obj) < type.livingProximityTrigger * type.livingProximityTrigger) { //If we are in a gametype and both thrower and triggerer are playing, check for friendly fire if(TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && obj instanceof EntityPlayerMP && player.isPresent()) { if(!TeamsManager.getInstance().currentRound.gametype.playerAttacked((EntityPlayerMP)obj, new EntityDamageSourceFlan(type.shortName, this, player.get(), type))) continue; } if(type.damageToTriggerer > 0) ((EntityLivingBase)obj).attackEntityFrom(getGrenadeDamage(), type.damageToTriggerer); detonate(); break; } if(obj instanceof EntityDriveable && getDistanceSq((Entity)obj) < type.driveableProximityTrigger * type.driveableProximityTrigger) { if(type.damageToTriggerer > 0) ((EntityDriveable)obj).attackEntityFrom(getGrenadeDamage(), type.damageToTriggerer); detonate(); break; } } } } //If the block we were stuck to is gone, unstick if(stuck && world.isAirBlock(new BlockPos(stuckToX, stuckToY, stuckToZ))) stuck = false; //Physics and motion (Don't move if stuck) if(!stuck && !type.stickToThrower) { prevRotationYaw = axes.getYaw(); prevRotationPitch = axes.getPitch(); prevRotationRoll = axes.getRoll(); if(angularVelocity.lengthSquared() > 0.00000001F) axes.rotateLocal(angularVelocity.length(), angularVelocity.normalise(null)); Vector3f posVec = new Vector3f(posX, posY, posZ); Vector3f motVec = new Vector3f(motionX, motionY, motionZ); Vector3f nextPosVec = Vector3f.add(posVec, motVec, null); //Raytrace the motion of this grenade RayTraceResult hit = world.rayTraceBlocks(posVec.toVec3(), nextPosVec.toVec3()); //If we hit block if(hit != null && hit.typeOfHit == RayTraceResult.Type.BLOCK) { //Get block material Material mat = world.getBlockState(hit.getBlockPos()).getMaterial(); //If this grenade detonates on impact, do so if(type.explodeOnImpact) detonate(); //If we hit glass and can break it, do so else if(type.breaksGlass && mat == Material.GLASS && TeamsManager.canBreakGlass) { if(!world.isRemote) { WorldServer worldServer = (WorldServer)world; BlockUtil.destroyBlock(worldServer, hit.getBlockPos(), player.orElse(null), false); } } //If this grenade does not penetrate blocks, hit the block instead //The grenade cannot bounce if it detonated on impact, so hence the "else" condition else if(!type.penetratesBlocks) { Vector3f hitVec = new Vector3f(hit.hitVec); //Motion of the grenade pre-hit Vector3f preHitMotVec = Vector3f.sub(hitVec, posVec, null); //Motion of the grenade post-hit Vector3f postHitMotVec = Vector3f.sub(motVec, preHitMotVec, null); //Reflect postHitMotVec based on side hit EnumFacing sideHit = hit.sideHit; switch(sideHit) { case UP: case DOWN: postHitMotVec.setY(-postHitMotVec.getY()); break; case EAST: case WEST: postHitMotVec.setX(-postHitMotVec.getX()); break; case NORTH: case SOUTH: postHitMotVec.setZ(-postHitMotVec.getZ()); break; //TODO : Check the compass directions are correct } //Calculate the time interval spent post reflection float lambda = Math.abs(motVec.lengthSquared()) < 0.00000001F ? 1F : postHitMotVec.length() / motVec.length(); //Scale the post hit motion by the bounciness of the grenade postHitMotVec.scale(type.bounciness / 2); //Move the grenade along the new path including reflection posX += preHitMotVec.x + postHitMotVec.x; posY += preHitMotVec.y + postHitMotVec.y; posZ += preHitMotVec.z + postHitMotVec.z; //Set the motion motionX = postHitMotVec.x / lambda; motionY = postHitMotVec.y / lambda; motionZ = postHitMotVec.z / lambda; //Reset the motion vector motVec = new Vector3f(motionX, motionY, motionZ); //Give it a random spin float randomSpinner = 90F; Vector3f.add(angularVelocity, new Vector3f(rand.nextGaussian() * randomSpinner, rand.nextGaussian() * randomSpinner, rand.nextGaussian() * randomSpinner), angularVelocity); //Slow the spin based on the motion angularVelocity.scale(motVec.lengthSquared()); //Play the bounce sound if(motVec.lengthSquared() > 0.01D) playSound(FlansModResourceHandler.getSoundEvent(type.bounceSound), 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F)); //If this grenade is sticky, stick it to the block if(type.sticky) { //Move the grenade to the point of contact posX = hitVec.x; posY = hitVec.y; posZ = hitVec.z; //Stop all motion of the grenade motionX = motionY = motionZ = 0; angularVelocity.set(0F, 0F, 0F); float yaw = axes.getYaw(); switch(hit.sideHit) { case DOWN: axes.setAngles(yaw, 180F, 0F); break; case UP: axes.setAngles(yaw, 0F, 0F); break; case NORTH: axes.setAngles(270F, 90F, 0F); axes.rotateLocalYaw(yaw); break; case SOUTH: axes.setAngles(90F, 90F, 0F); axes.rotateLocalYaw(yaw); break; case WEST: axes.setAngles(180F, 90F, 0F); axes.rotateLocalYaw(yaw); break; case EAST: axes.setAngles(0F, 90F, 0F); axes.rotateLocalYaw(yaw); break; } //Set the stuck flag on stuck = true; stuckToX = hit.getBlockPos().getX(); stuckToY = hit.getBlockPos().getY(); stuckToZ = hit.getBlockPos().getZ(); } } } //We didn't hit a block, continue as normal else { posX += motionX; posY += motionY; posZ += motionZ; } //Update the grenade position setPosition(posX, posY, posZ); } if(type.stickToThrower) { if (!thrower.isPresent() || thrower.get().isDead || !(thrower.get() instanceof EntityLivingBase)) { setDead(); } else { EntityLivingBase entity = (EntityLivingBase) thrower.get(); setPosition(entity.posX, entity.posY, entity.posZ); } } //If throwing this grenade at an entity should hurt them, this bit checks for entities in the way and does so //(Don't attack entities when stuck to stuff) if(type.damageVsLiving > 0 && !stuck) { Vector3f motVec = new Vector3f(motionX, motionY, motionZ); List list = world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox()); for(Object obj : list) { if(obj == thrower && ticksExisted < 10 || motVec.lengthSquared() < 0.01D) continue; if(obj instanceof EntityLivingBase) ((EntityLivingBase)obj).attackEntityFrom(getGrenadeDamage(), type.damageVsLiving * motVec.lengthSquared() * 3); } } //Apply gravity motionY -= 9.81D / 400D * type.fallSpeed; //Temporary fire glitch fix if(world.isRemote) extinguish(); } @Override public boolean attackEntityFrom(DamageSource source, float f) { if(type.detonateWhenShot) detonate(); return type.detonateWhenShot; } public void detonate() { //Do not detonate before grenade is primed if(ticksExisted < type.primeDelay) return; //Stop repeat detonations if(detonated) return; detonated = true; //Play detonate sound PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.detonateSound, true); //Explode if(!world.isRemote && type.explosionRadius > 0.1F) { new FlansModExplosion(world, this, player, type, posX, posY, posZ, type.explosionRadius, type.fireRadius > 0, type.smokeRadius > 0, type.explosionBreaksBlocks); } //Make fire if(type.fireRadius > 0.1F) { for(float i = -type.fireRadius; i < type.fireRadius; i++) { for(float j = -type.fireRadius; j < type.fireRadius; j++) { for(float k = -type.fireRadius; k < type.fireRadius; k++) { int x = MathHelper.floor(i + posX); int y = MathHelper.floor(j + posY); int z = MathHelper.floor(k + posZ); if(i * i + j * j + k * k <= type.fireRadius * type.fireRadius && world.getBlockState(new BlockPos(x, y, z)).getBlock() == Blocks.AIR && rand.nextBoolean()) { /* if(!world.getBlockState(new BlockPos(x + 1, y, z)).getBlock(). || !world.isAirBlock(new BlockPos(x - 1, y, z)) || !world.isAirBlock(new BlockPos(x, y + 1, z)) || !world.isAirBlock(new BlockPos(x, y - 1, z)) || !world.isAirBlock(new BlockPos(x, y, z + 1)) || !world.isAirBlock(new BlockPos(x, y, z - 1))) */ { world.setBlockState(new BlockPos(x, y, z), Blocks.FIRE.getDefaultState(), 2); world.scheduleUpdate(new BlockPos(x, y, z), Blocks.FIRE, 0); } } } } } } //Make explosion particles if(world.isRemote) { for(int i = 0; i < type.explodeParticles; i++) { world.spawnParticle(FlansModClient.getParticleType(type.explodeParticleType), posX, posY, posZ, rand.nextGaussian(), rand.nextGaussian(), rand.nextGaussian()); } } //Drop item upon detonation, after explosions and whatnot if(!world.isRemote && type.dropItemOnDetonate != null) { ItemStack dropStack = InfoType.getRecipeElement(type.dropItemOnDetonate); entityDropItem(dropStack, 1.0F); } //Start smoke counter if(type.smokeTime > 0) { smoking = true; smokeTime = type.smokeTime; } else { setDead(); } } @Override public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int i, boolean b) { } private DamageSource getGrenadeDamage() { if (player.isPresent()) { return new EntityDamageSourceFlan(type.shortName, this, player.get(), type).setProjectile(); } return new EntityDamageSource(type.shortName, this).setProjectile(); } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { type = GrenadeType.getGrenade(tags.getString("Type")); player = Optional.ofNullable(world.getPlayerEntityByName(tags.getString("Player"))); rotationYaw = tags.getFloat("RotationYaw"); rotationPitch = tags.getFloat("RotationPitch"); axes.setAngles(rotationYaw, rotationPitch, 0F); } @Override protected void writeEntityToNBT(NBTTagCompound tags) { if(type == null) setDead(); else { tags.setString("Type", type.shortName); if(player.isPresent()) tags.setString("Player", player.get().getName()); tags.setFloat("RotationYaw", axes.getYaw()); tags.setFloat("RotationPitch", axes.getPitch()); } } @Override public void writeSpawnData(ByteBuf data) { ByteBufUtils.writeUTF8String(data, type.shortName); data.writeInt(player.isPresent() ? player.get().getEntityId() : -1); data.writeInt(thrower.isPresent() ? thrower.get().getEntityId() : -1); data.writeFloat(axes.getYaw()); data.writeFloat(axes.getPitch()); } @Override public void readSpawnData(ByteBuf data) { type = GrenadeType.getGrenade(ByteBufUtils.readUTF8String(data)); { Entity ent = world.getEntityByID(data.readInt()); player = ent instanceof EntityPlayer ? Optional.of((EntityPlayer) ent) : Optional.empty(); } thrower = Optional.ofNullable(world.getEntityByID(data.readInt())); setRotation(data.readFloat(), data.readFloat()); prevRotationYaw = rotationYaw; prevRotationPitch = rotationPitch; axes.setAngles(rotationYaw, rotationPitch, 0F); if(type.spinWhenThrown) angularVelocity = new Vector3f(0F, 0F, 10F); } @Override public boolean isBurning() { return false; } @Override public boolean canBeCollidedWith() { return !isDead && type.isDeployableBag; } @Override public boolean processInitialInteract(EntityPlayer player, EnumHand hand) { // Player right clicked on grenade //For deployable bags, give player rewards if(type.isDeployableBag && !world.isRemote) { boolean used = false; //Handle healing if(type.healAmount > 0 && player.getHealth() < player.getMaxHealth()) { player.heal(type.healAmount); FlansMod.getPacketHandler().sendToAllAround(new PacketFlak(player.posX, player.posY, player.posZ, 5, "heart"), new NetworkRegistry.TargetPoint(player.dimension, player.posX, player.posY, player.posZ, 50F)); used = true; } //Handle potion effects for(PotionEffect effect : type.potionEffects) { player.addPotionEffect(new PotionEffect(effect)); used = true; } //Handle ammo if(type.numClips > 0 && player.getHeldItemMainhand() != null && player.getHeldItemMainhand().getItem() instanceof ItemGun) { GunType gun = ((ItemGun)player.getHeldItemMainhand().getItem()).GetType(); if(gun.ammo.size() > 0) { ShootableType bulletToGive = gun.ammo.get(0); int numToGive = Math.min(bulletToGive.maxStackSize, type.numClips * gun.numAmmoItemsInGun); if(player.inventory.addItemStackToInventory(new ItemStack(bulletToGive.item, numToGive))) { used = true; } } } //If the bag is all used up, get rid of it if(used) { numUsesRemaining--; if(numUsesRemaining <= 0) setDead(); } } return true; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityMG.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.lwjgl.input.Mouse; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerHandler; import com.flansmod.common.network.PacketMGFire; import com.flansmod.common.network.PacketMGMount; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.EntityGunItem; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.vector.Vector3f; public class EntityMG extends Entity implements IEntityAdditionalSpawnData { public int blockX, blockY, blockZ; public int direction; public GunType type; public ItemStack ammo = ItemStack.EMPTY.copy(); public int reloadTimer; public int soundDelay; public float shootDelay; public static List mgs = new ArrayList<>(); public EntityPlayer gunner; //Server side public boolean isShooting; //Client side public boolean wasShooting = false; public int ticksSinceUsed = 0; public EntityMG(World world) { super(world); setSize(1.0F, 1.0F); ignoreFrustumCheck = true; } public EntityMG(World world, int x, int y, int z, int dir, GunType gunType) { super(world); setSize(1.0F, 1.0F); blockX = x; blockY = y; blockZ = z; prevPosX = x + 0.5D; prevPosY = y; prevPosZ = z + 0.5D; setPosition(x + 0.5D, y, z + 0.5D); direction = dir; rotationYaw = 0; rotationPitch = -60; type = gunType; ignoreFrustumCheck = true; mgs.add(this); } @Override public boolean canBeCollidedWith() { return !isDead; } @Override public void onUpdate() { super.onUpdate(); prevPosX = posX = blockX + 0.5f; prevPosY = posY = blockY; prevPosZ = posZ = blockZ + 0.5f; ticksSinceUsed++; if(TeamsManager.mgLife > 0 && ticksSinceUsed > TeamsManager.mgLife * 20) { setDead(); } if(world.getBlockState(new BlockPos(blockX, blockY - 1, blockZ)).getBlock() == Blocks.AIR) { if(!world.isRemote) { setDead(); } } prevRotationYaw = rotationYaw; prevRotationPitch = rotationPitch; if(gunner != null) { ticksSinceUsed = 0; rotationYaw = gunner.rotationYaw - direction * 90; for(; rotationYaw < -180; rotationYaw += 360) { } for(; rotationYaw > 180; rotationYaw -= 360) { } rotationPitch = gunner.rotationPitch; // Keep it within reasonable angles if(rotationYaw > type.sideViewLimit) prevRotationYaw = rotationYaw = type.sideViewLimit; if(rotationYaw < -type.sideViewLimit) prevRotationYaw = rotationYaw = -type.sideViewLimit; // Keep user standing behind the gun float angle = direction * 90F + rotationYaw; double dX = (type.standBackDist * Math.sin(angle * 3.1415926535F / 180F)); double dZ = -(type.standBackDist * Math.cos(angle * 3.1415926535F / 180F)); gunner.setPosition((blockX + 0.5D + dX), blockY - 1.0d, (blockZ + 0.5D + dZ)); // gunner.setPosition((double)(blockX + (direction == 1 ? 1 : 0) - // (direction == 3 ? 1 : 0)) + 0.5D, blockY + gunner.getYOffset() - // 0.5D, (double)(blockZ - (direction == 0 ? 1 : 0) + (direction == // 2 ? 1 : 0)) + 0.5D); } else { rotationPitch--; } if(rotationPitch < -type.topViewLimit) rotationPitch = -type.topViewLimit; if(rotationPitch > type.bottomViewLimit) rotationPitch = type.bottomViewLimit; if(shootDelay > 0) shootDelay--; // Decrement the reload timer and reload if(reloadTimer > 0) reloadTimer--; if(!ammo.isEmpty() && ammo.getItemDamage() == ammo.getMaxDamage()) { ammo = ItemStack.EMPTY.copy(); // Scrap metal output? } if(ammo.isEmpty() && gunner != null) { int slot = findAmmo(gunner); if(slot >= 0) { ammo = gunner.inventory.getStackInSlot(slot); if(!gunner.capabilities.isCreativeMode) gunner.inventory.setInventorySlotContents(slot, ItemStack.EMPTY.copy()); reloadTimer = type.reloadTime; PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.reloadSound, false); } } if(world.isRemote && gunner != null && gunner == FMLClientHandler.instance().getClient().player && type.mode == EnumFireMode.FULLAUTO) { //Send a packet! checkForShooting(); } if(!world.isRemote && isShooting) { fire(); } if(soundDelay > 0) soundDelay--; } @SideOnly(Side.CLIENT) private void checkForShooting() { if(Mouse.isButtonDown(0) && !wasShooting && !FlansMod.proxy.isScreenOpen()) { FlansMod.getPacketHandler().sendToServer(new PacketMGFire(true)); wasShooting = true; } else if(!Mouse.isButtonDown(0) && wasShooting) { FlansMod.getPacketHandler().sendToServer(new PacketMGFire(false)); wasShooting = false; } } //Server side setter to be called upon receiving a packet public void mouseHeld(boolean held) { isShooting = held; } private void fire() { if(gunner == null || gunner.isDead) isShooting = false; // Check for ammo / reloading if(ammo.isEmpty() || reloadTimer > 0 || shootDelay > 0) { return; } // Fire BulletType bullet = BulletType.getBullet(ammo.getItem()); ShootBulletHandler handler = isExtraBullet -> { if(gunner != null && !gunner.capabilities.isCreativeMode) ammo.damageItem(1, gunner); }; shootDelay = type.shootDelay; ItemShootable shootableItem = (ItemShootable)ammo.getItem(); ShootableType shootableType = shootableItem.type; Vector3f position = new Vector3f(blockX + 0.5D, blockY + type.pivotHeight, blockZ + 0.5D); FireableGun gun = new FireableGun(type, type.damage, type.bulletSpread, type.bulletSpeed, type.spreadPattern); FiredShot shot = new FiredShot(gun, bullet, this, (EntityPlayerMP) gunner); Double radianYaw = Math.toRadians(direction * 90F + rotationYaw); Double radianPitch = Math.toRadians(rotationPitch); Vector3f shootingDirection = new Vector3f(-Math.sin(radianYaw), -Math.sin(radianPitch), Math.cos(radianYaw)); ShotHandler.fireGun(world, shot, type.numBullets*shootableType.numBullets, position, shootingDirection, handler); if(soundDelay <= 0) { soundDelay = type.shootSoundLength; PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound, type.distortSound); } } @Override public boolean attackEntityFrom(DamageSource damagesource, float i) { if(damagesource.damageType.equals("player")) { Entity player = damagesource.getTrueSource(); if(player == gunner) { // Player left clicked on the gun if(type.mode == EnumFireMode.FULLAUTO) return true; fire(); } else if(gunner != null) { return gunner.attackEntityFrom(damagesource, i); } else if(TeamsManager.canBreakGuns) { setDead(); } } return true; } @Override public boolean processInitialInteract(EntityPlayer player, EnumHand hand) { // Player right clicked on gun // Mount gun if(gunner != null && gunner != player) { return true; } if(!world.isRemote) { //If this is the player currently using this MG, dismount if(gunner == player) { mountGun(player, false); FlansMod.getPacketHandler().sendToAllAround(new PacketMGMount(player, this, false), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); return true; } //If this person is already mounting a gun, dismount it first if(PlayerHandler.getPlayerData(player).mountingGun != null && !PlayerHandler.getPlayerData(player).mountingGun.isDead) { PlayerHandler.getPlayerData(player).mountingGun.mountGun(player, false); return true; } //Spectators can't mount guns if(TeamsManager.instance.currentRound != null && PlayerHandler.getPlayerData(player).team == Team.spectators) return true; //None of the above applied, so mount the gun mountGun(player, true); FlansMod.getPacketHandler().sendToAllAround(new PacketMGMount(player, this, true), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); if(ammo.isEmpty()) { int slot = findAmmo(player); if(slot >= 0) { ammo = player.inventory.getStackInSlot(slot).splitStack(1); reloadTimer = type.reloadTime; playSound(FlansModResourceHandler.getSoundEvent(type.reloadSound), 1.0F, 1.0F / (rand.nextFloat() * 0.4F + 0.8F)); } } } return true; } public void mountGun(EntityPlayer player, boolean mounting) { if(player == null) return; Side side = world.isRemote ? Side.CLIENT : Side.SERVER; if(PlayerHandler.getPlayerData(player, side) == null) return; if(mounting) { gunner = player; PlayerHandler.getPlayerData(player, side).mountingGun = this; } else { PlayerHandler.getPlayerData(player, side).mountingGun = null; gunner = null; } } public int findAmmo(EntityPlayer player) { for(int i = 0; i < player.inventory.getSizeInventory(); i++) { ItemStack stack = player.inventory.getStackInSlot(i); if(type.isCorrectAmmo(stack)) { return i; } } return -1; } @Override public void setDead() { // Drop gun if(!world.isRemote) { if(TeamsManager.weaponDrops == 2) { EntityGunItem gunEntity = new EntityGunItem(world, posX, posY, posZ, new ItemStack(type.getItem()), Arrays.asList(ammo)); world.spawnEntity(gunEntity); } else if(TeamsManager.weaponDrops == 1) { dropItem(type.getItem(), 1); // Drop ammo box if(!ammo.isEmpty()) entityDropItem(ammo, 0.5F); } } if(gunner != null && PlayerHandler.getPlayerData(gunner) != null) PlayerHandler.getPlayerData(gunner).mountingGun = null; super.setDead(); } @Override protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { nbttagcompound.setString("Type", type.shortName); nbttagcompound.setTag("Ammo", ammo.writeToNBT(new NBTTagCompound())); nbttagcompound.setInteger("BlockX", blockX); nbttagcompound.setInteger("BlockY", blockY); nbttagcompound.setInteger("BlockZ", blockZ); nbttagcompound.setByte("Dir", (byte)direction); } @Override protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { type = GunType.getGun(nbttagcompound.getString("Type")); blockX = nbttagcompound.getInteger("BlockX"); blockY = nbttagcompound.getInteger("BlockY"); blockZ = nbttagcompound.getInteger("BlockZ"); direction = nbttagcompound.getByte("Dir"); ammo = new ItemStack(nbttagcompound.getCompoundTag("Ammo")); } @Override protected void entityInit() { } @Override public void writeSpawnData(ByteBuf data) { ByteBufUtils.writeUTF8String(data, type.shortName); data.writeInt(direction); data.writeInt(blockX); data.writeInt(blockY); data.writeInt(blockZ); ByteBufUtils.writeItemStack(data, ammo); } @Override public void readSpawnData(ByteBuf data) { try { type = GunType.getGun(ByteBufUtils.readUTF8String(data)); direction = data.readInt(); blockX = data.readInt(); blockY = data.readInt(); blockZ = data.readInt(); ammo = ByteBufUtils.readItemStack(data); } catch(Exception e) { FlansMod.log.error("Failed to retreive gun type from server."); super.setDead(); FlansMod.log.throwing(e); } } @Override public ItemStack getPickedResult(RayTraceResult target) { return new ItemStack(type.item, 1, 0); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EntityShootable.java ================================================ package com.flansmod.common.guns; import net.minecraft.entity.Entity; import net.minecraft.world.World; public abstract class EntityShootable extends Entity { public EntityShootable(World w) { super(w); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EnumAttachmentType.java ================================================ package com.flansmod.common.guns; public enum EnumAttachmentType { barrel, sights, stock, grip, generic; public static EnumAttachmentType get(String s) { for(EnumAttachmentType type : values()) { if(type.toString().equals(s)) return type; } return generic; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EnumFireMode.java ================================================ package com.flansmod.common.guns; public enum EnumFireMode { SEMIAUTO, FULLAUTO, MINIGUN, BURST; public static EnumFireMode getFireMode(String s) { s = s.toLowerCase(); if(s.equals("fullauto")) return FULLAUTO; if(s.equals("minigun")) return MINIGUN; if(s.equals("burst")) return BURST; return SEMIAUTO; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EnumSecondaryFunction.java ================================================ package com.flansmod.common.guns; public enum EnumSecondaryFunction { ZOOM, ADS_ZOOM, MELEE, CUSTOM_MELEE; public static EnumSecondaryFunction get(String s) { s = s.toLowerCase(); if(s.equals("zoom")) return ZOOM; else if(s.equals("melee")) return MELEE; else if(s.equals("custommelee")) return CUSTOM_MELEE; else return ADS_ZOOM; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/EnumSpreadPattern.java ================================================ package com.flansmod.common.guns; public enum EnumSpreadPattern { circle, cube, triangle, horizontal, vertical; public static EnumSpreadPattern get(String s) { s = s.toLowerCase(); if(s.equals("circle")) return circle; else if(s.equals("cube")) return cube; else if(s.equals("triangle")) return triangle; else if(s.equals("horizontal")) return horizontal; else if(s.equals("vertical")) return vertical; return null; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/FireableGun.java ================================================ package com.flansmod.common.guns; import com.flansmod.common.types.InfoType; /** * Class used for storing the properties of a gun */ public class FireableGun { //Spread of the bullets shot with this gun private float spread; private EnumSpreadPattern spreadPattern; // Speed a bullet fired from this gun will travel at. (0 means instant/raytraced) private float bulletSpeed; private InfoType type; // the damage this gun will cause private float damage; // the damage against vehicles private float vehicledamage; /** * @param type InfoType of the gun * @param damage Damage of the gun * @param spread Bullet spread of the gun * @param bulletSpeed Bullet speed of the gun (0 means instant/raytraced) */ public FireableGun(InfoType type, float damage, float spread, float bulletSpeed, EnumSpreadPattern spreadPattern) { this(type, damage, damage, spread, bulletSpeed, spreadPattern); } /** * @param type InfoType of the gun * @param damage Damage of the gun * @param vehicledamage Damage of the gun against vehicles * @param spread Bullet spread of the gun * @param bulletSpeed Bullet speed of the gun (0 means instant/raytraced) */ public FireableGun(InfoType type, float damage, float vehicledamage, float spread, float bulletSpeed, EnumSpreadPattern spreadPattern) { this.type = type; this.damage = damage; this.spread = spread; this.bulletSpeed = bulletSpeed; this.vehicledamage = vehicledamage; this.spreadPattern = spreadPattern; } /** * @return the bullet spread of this gun */ public float getGunSpread() { return spread; } public EnumSpreadPattern getSpreadPattern() { return spreadPattern; } /** * @return the shortName of the InfoType of this gun */ public String getShortName() { return type.shortName; } /** * @return the InfoType of this gun */ public InfoType getInfoType() { return type; } /** * @return the damage this gun will cause */ public float getDamage() { return damage; } /** * @return the speed a bullet fired from this gun will travel at. (0 means instant/raytraced) */ public float getBulletSpeed() { return this.bulletSpeed; } /** * @return the damage this gun will cause against vehicles */ public float getDamageAgainstVehicles() { return this.vehicledamage; } public void MultiplySpread(float multiplier) { spread *= multiplier; } public void MultiplyDamage(float multiplier) { damage *= multiplier; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/FiredShot.java ================================================ package com.flansmod.common.guns; import java.util.Optional; import javax.annotation.Nullable; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; /** * Class for creating object containing all necessary informations about a fired shot */ public class FiredShot { /** * The weapon used to fire the shot */ private FireableGun weapon; /** * The BulletType of the fired bullet */ private BulletType bullet; /** * Optional containing a player, if one can be associated with the shot */ private Optional player; /** * Optional of the entity which fired the shot. Can be the same as the Player optional */ private Optional shooter; /** * @param weapon weapon used to fire the shot * @param bullet BulletType of the fired bullet */ public FiredShot(FireableGun weapon, BulletType bullet) { this.weapon = weapon; this.bullet = bullet; this.player = Optional.empty(); this.shooter = this.player; } /** * @param weapon weapon used to fire the shot * @param bullet BulletType of the fired bullet * @param player The player who shot */ public FiredShot(FireableGun weapon, BulletType bullet, EntityPlayerMP player) { this(weapon,bullet, player, player); } /** * This constructor should be used when an entity shot, but no player is involved * e.g a zombie holding a gun or a sentry * * @param weapon weapon used to fire the shot * @param bullet BulletType of the fired bullet * @param shooter Entity which fired the shot */ public FiredShot(FireableGun weapon, BulletType bullet, Entity shooter) { this(weapon, bullet, shooter, null); } /** * This constructor should be used if a player causes a shot, but the player is actually not the entity shooting it * e.g a player flying a plane * * @param weapon weapon used to fire the shot * @param bullet BulletType of the fired bullet * @param shooter the Entity firing the shot * @param player the Player causing the shot */ public FiredShot(FireableGun weapon, BulletType bullet, Entity shooter, @Nullable EntityPlayerMP player) { this.weapon = weapon; this.bullet = bullet; this.player = Optional.ofNullable(player); this.shooter = Optional.of(shooter); } /** * @return The gun used for this shot */ public FireableGun getFireableGun() { return this.weapon; } /** * @return The BulletType of the bullet used in the shot */ public BulletType getBulletType() { return this.bullet; } /** * @return the matching DamageSource for the shot */ public DamageSource getDamageSource() { return getDamageSource(false); } /** * @return the matching DamageSource for the shot with the additional 'headshot' information */ public DamageSource getDamageSource(Boolean headshot) { if (player.isPresent()) { return new EntityDamageSourceFlan(weapon.getShortName(), player.get(), player.get(), weapon.getInfoType(), headshot).setProjectile(); } else if(shooter.isPresent()) { return new EntityDamageSourceFlan(weapon.getShortName(), null, null, weapon.getInfoType(), headshot).setProjectile(); } return DamageSource.GENERIC; } /** * @return Optional containing a player if one is involved in the cause of the shot */ public Optional getPlayerOptional() { return this.player; } /** * @return Optional containing the Entity which shot. Might be the same as the player optional */ public Optional getShooterOptional() { return this.shooter; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/GrenadeType.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import net.minecraft.client.model.ModelBase; import net.minecraft.potion.PotionEffect; import com.flansmod.common.FlansMod; import com.flansmod.common.types.TypeFile; public class GrenadeType extends ShootableType { public static ArrayList grenades = new ArrayList<>(); //Misc /** * The damage imparted by smacking someone over the head with this grenade */ public int meleeDamage = 1; //Throwing /** * The delay between subsequent grenade throws */ public int throwDelay = 0; /** * The sound to play upon throwing this grenade */ public String throwSound = ""; /** * The name of the item to drop (if any) when throwing the grenade */ public String dropItemOnThrow = null; /** * Whether you can throw this grenade by right clicking */ public boolean canThrow = true; //Physics /** * Upon hitting a block or entity, the grenade will be deflected and its motion will be multiplied by this constant */ public float bounciness = 0.9F; /** * Whether this grenade may pass through entities or blocks */ public boolean penetratesEntities = false, penetratesBlocks = false; /** * The sound to play upon bouncing off a surface */ public String bounceSound = ""; /** * Whether the grenade should stick to surfaces */ public boolean sticky = false; /** * If true, then the grenade will stick to the player that threw it. Used to make delayed self destruct weapons */ public boolean stickToThrower = false; //Conditions for detonation /** * If > 0 this will act like a mine and explode when a living entity comes within this radius of the grenade */ public float livingProximityTrigger = -1F; /** * If > 0 this will act like a mine and explode when a driveable comes within this radius of the grenade */ public float driveableProximityTrigger = -1F; /** * If true, then anything attacking this entity will detonate it */ public boolean detonateWhenShot = false; /** * If true, then this grenade can be detonated by any remote detonator tool */ public boolean remote = false; /** * How much damage to deal to the entity that triggered it */ public float damageToTriggerer = 0F; //Detonation /** * Explosion damage vs various classes of entities */ public float explosionDamageVsLiving = 0F, explosionDamageVsDriveable = 0F; /** * Detonation will not occur until after this time */ public int primeDelay = 0; //Aesthetics /** * Particles given off in the detonation */ public int explodeParticles = 0; public String explodeParticleType = "largesmoke"; /** * Whether the grenade should spin when thrown. Generally false for mines or things that should lie flat */ public boolean spinWhenThrown = true; //Smoke /** * Time to remain after detonation */ public int smokeTime = 0; /** * Particles given off after detonation */ public String smokeParticleType = "explode"; /** * The effects to be given to people coming too close */ public ArrayList smokeEffects = new ArrayList<>(); /** * The radius for smoke effects to take place in */ public float smokeRadius = 5F; //Deployed bag functionality /** * If true, then right clicking this "grenade" will give the player health or buffs or ammo as defined below */ public boolean isDeployableBag = false; /** * The number of times players can use this bag before it runs out */ public int numUses = 1; /** * The amount to heal the player using this bag */ public float healAmount = 0; /** * The potion effects to apply to users of this bag */ public ArrayList potionEffects = new ArrayList<>(); /** * The number of clips to give to the player when using this bag * When they right click with a gun, they will get this number of clips for that gun. * They get the first ammo type, as listed in the gun type file * The number of clips they get is multiplied by numBulletsInGun too * TODO : Give guns a "can get ammo from bag" variable. Stops miniguns and such getting ammo */ public int numClips = 0; public GrenadeType(TypeFile file) { super(file); grenades.add(this); } @Override public void postRead(TypeFile file) { super.postRead(file); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(split[0].equals("MeleeDamage")) meleeDamage = Integer.parseInt(split[1]); //Grenade Throwing else if(split[0].equals("ThrowDelay")) throwDelay = Integer.parseInt(split[1]); else if(split[0].equals("ThrowSound")) { throwSound = split[1]; FlansMod.proxy.loadSound(contentPack, "grenades", split[1]); } else if(split[0].equals("DropItemOnThrow")) dropItemOnThrow = split[1]; else if(split[0].equals("CanThrow")) canThrow = Boolean.parseBoolean(split[1]); //Grenade Physics else if(split[0].equals("Bounciness")) bounciness = Float.parseFloat(split[1]); else if(split[0].equals("PenetratesEntities")) penetratesEntities = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("PenetratesBlocks")) penetratesBlocks = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("BounceSound")) { bounceSound = split[1]; FlansMod.proxy.loadSound(contentPack, "grenades", split[1]); } else if(split[0].equals("Sticky")) sticky = Boolean.parseBoolean(split[1]); else if(split[0].equals("LivingProximityTrigger")) livingProximityTrigger = Float.parseFloat(split[1]); else if(split[0].equals("VehicleProximityTrigger")) driveableProximityTrigger = Float.parseFloat(split[1]); else if(split[0].equals("DamageToTriggerer")) damageToTriggerer = Float.parseFloat(split[1]); else if(split[0].equals("DetonateWhenShot")) detonateWhenShot = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("PrimeDelay") || split[0].equals("TriggerDelay")) primeDelay = Integer.parseInt(split[1]); else if(split[0].equals("StickToThrower")) stickToThrower = Boolean.parseBoolean(split[1]); else if(split[0].equals("ExplosionDamageVsLiving")) explosionDamageVsLiving = Float.parseFloat(split[1]); else if(split[0].equals("ExplosionDamageVsDrivable")) explosionDamageVsDriveable = Float.parseFloat(split[1]); else if(split[0].equals("NumExplodeParticles")) explodeParticles = Integer.parseInt(split[1]); else if(split[0].equals("ExplodeParticles")) explodeParticleType = split[1]; else if(split[0].equals("SmokeTime")) smokeTime = Integer.parseInt(split[1]); else if(split[0].equals("SmokeParticles")) smokeParticleType = split[1]; else if(split[0].equals("SmokeEffect")) smokeEffects.add(getPotionEffect(split)); else if(split[0].equals("SmokeRadius")) smokeRadius = Float.parseFloat(split[1]); else if(split[0].equals("SpinWhenThrown")) spinWhenThrown = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("Remote")) remote = Boolean.parseBoolean(split[1].toLowerCase()); //Deployable Bag Stuff else if(split[0].equals("DeployableBag")) isDeployableBag = true; else if(split[0].equals("NumUses")) numUses = Integer.parseInt(split[1]); else if(split[0].equals("HealAmount")) healAmount = Float.parseFloat(split[1]); else if(split[0].equals("AddPotionEffect") || split[0].equals("PotionEffect")) potionEffects.add(getPotionEffect(split)); else if(split[0].equals("NumClips")) numClips = Integer.parseInt(split[1]); } catch(Exception e) { FlansMod.log.error("Reading grenade file failed."); FlansMod.log.throwing(e); } } public static GrenadeType getGrenade(String s) { for(GrenadeType grenade : grenades) { if(grenade.shortName.equals(s)) return grenade; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelBase.class); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/GunType.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import net.minecraft.client.model.ModelBase; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelDefaultMuzzleFlash; import com.flansmod.client.model.ModelGun; import com.flansmod.client.model.ModelMG; import com.flansmod.client.model.ModelMuzzleFlash; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.types.TypeFile; import com.flansmod.common.vector.Vector3f; public class GunType extends PaintableType implements IScope { //Gun Behaviour Variables /** * The list of bullet types that can be used in this gun */ public List ammo = new ArrayList<>(), nonExplosiveAmmo = new ArrayList<>(); /** * Whether the player can press the reload key (default R) to reload this gun */ public boolean canForceReload = true; /** * The time (in ticks) it takes to reload this gun */ public int reloadTime; /** * The amount to recoil the player's view by when firing a single shot from this gun */ public int recoil; /** * The amount that bullets spread out when fired from this gun */ public float bulletSpread; public EnumSpreadPattern spreadPattern = EnumSpreadPattern.cube; /** * Damage inflicted by this gun. Multiplied by the bullet damage. */ public float damage = 0; /** * The damage inflicted upon punching someone with this gun */ public float meleeDamage = 1; /** * The speed of bullets upon leaving this gun. 0.0f means instant. */ public float bulletSpeed = 0.0f; /** * The number of bullet entities created by each shot */ public int numBullets = 1; /** * The delay between shots in ticks (1/20ths of seconds) */ public float shootDelay = 1.0f; /** * Number of ammo items that the gun may hold. Most guns will hold one magazine. * Some may hold more, such as Nerf pistols, revolvers or shotguns */ public int numAmmoItemsInGun = 1; /** * The firing mode of the gun. One of semi-auto, full-auto, minigun or burst */ public EnumFireMode mode = EnumFireMode.FULLAUTO; /** * The number of bullets to fire per burst in burst mode */ public int numBurstRounds = 3; /** * The required speed for minigun mode guns to start firing */ public float minigunStartSpeed = 15F; /** * The maximum speed a minigun mode gun can reach */ public float minigunMaxSpeed = 30F; /** * Whether this gun can be used underwater */ public boolean canShootUnderwater = true; /** * The amount of knockback to impact upon the player per shot */ public float knockback = 0F; /** * The secondary function of this gun. By default, the left mouse button triggers this */ public EnumSecondaryFunction secondaryFunction = EnumSecondaryFunction.ADS_ZOOM; /** * If true, then this gun can be dual wielded */ public boolean oneHanded = false; /** * For one shot items like a panzerfaust */ public boolean consumeGunUponUse = false; /** * Item to drop on shooting */ public String dropItemOnShoot = null; //Custom Melee Stuff /** * The time delay between custom melee attacks */ public int meleeTime = 1; /** * The path the melee weapon takes */ public ArrayList meleePath = new ArrayList<>(), meleePathAngles = new ArrayList<>(); /** * The points on the melee weapon that damage is actually done from. */ public ArrayList meleeDamagePoints = new ArrayList<>(); /** * Set these to make guns only usable by a certain type of entity */ public boolean usableByPlayers = true, usableByMechas = true; //Information //Show any variables into the GUI when hovering over items. /** * If false, then attachments wil not be listed in item GUI */ public boolean showAttachments = true; /** * Show statistics */ public boolean showDamage = false, showRecoil = false, showSpread = false; /** * Show reload time in seconds */ public boolean showReloadTime = false; //Shields //A shield is actually a gun without any shoot functionality (similar to knives or binoculars) //and a load of shield code on top. This means that guns can have in built shields (think Nerf Stampede) /** * Whether or not this gun has a shield piece */ public boolean shield = false; /** * Shield collision box definition. In model co-ordinates */ public Vector3f shieldOrigin, shieldDimensions; /** * Float between 0 and 1 denoting the proportion of damage blocked by the shield */ public float shieldDamageAbsorption = 0F; //Sounds /** * The sound played upon shooting */ public String shootSound; /** * The length of the sound for looping sounds */ public int shootSoundLength; /** * Whether to distort the sound or not. Generally only set to false for looping sounds */ public boolean distortSound = true; /** * The sound to play upon reloading */ public String reloadSound; //Looping sounds /** * Whether the looping sounds should be used. Automatically set if the player sets any one of the following sounds */ public boolean useLoopingSounds = false; /** * Played when the player starts to hold shoot */ public String warmupSound; public int warmupSoundLength = 20; /** * Played in a loop until player stops holding shoot */ public String loopedSound; public int loopedSoundLength = 20; /** * Played when the player stops holding shoot */ public String cooldownSound; /** * The sound to play upon weapon swing */ public String meleeSound; /** * The sound to play while holding the weapon in the hand */ public String idleSound; public int idleSoundLength; //Deployable Settings /** * If true, then the bullet does not shoot when right clicked, but must instead be placed on the ground */ public boolean deployable = false; /** * The deployable model */ @SideOnly(Side.CLIENT) public ModelMG deployableModel; @SideOnly(Side.CLIENT) public ModelMuzzleFlash muzzleFlashModel; /** * The deployable model's texture */ public String deployableTexture; /** * Various deployable settings controlling the player view limits and standing position */ public float standBackDist = 1.5F, topViewLimit = -60F, bottomViewLimit = 30F, sideViewLimit = 45F, pivotHeight = 0.375F; //Default Scope Settings. Overriden by scope attachments //In many cases, this will simply be iron sights /** * Default scope overlay texture */ public String defaultScopeTexture; /** * Whether the default scope has an overlay */ public boolean hasScopeOverlay = false; /** * The zoom level of the default scope */ public float zoomLevel = 1.0F; /** * The FOV zoom level of the default scope */ public float FOVFactor = 1.5F; /** * For guns with 3D models */ //TODO properly separate the data //@SideOnly(Side.CLIENT) public ModelGun model; //Attachment settings /** * If this is true, then all attachments are allowed. Otherwise the list is checked */ public boolean allowAllAttachments = false; /** * The list of allowed attachments for this gun */ public ArrayList allowedAttachments = new ArrayList<>(); /** * Whether each attachment slot is available */ public boolean allowBarrelAttachments = false, allowScopeAttachments = false, allowStockAttachments = false, allowGripAttachments = false; /** * The number of generic attachment slots there are on this gun */ public int numGenericAttachmentSlots = 0; /** * The static hashmap of all guns by shortName */ public static HashMap guns = new HashMap<>(); /** * The static list of all guns */ public static ArrayList gunList = new ArrayList<>(); //Modifiers /** * Speeds up or slows down player movement when this item is held */ public float moveSpeedModifier = 1F; /** * Gives knockback resistance to the player */ public float knockbackModifier = 0F; public GunType(TypeFile file) { super(file); } @Override public void postRead(TypeFile file) { super.postRead(file); gunList.add(this); guns.put(shortName.hashCode(), this); if(FMLCommonHandler.instance().getSide() == Side.CLIENT) { checkMF(); } } @SideOnly(Side.CLIENT) private void checkMF() { if(muzzleFlashModel == null) { muzzleFlashModel = new ModelDefaultMuzzleFlash(); } } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { damage = Read(split, "Damage", damage); canForceReload = Read(split, "CanForceReload", canForceReload); reloadTime = Read(split, "ReloadTime", reloadTime); recoil = Read(split, "Recoil", recoil); knockback = Read(split, "Knockback", knockback); bulletSpread = Read(split, "Accuracy", bulletSpread); bulletSpread = Read(split, "Spread", bulletSpread); numBullets = Read(split, "NumBullets", numBullets); consumeGunUponUse = Read(split, "ConsumeGunOnUse", consumeGunUponUse); dropItemOnShoot = Read(split, "DropItemOnShoot", dropItemOnShoot); numBurstRounds = Read(split, "NumBurstRounds", numBurstRounds); minigunStartSpeed = Read(split, "MinigunStartSpeed", minigunStartSpeed); if(split[0].equals("MeleeDamage")) { meleeDamage = Float.parseFloat(split[1]); if(meleeDamage > 0F) secondaryFunction = EnumSecondaryFunction.MELEE; } //Information showAttachments = Read(split, "ShowAttachments", showAttachments); showDamage = Read(split, "ShowDamage", showDamage); showRecoil = Read(split, "ShowRecoil", showRecoil); showSpread = Read(split, "ShowAccuracy", showSpread); showReloadTime = Read(split, "ShowReloadTime", showReloadTime); //Sounds shootDelay = Read(split, "ShootDelay", shootDelay); shootSoundLength = Read(split, "SoundLength", shootSoundLength); distortSound = Read(split, "DistortSound", distortSound); idleSoundLength = Read(split, "IdleSoundLength", idleSoundLength); warmupSoundLength = Read(split, "WarmupSoundLength", warmupSoundLength); loopedSoundLength = Read(split, "LoopedSoundLength", loopedSoundLength); loopedSoundLength = Read(split, "SpinSoundLength", loopedSoundLength); if(split[0].equals("ShootSound")) { shootSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } else if(split[0].equals("ReloadSound")) { reloadSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } else if(split[0].equals("IdleSound")) { idleSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } else if(split[0].equals("MeleeSound")) { meleeSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } //Looping sounds else if(split[0].equals("WarmupSound")) { warmupSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } else if(split[0].equals("LoopedSound") || split[0].equals("SpinSound")) { loopedSound = split[1]; useLoopingSounds = true; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } else if(split[0].equals("CooldownSound")) { cooldownSound = split[1]; FlansMod.proxy.loadSound(contentPack, "guns", split[1]); } //Modes and zoom settings else if(split[0].equals("Mode")) mode = EnumFireMode.getFireMode(split[1]); else if(split[0].equals("Scope")) { hasScopeOverlay = true; if(split[1].equals("None")) hasScopeOverlay = false; else defaultScopeTexture = split[1]; } else if(split[0].equals("ZoomLevel")) { zoomLevel = Float.parseFloat(split[1]); if(zoomLevel > 1F) secondaryFunction = EnumSecondaryFunction.ZOOM; } else if(split[0].equals("FOVZoomLevel")) { FOVFactor = Float.parseFloat(split[1]); if(FOVFactor > 1F) secondaryFunction = EnumSecondaryFunction.ADS_ZOOM; } else if(split[0].equals("Deployable")) deployable = split[1].equals("True"); else if(FMLCommonHandler.instance().getSide().isClient() && deployable && split[0].equals("DeployedModel")) { deployableModel = FlansMod.proxy.loadModel(split[1], shortName, ModelMG.class); } else if(FMLCommonHandler.instance().getSide().isClient() && (split[0].equals("Model"))) { model = FlansMod.proxy.loadModel(split[1], shortName, ModelGun.class); } else if(FMLCommonHandler.instance().getSide().isClient() && (split[0].equals("MuzzleFlashModel"))) { muzzleFlashModel = FlansMod.proxy.loadModel(split[1], shortName, ModelMuzzleFlash.class); } deployableTexture = Read(split, "DeployedTexture", deployableTexture); standBackDist = Read(split, "StandBackDistance", standBackDist); topViewLimit = Read(split, "TopViewLimit", topViewLimit); bottomViewLimit = Read(split, "BottomViewLimit", bottomViewLimit); sideViewLimit = Read(split, "SideViewLimit", sideViewLimit); pivotHeight = Read(split, "PivotHeight", pivotHeight); numAmmoItemsInGun = Read(split, "NumAmmoSlots", numAmmoItemsInGun); numAmmoItemsInGun = Read(split, "NumAmmoItemsInGun", numAmmoItemsInGun); numAmmoItemsInGun = Read(split, "LoadIntoGun", numAmmoItemsInGun); canShootUnderwater = Read(split, "CanShootUnderwater", canShootUnderwater); oneHanded = Read(split, "OneHanded", oneHanded); usableByPlayers = Read(split, "UsableByPlayers", usableByPlayers); usableByMechas = Read(split, "UsableByMechas", usableByMechas); if(split[0].equals("SpreadPattern")) spreadPattern = EnumSpreadPattern.get(split[1]); if(split[0].equals("Ammo")) { ShootableType type = ShootableType.getShootableType(split[1]); if(type != null) { ammo.add(type); if(type.explosionRadius <= 0F) nonExplosiveAmmo.add(type); } // Too spammy when packs have optional dependencies //else FlansMod.log.warn("Could not find " + split[1] + " when reading ammo types for " + shortName); } else if(split[0].equals("BulletSpeed")) { if(split[1].toLowerCase().equals("instant")) { bulletSpeed = 0.0f; } else bulletSpeed = Float.parseFloat(split[1]); if(bulletSpeed > 3.0f) { bulletSpeed = 0.0f; } } else if(split[0].equals("SecondaryFunction")) secondaryFunction = EnumSecondaryFunction.get(split[1]); //Custom Melee Stuff else if(split[0].equals("UseCustomMelee") && Boolean.parseBoolean(split[1])) secondaryFunction = EnumSecondaryFunction.CUSTOM_MELEE; meleeTime = Read(split, "MeleeTime", meleeTime); if(split[0].equals("AddNode")) { meleePath.add(new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F)); meleePathAngles.add(new Vector3f(Float.parseFloat(split[4]), Float.parseFloat(split[5]), Float.parseFloat(split[6]))); } else if(split[0].equals("MeleeDamagePoint") || split[0].equals("MeleeDamageOffset")) { meleeDamagePoints.add(new Vector3f(Float.parseFloat(split[1]) / 16F, Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F)); } //Player modifiers moveSpeedModifier = Read(split, "MoveSpeedModifier", moveSpeedModifier); moveSpeedModifier = Read(split, "Slowness", moveSpeedModifier); knockbackModifier = Read(split, "KnockbackReduction", knockbackModifier); knockbackModifier = Read(split, "KnockbackModifier", knockbackModifier); //Attachment settings allowAllAttachments = Read(split, "AllowAllAttachments", allowAllAttachments); if(split[0].equals("AllowAttachments")) { for(int i = 1; i < split.length; i++) { allowedAttachments.add(AttachmentType.getAttachment(split[i])); } } allowBarrelAttachments = Read(split, "AllowBarrelAttachments", allowBarrelAttachments); allowScopeAttachments = Read(split, "AllowScopeAttachments", allowScopeAttachments); allowStockAttachments = Read(split, "AllowStockAttachments", allowStockAttachments); allowGripAttachments = Read(split, "AllowGripAttachments", allowGripAttachments); numGenericAttachmentSlots = Read(split, "NumGenericAttachmentSlots", numGenericAttachmentSlots); //Shield settings if(split[0].toLowerCase().equals("shield")) { shield = true; shieldDamageAbsorption = Float.parseFloat(split[1]); shieldOrigin = new Vector3f(Float.parseFloat(split[2]) / 16F, Float.parseFloat(split[3]) / 16F, Float.parseFloat(split[4]) / 16F); shieldDimensions = new Vector3f(Float.parseFloat(split[5]) / 16F, Float.parseFloat(split[6]) / 16F, Float.parseFloat(split[7]) / 16F); } } catch(Exception e) { FlansMod.log.error("Reading gun file failed."); FlansMod.log.throwing(e); } } public boolean isCorrectAmmo(ShootableType type) { return ammo.contains(type); } public boolean isCorrectAmmo(ItemStack stack) { if(stack == null || stack.isEmpty()) return false; else if(stack.getItem() instanceof ItemBullet) { return isCorrectAmmo(((ItemBullet)stack.getItem()).type); } else if(stack.getItem() instanceof ItemGrenade) { return isCorrectAmmo(((ItemGrenade)stack.getItem()).type); } return false; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelGun.class); } @Override public float getZoomFactor() { return zoomLevel; } @Override public boolean hasZoomOverlay() { return hasScopeOverlay; } @Override public String getZoomOverlay() { return defaultScopeTexture; } @Override public float getFOVFactor() { return FOVFactor; } //ItemStack specific methods /** * Return the currently active scope on this gun. Search attachments, and by default, simply give the gun */ public IScope getCurrentScope(ItemStack gunStack) { IScope attachedScope = getScope(gunStack); return attachedScope == null ? this : attachedScope; } /** * Returns all attachments currently attached to the specified gun */ public ArrayList getCurrentAttachments(ItemStack gun) { checkForTags(gun); ArrayList attachments = new ArrayList<>(); NBTTagCompound attachmentTags = gun.getTagCompound().getCompoundTag("attachments"); NBTTagList genericsList = attachmentTags.getTagList("generics", (byte)10); //TODO : Check this 10 is correct for(int i = 0; i < numGenericAttachmentSlots; i++) { appendToList(gun, "generic_" + i, attachments); } appendToList(gun, "barrel", attachments); appendToList(gun, "scope", attachments); appendToList(gun, "stock", attachments); appendToList(gun, "grip", attachments); return attachments; } /** * Private method for attaching attachments to a list of attachments with a nullcheck */ private void appendToList(ItemStack gun, String name, ArrayList attachments) { AttachmentType type = getAttachment(gun, name); if(type != null) attachments.add(type); } //Attachment getter methods public AttachmentType getBarrel(ItemStack gun) { return getAttachment(gun, "barrel"); } public AttachmentType getScope(ItemStack gun) { return getAttachment(gun, "scope"); } public AttachmentType getStock(ItemStack gun) { return getAttachment(gun, "stock"); } public AttachmentType getGrip(ItemStack gun) { return getAttachment(gun, "grip"); } public AttachmentType getGeneric(ItemStack gun, int i) { return getAttachment(gun, "generic_" + i); } //Attachment ItemStack getter methods public ItemStack getBarrelItemStack(ItemStack gun) { return getAttachmentItemStack(gun, "barrel"); } public ItemStack getScopeItemStack(ItemStack gun) { return getAttachmentItemStack(gun, "scope"); } public ItemStack getStockItemStack(ItemStack gun) { return getAttachmentItemStack(gun, "stock"); } public ItemStack getGripItemStack(ItemStack gun) { return getAttachmentItemStack(gun, "grip"); } public ItemStack getGenericItemStack(ItemStack gun, int i) { return getAttachmentItemStack(gun, "generic_" + i); } /** * Generalised attachment getter method */ public AttachmentType getAttachment(ItemStack gun, String name) { checkForTags(gun); return AttachmentType.getFromNBT(gun.getTagCompound().getCompoundTag("attachments").getCompoundTag(name)); } /** * Generalised attachment ItemStack getter method */ public ItemStack getAttachmentItemStack(ItemStack gun, String name) { checkForTags(gun); return new ItemStack(gun.getTagCompound().getCompoundTag("attachments").getCompoundTag(name)); } /** * Method to check for null tags and assign default empty tags in that case */ private void checkForTags(ItemStack gun) { //If the gun has no tags, give it some if(!gun.hasTagCompound()) { gun.setTagCompound(new NBTTagCompound()); } //If the gun has no attachment tags, give it some if(!gun.getTagCompound().hasKey("attachments")) { NBTTagCompound attachmentTags = new NBTTagCompound(); for(int i = 0; i < numGenericAttachmentSlots; i++) attachmentTags.setTag("generic_" + i, new NBTTagCompound()); attachmentTags.setTag("barrel", new NBTTagCompound()); attachmentTags.setTag("scope", new NBTTagCompound()); attachmentTags.setTag("stock", new NBTTagCompound()); attachmentTags.setTag("grip", new NBTTagCompound()); gun.getTagCompound().setTag("attachments", attachmentTags); } } /** * Get the melee damage of a specific gun, taking into account attachments */ public float getMeleeDamage(ItemStack stack) { float stackMeleeDamage = meleeDamage; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackMeleeDamage *= attachment.meleeDamageMultiplier; } return stackMeleeDamage; } /** * Get the damage of a specific gun, taking into account attachments */ public float getDamage(ItemStack stack) { float stackDamage = damage; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackDamage *= attachment.damageMultiplier; } return stackDamage; } /** * Get the bullet spread of a specific gun, taking into account attachments */ public float getSpread(ItemStack stack) { float stackSpread = bulletSpread; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackSpread *= attachment.spreadMultiplier; } return stackSpread; } public EnumSpreadPattern getSpreadPattern(ItemStack stack) { for(AttachmentType attachment : getCurrentAttachments(stack)) { if(attachment.spreadPattern != null) return attachment.spreadPattern; } return spreadPattern; } /** * Get the recoil of a specific gun, taking into account attachments */ public float getRecoil(ItemStack stack) { float stackRecoil = recoil; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackRecoil *= attachment.recoilMultiplier; } return stackRecoil; } /** * Get the bullet speed of a specific gun, taking into account attachments */ public float getBulletSpeed(ItemStack stack) { float stackBulletSpeed = bulletSpeed; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackBulletSpeed *= attachment.bulletSpeedMultiplier; } return stackBulletSpeed; } /** * Get the reload time of a specific gun, taking into account attachments */ public float getReloadTime(ItemStack stack) { float stackReloadTime = reloadTime; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackReloadTime *= attachment.reloadTimeMultiplier; } return stackReloadTime; } /** * Get the firing mode of a specific gun, taking into account attachments */ public EnumFireMode getFireMode(ItemStack stack) { for(AttachmentType attachment : getCurrentAttachments(stack)) { if(attachment.modeOverride != null) return attachment.modeOverride; } return mode; } public float GetShootDelay(ItemStack stack) { for(AttachmentType attachment : getCurrentAttachments(stack)) { if(attachment.modeOverride == EnumFireMode.BURST) return Math.max(shootDelay, 3); } float stackShootDelay = shootDelay; for(AttachmentType attachment : getCurrentAttachments(stack)) { stackShootDelay *= attachment.shootDelayMultiplier; } return stackShootDelay; } /** * Static String to GunType method */ public static GunType getGun(String s) { return guns.get(s.hashCode()); } public static GunType getGun(int hash) { return guns.get(hash); } @Override protected void preRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } @Override public float GetRecommendedScale() { return 60.0f; } /** * @return Returns the pumpDelayAfterReload if a model exits, otherwise 0 */ public Integer getPumpDelayAfterReload() { if (model != null) return model.pumpDelayAfterReload; return 0; } /** * @return Returns the pumpDelay if a model exits, otherwise 0 */ public Integer getPumpDelay() { if (model != null) return model.pumpDelay; return 0; } /** * @return the pump time if a model exits, otherwise 1 */ public Integer getPumpTime() { if (model != null) return model.pumpTime; return 0; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/IScope.java ================================================ package com.flansmod.common.guns; public interface IScope { float getFOVFactor(); float getZoomFactor(); boolean hasZoomOverlay(); String getZoomOverlay(); } ================================================ FILE: src/main/java/com/flansmod/common/guns/InventoryGunModTable.java ================================================ package com.flansmod.common.guns; import net.minecraft.inventory.InventoryBasic; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; public class InventoryGunModTable extends InventoryBasic { public InventoryGunModTable() { super("Gun Modification Table", true, 13); } public ItemStack lastGunStack; public GunType gunType; public int genericScroll = 0; /** * Hacky way to change slots within onInventoryChanged without causing a huge stack overflow */ private boolean busy = false; @Override public void markDirty() { if(busy) return; ItemStack gunStack = getStackInSlot(0); if(gunStack == null || !(gunStack.getItem() instanceof ItemGun)) return; gunType = ((ItemGun)gunStack.getItem()).GetType(); //If we changed the gun (i.e. a new gun has been placed in the table) if(gunStack != lastGunStack) { busy = true; if(!gunStack.hasTagCompound()) gunStack.setTagCompound(new NBTTagCompound()); NBTTagCompound attachmentTags = gunStack.getTagCompound().getCompoundTag("attachments"); if(attachmentTags == null) { attachmentTags = new NBTTagCompound(); gunStack.getTagCompound().setTag("attachments", attachmentTags); } setInventorySlotContents(1, new ItemStack(attachmentTags.getCompoundTag("barrel"))); setInventorySlotContents(2, new ItemStack(attachmentTags.getCompoundTag("scope"))); setInventorySlotContents(3, new ItemStack(attachmentTags.getCompoundTag("stock"))); setInventorySlotContents(4, new ItemStack(attachmentTags.getCompoundTag("grip"))); genericScroll = 0; for(int i = 0; i < Math.min(gunType.numGenericAttachmentSlots, 8); i++) setInventorySlotContents(5 + i, new ItemStack(attachmentTags.getCompoundTag("generic_" + i))); busy = false; } //Else we changed an attachment else { //Create a new NBT tag compound for our gun item NBTTagCompound gunTags = new NBTTagCompound(); //Copy the ammo and paintjob from the old stack gunTags.setTag("ammo", getStackInSlot(0).getTagCompound().getTag("ammo")); if(getStackInSlot(0).getTagCompound().hasKey("Paint")) gunTags.setTag("Paint", getStackInSlot(0).getTagCompound().getTag("Paint")); if(getStackInSlot(0).getTagCompound().hasKey("LegendaryCrafter")) gunTags.setTag("LegendaryCrafter", getStackInSlot(0).getTagCompound().getTag("LegendaryCrafter")); if(getStackInSlot(0).getTagCompound().hasKey("display")) gunTags.setTag("display", getStackInSlot(0).getTagCompound().getTag("display")); //Add each attachment from the inventory to our gun stack NBTTagCompound attachmentTags = new NBTTagCompound(); writeAttachmentTags(attachmentTags, getStackInSlot(1), "barrel"); writeAttachmentTags(attachmentTags, getStackInSlot(2), "scope"); writeAttachmentTags(attachmentTags, getStackInSlot(3), "stock"); writeAttachmentTags(attachmentTags, getStackInSlot(4), "grip"); //Change all the attachments that we are looking at, but copy in the old ones for(int i = 0; i < gunType.numGenericAttachmentSlots; i++) { if(i >= genericScroll * 4 && i < genericScroll * 4 + 8) { writeAttachmentTags(attachmentTags, getStackInSlot(i - genericScroll * 4 + 5), "generic_" + i); } else attachmentTags.setTag("generic_" + i, getStackInSlot(0).getTagCompound().getTag("generic_" + i)); } //Set the tags to be these new tags gunTags.setTag("attachments", attachmentTags); gunStack.setTagCompound(gunTags); } lastGunStack = gunStack; } public void writeAttachmentTags(NBTTagCompound attachmentTags, ItemStack attachmentStack, String attachmentName) { NBTTagCompound tags = new NBTTagCompound(); if(attachmentStack != null) attachmentStack.writeToNBT(tags); attachmentTags.setTag(attachmentName, tags); } @Override public boolean isItemValidForSlot(int i, ItemStack itemstack) { return false; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/InventoryHelper.java ================================================ package com.flansmod.common.guns; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import com.flansmod.common.FlansMod; /** * Adds access to the InventoryPlayer stack combination methods for arbitrary inventories */ public class InventoryHelper { public static boolean addItemStackToInventory(IInventory inventory, ItemStack stack, boolean creative) { if(stack == null || stack.isEmpty()) return false; else if(stack.getCount() == 0) return false; else { try { int i; if(stack.isItemDamaged()) { i = getFirstEmptyStack(inventory); if(i >= 0) { ItemStack stackToAdd = stack.copy(); stackToAdd.setAnimationsToGo(5); inventory.setInventorySlotContents(i, stackToAdd); stack.setCount(0); return true; } else if(creative) { stack.setCount(0); return true; } return false; } else { do { i = stack.getCount(); stack.setCount(storePartialItemStack(inventory, stack)); } while(stack.getCount() > 0 && stack.getCount() < i); if(stack.getCount() == i && creative) { stack.setCount(0); return true; } else { return stack.getCount() < i; } } } catch(Throwable throwable) { FlansMod.log.throwing(throwable); return false; } } } public static int storeItemStack(IInventory inventory, ItemStack stack) { for(int i = 0; i < inventory.getSizeInventory(); ++i) { ItemStack oldStack = inventory.getStackInSlot(i); if(oldStack != null && !oldStack.isEmpty() && oldStack.getItem() == stack.getItem() && oldStack.isStackable() && oldStack.getCount() < oldStack.getMaxStackSize() && oldStack.getCount() < inventory.getInventoryStackLimit() && (!oldStack.getHasSubtypes() || oldStack.getItemDamage() == stack.getItemDamage()) && ItemStack.areItemStackTagsEqual(oldStack, stack)) { return i; } } return -1; } public static int storePartialItemStack(IInventory inventory, ItemStack stack) { Item item = stack.getItem(); int j = stack.getCount(); int k; //If the item doesn't stack, just find an empty slot for it if(stack.getMaxStackSize() == 1) { k = getFirstEmptyStack(inventory); //If it is impossible, return if(k < 0) { return j; } else { if(inventory.getStackInSlot(k) == null || inventory.getStackInSlot(k).isEmpty()) { inventory.setInventorySlotContents(k, stack.copy()); } return 0; } } else { k = storeItemStack(inventory, stack); if(k < 0) { k = getFirstEmptyStack(inventory); } if(k < 0) { return j; } else { ItemStack oldStack = inventory.getStackInSlot(k); if(oldStack == null || oldStack.isEmpty()) { oldStack = new ItemStack(item, 0, stack.getItemDamage()); if(stack.hasTagCompound()) oldStack.setTagCompound(stack.getTagCompound().copy()); inventory.setInventorySlotContents(k, oldStack); } int l = j; if(j > oldStack.getMaxStackSize() - oldStack.getCount()) { l = oldStack.getMaxStackSize() - oldStack.getCount(); } if(l > inventory.getInventoryStackLimit() - oldStack.getCount()) { l = inventory.getInventoryStackLimit() - oldStack.getCount(); } if(l == 0) { return j; } else { j -= l; oldStack.setCount(oldStack.getCount() + l); oldStack.setAnimationsToGo(5); return j; } } } } /** * Method from InventoryPlayer */ public static int getFirstEmptyStack(IInventory inventory) { for(int i = 0; i < inventory.getSizeInventory(); ++i) if(inventory.getStackInSlot(i) == null || inventory.getStackInSlot(i).isEmpty()) return i; return -1; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemAAGun.java ================================================ package com.flansmod.common.guns; import java.util.ArrayList; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class ItemAAGun extends Item implements IFlanItem { public static final ArrayList names = new ArrayList<>(); public AAGunType type; public ItemAAGun(AAGunType type1) { maxStackSize = 1; type = type1; type.item = this; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanGuns); } @Override public ActionResult onItemRightClick(World world, EntityPlayer entityplayer, EnumHand hand) { ItemStack itemstack = entityplayer.getHeldItem(hand); //Raytracing float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F); float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F); double length = 5D; Vec3d posVec = new Vec3d(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ); Vec3d lookVec = posVec.add(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length); RayTraceResult RayTraceResult = world.rayTraceBlocks(posVec, lookVec, true); //Result check if(RayTraceResult == null) { return new ActionResult<>(EnumActionResult.PASS, itemstack); } if(RayTraceResult.typeOfHit == Type.BLOCK) { int i = RayTraceResult.getBlockPos().getX(); int j = RayTraceResult.getBlockPos().getY(); int k = RayTraceResult.getBlockPos().getZ(); if(!world.isRemote && world.isSideSolid(RayTraceResult.getBlockPos(), EnumFacing.UP)) { world.spawnEntity(new EntityAAGun(world, type, (double)i + 0.5F, (double)j + 1F, (double)k + 0.5F, entityplayer)); } if(!entityplayer.capabilities.isCreativeMode) { itemstack.setCount(itemstack.getCount() - 1); } return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } return new ActionResult<>(EnumActionResult.PASS, itemstack); } public Entity spawnAAGun(World world, double x, double y, double z, ItemStack stack) { Entity entity = new EntityAAGun(world, type, x, y, z, null); if(!world.isRemote) { world.spawnEntity(entity); } return entity; } @Override public InfoType getInfoType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemAttachment.java ================================================ package com.flansmod.common.guns; import java.util.Collections; import java.util.List; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.NonNullList; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.types.InfoType; public class ItemAttachment extends Item implements IPaintableItem { public AttachmentType type; public ItemAttachment(AttachmentType t) { type = t; type.item = this; maxStackSize = t.maxStackSize; setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanGuns); } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } if(type.shootDelayMultiplier != 1.0f) lines.add("Rate of Fire x" + MathHelper.floor(100.0f / type.shootDelayMultiplier) + "%"); if(type.damageMultiplier != 1.0f) lines.add("Damage x" + MathHelper.floor(type.damageMultiplier * 100.0f) + "%"); if(type.recoilMultiplier != 1.0f) lines.add("Recoil x" + MathHelper.floor(type.recoilMultiplier * 100.0f) + "%"); if(type.spreadMultiplier != 1.0f) lines.add("Bullet Spread x" + MathHelper.floor(type.spreadMultiplier * 100.0f) + "%"); if(type.reloadTimeMultiplier != 1.0f) lines.add("Reload Time x" + MathHelper.floor(type.reloadTimeMultiplier * 100.0f) + "%"); if(type.bulletSpeedMultiplier != 1.0f) lines.add("Projectile Speed x" + MathHelper.floor(type.bulletSpeedMultiplier * 100.0f) + "%"); if(type.silencer) lines.add("Silenced"); if(type.meleeDamageMultiplier != 1.0f) lines.add("Melee Damage x" + MathHelper.floor(type.meleeDamageMultiplier * 100.0f) + "%"); if(type.flashlight) lines.add("Flashlight " + type.flashlightStrength); } @Override public InfoType getInfoType() { return type; } @Override public PaintableType GetPaintableType() { return type; } // ----------------- Paintjobs ----------------- @Override public void getSubItems(CreativeTabs tab, NonNullList items) { if(tab != FlansMod.tabFlanGuns && tab != CreativeTabs.SEARCH) return; PaintableType type = ((IPaintableItem)this).GetPaintableType(); if(FlansMod.addAllPaintjobsToCreative) { for(Paintjob paintjob : type.paintjobs) addPaintjobToList(this, type, paintjob, items); } else addPaintjobToList(this, type, type.defaultPaintjob, items); } private void addPaintjobToList(Item item, PaintableType type, Paintjob paintjob, List list) { ItemStack paintableStack = new ItemStack(item, 1, paintjob.ID); NBTTagCompound tags = new NBTTagCompound(); paintableStack.setTagCompound(tags); list.add(paintableStack); } // --------------------------------------------- } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemBullet.java ================================================ package com.flansmod.common.guns; import java.util.Collections; import java.util.List; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; /** * Implemented from old source. */ public class ItemBullet extends ItemShootable implements IFlanItem { public BulletType type; public ItemBullet(BulletType infoType) { super(infoType); type = infoType; setMaxStackSize(type.maxStackSize); setHasSubtypes(true); type.item = this; switch(type.weaponType) { case SHELL: case BOMB: case MINE: case MISSILE: setCreativeTab(FlansMod.tabFlanDriveables); break; default: setCreativeTab(FlansMod.tabFlanGuns); } } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } } @Override public InfoType getInfoType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemGrenade.java ================================================ package com.flansmod.common.guns; import java.util.Collections; import java.util.List; import com.google.common.collect.Multimap; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumHand; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class ItemGrenade extends ItemShootable implements IFlanItem { public GrenadeType type; public ItemGrenade(GrenadeType t) { super(t); type = t; type.item = this; setCreativeTab(FlansMod.tabFlanGuns); } @Override public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) { Multimap multimap = super.getAttributeModifiers(slot, stack); if(EntityEquipmentSlot.MAINHAND.equals(slot)) { multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", type.meleeDamage, 0)); } return multimap; } @Override public boolean isFull3D() { return true; } @Override public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) { return type.meleeDamage == 0; } @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { ItemStack stack = player.getHeldItem(hand); PlayerData data = PlayerHandler.getPlayerData(player, world.isRemote ? Side.CLIENT : Side.SERVER); //If can throw grenade if(type.canThrow && data != null && data.shootTimeRight <= 0 && data.shootTimeLeft <= 0) { //Delay the next throw / weapon fire / whatnot data.shootTimeRight = type.throwDelay; //Create a new grenade entity EntityGrenade grenade = new EntityGrenade(player, this.type); //Spawn the entity server side if(!world.isRemote) world.spawnEntity(grenade); //If this can be remotely detonated, add it to the players detonate list if(type.remote) data.remoteExplosives.add(grenade); //Consume an item if(!player.capabilities.isCreativeMode) stack.setCount(stack.getCount() - 1); //Drop an item upon throwing if necessary if(type.dropItemOnThrow != null) { ItemStack dropStack = InfoType.getRecipeElement(type.dropItemOnDetonate); world.spawnEntity(new EntityItem(world, player.posX, player.posY, player.posZ, dropStack)); } return new ActionResult<>(EnumActionResult.SUCCESS, stack); } return new ActionResult<>(EnumActionResult.FAIL, stack); } @Override public InfoType getInfoType() { return type; } private EntityGrenade getGrenade(World world, EntityLivingBase thrower) { //Create a new grenade entity EntityGrenade grenade = new EntityGrenade(thrower, type); //If this can be remotely detonated, add it to the players detonate list if(type.remote && thrower instanceof EntityPlayer) PlayerHandler.getPlayerData((EntityPlayer)thrower).remoteExplosives.add(grenade); return grenade; } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } } public void throwGrenade(World world, EntityLivingBase thrower) { EntityGrenade grenade = getGrenade(world, thrower); world.spawnEntity(grenade); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemGun.java ================================================ package com.flansmod.common.guns; import javax.annotation.Nullable; import java.util.Collections; import java.util.List; import java.util.UUID; import org.lwjgl.input.Mouse; import com.google.common.collect.Multimap; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.inventory.IInventory; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemShield; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.ActionResult; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.FlansModClient; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.client.model.GunAnimations; import com.flansmod.common.EntityItemCustomRender; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.enchantments.EnchantmentModule; import com.flansmod.common.enchantments.ItemGlove; import com.flansmod.common.guns.raytracing.FlansModRaytracer; import com.flansmod.common.network.PacketGunFire; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.network.PacketReload; import com.flansmod.common.paintjob.IPaintableItem; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.teams.EntityFlag; import com.flansmod.common.teams.EntityFlagpole; import com.flansmod.common.teams.EntityGunItem; import com.flansmod.common.types.InfoType; import com.flansmod.common.vector.Vector3f; public class ItemGun extends Item implements IPaintableItem { private GunType type; public GunType GetType() { return type; } @Override public InfoType getInfoType() { return type; } @Override public PaintableType GetPaintableType() { return type; } private int soundDelay = 0; private static boolean rightMouseHeld; private static boolean lastRightMouseHeld; private static boolean leftMouseHeld; private static boolean lastLeftMouseHeld; private static boolean GetMouseHeld(EnumHand hand) { if(FlansMod.shootOnRightClick) return hand == EnumHand.MAIN_HAND ? rightMouseHeld : leftMouseHeld; else return hand == EnumHand.MAIN_HAND ? leftMouseHeld : rightMouseHeld; } private static boolean GetLastMouseHeld(EnumHand hand) { if(FlansMod.shootOnRightClick) return hand == EnumHand.MAIN_HAND ? lastRightMouseHeld : lastLeftMouseHeld; else return hand == EnumHand.MAIN_HAND ? lastLeftMouseHeld : lastRightMouseHeld; } public ItemGun(GunType type) { maxStackSize = 1; this.type = type; type.item = this; setMaxDamage(0); setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanGuns); } /** * Get the bullet item stack stored in the gun's NBT data (the loaded magazine / bullets) */ public ItemStack getBulletItemStack(ItemStack gun, int id) { //If the gun has no tags, give it some if(!gun.hasTagCompound()) { gun.setTagCompound(new NBTTagCompound()); return ItemStack.EMPTY.copy(); } //If the gun has no ammo tags, give it some if(!gun.getTagCompound().hasKey("ammo")) { NBTTagList ammoTagsList = new NBTTagList(); for(int i = 0; i < type.numAmmoItemsInGun; i++) { ammoTagsList.appendTag(new NBTTagCompound()); } gun.getTagCompound().setTag("ammo", ammoTagsList); return ItemStack.EMPTY.copy(); } //Take the list of ammo tags NBTTagList ammoTagsList = gun.getTagCompound().getTagList("ammo", Constants.NBT.TAG_COMPOUND); //Get the specific ammo tags required NBTTagCompound ammoTags = ammoTagsList.getCompoundTagAt(id); return new ItemStack(ammoTags); } /** * Set the bullet item stack stored in the gun's NBT data (the loaded magazine / bullets) */ public void setBulletItemStack(ItemStack gun, ItemStack bullet, int id) { //If the gun has no tags, give it some if(!gun.hasTagCompound()) { gun.setTagCompound(new NBTTagCompound()); } //If the gun has no ammo tags, give it some if(!gun.getTagCompound().hasKey("ammo")) { NBTTagList ammoTagsList = new NBTTagList(); for(int i = 0; i < type.numAmmoItemsInGun; i++) { ammoTagsList.appendTag(new NBTTagCompound()); } gun.getTagCompound().setTag("ammo", ammoTagsList); } //Take the list of ammo tags NBTTagList ammoTagsList = gun.getTagCompound().getTagList("ammo", Constants.NBT.TAG_COMPOUND); //Get the specific ammo tags required NBTTagCompound ammoTags = ammoTagsList.getCompoundTagAt(id); //Represent empty slots by nulltypes if(bullet == null) { ammoTags = new NBTTagCompound(); } //Set the tags to match the bullet stack bullet.writeToNBT(ammoTags); } /** * Method for dropping items on reload and on shoot */ public static void dropItem(World world, Entity entity, String itemName) { if(itemName != null && !world.isRemote) { ItemStack dropStack = InfoType.getRecipeElement(itemName); entity.entityDropItem(dropStack, 0.5F); } } /** * Deployable guns only */ @Override public ActionResult onItemRightClick(World world, EntityPlayer entityplayer, EnumHand hand) { ItemStack itemstack = entityplayer.getHeldItem(hand); if(type.deployable) { //Raytracing float cosYaw = MathHelper.cos(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float sinYaw = MathHelper.sin(-entityplayer.rotationYaw * 0.01745329F - 3.141593F); float cosPitch = -MathHelper.cos(-entityplayer.rotationPitch * 0.01745329F); float sinPitch = MathHelper.sin(-entityplayer.rotationPitch * 0.01745329F); double length = 5D; Vec3d posVec = new Vec3d(entityplayer.posX, entityplayer.posY + 1.62D - entityplayer.getYOffset(), entityplayer.posZ); Vec3d lookVec = posVec.add(sinYaw * cosPitch * length, sinPitch * length, cosYaw * cosPitch * length); RayTraceResult look = world.rayTraceBlocks(posVec, lookVec, true); //Result check if(look != null && look.typeOfHit == Type.BLOCK) { if(look.sideHit == EnumFacing.UP) { int playerDir = MathHelper.floor(((entityplayer.rotationYaw * 4F) / 360F) + 0.5D) & 3; int i = look.getBlockPos().getX(); int j = look.getBlockPos().getY(); int k = look.getBlockPos().getZ(); if(!world.isRemote) { if(world.getBlockState(new BlockPos(i, j, k)).getBlock() == Blocks.SNOW) { j--; } if(isSolid(world, i, j, k) && (world.getBlockState(new BlockPos(i, j + 1, k)).getBlock() == Blocks.AIR || world.getBlockState(new BlockPos(i, j + 1, k)).getBlock() == Blocks.SNOW) && (world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j + 1, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.AIR) && (world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.AIR || world.getBlockState(new BlockPos(i + (playerDir == 1 ? 1 : 0) - (playerDir == 3 ? 1 : 0), j, k - (playerDir == 0 ? 1 : 0) + (playerDir == 2 ? 1 : 0))).getBlock() == Blocks.SNOW)) { for(EntityMG mg : EntityMG.mgs) { if(mg.blockX == i && mg.blockY == j + 1 && mg.blockZ == k && !mg.isDead) return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } EntityMG mg = new EntityMG(world, i, j + 1, k, playerDir, type); if(getBulletItemStack(itemstack, 0) != null) { mg.ammo = getBulletItemStack(itemstack, 0); } world.spawnEntity(mg); if(!entityplayer.capabilities.isCreativeMode) itemstack.setCount(0); } } } } } //Stop the gun bobbing up and down when holding shoot and looking at a block if(world.isRemote) { for(int i = 0; i < 3; i++) Minecraft.getMinecraft().entityRenderer.itemRenderer.updateEquippedItem(); } return new ActionResult<>(EnumActionResult.PASS, itemstack); } // _____________________________________________________________________________ // // Shooting code // _____________________________________________________________________________ @SideOnly(Side.CLIENT) public void onUpdateClient(ItemStack gunstack, int gunSlot, World world, Entity entity, EnumHand hand, boolean hasOffHand) { if(!(entity instanceof EntityPlayer)) { //This code is for players only return; } // This code is not for deployables if(type.deployable) return; //Scope Handling IScope currentScope = type.getCurrentScope(gunstack); if(!hasOffHand) { switch(hand) { case MAIN_HAND: { if(GetMouseHeld(EnumHand.OFF_HAND) && !GetLastMouseHeld(EnumHand.OFF_HAND) && (type.secondaryFunction == EnumSecondaryFunction.ADS_ZOOM || type.secondaryFunction == EnumSecondaryFunction.ZOOM)) { FlansModClient.setScope(currentScope); } break; } case OFF_HAND: { if(GetMouseHeld(EnumHand.MAIN_HAND) && !GetLastMouseHeld(EnumHand.MAIN_HAND) && (type.secondaryFunction == EnumSecondaryFunction.ADS_ZOOM || type.secondaryFunction == EnumSecondaryFunction.ZOOM)) { FlansModClient.setScope(currentScope); } break; } } } // Get useful objects Minecraft mc = Minecraft.getMinecraft(); EntityPlayer player = (EntityPlayer) entity; PlayerData data = PlayerHandler.getPlayerData(player); //Slow down minigun data.minigunSpeed *= 0.9f; Boolean hold = GetMouseHeld(hand); Boolean held = GetLastMouseHeld(hand); // Do not shoot ammo bags, flags or dropped gun items if(mc.objectMouseOver != null && (mc.objectMouseOver.entityHit instanceof EntityFlagpole || mc.objectMouseOver.entityHit instanceof EntityFlag || mc.objectMouseOver.entityHit instanceof EntityGunItem || (mc.objectMouseOver.entityHit instanceof EntityGrenade && ((EntityGrenade)mc.objectMouseOver.entityHit).type.isDeployableBag))) hold = false; //TODO idle sound should be done on the server side // Play idle sounds if(soundDelay <= 0 && type.idleSound != null) { PacketPlaySound.sendSoundPacket(player.posX, player.posY, player.posZ, FlansMod.soundRange, player.dimension, type.idleSound, false); soundDelay = type.idleSoundLength; } if (!gunCanBeHandled(type, player)) return; if(type.usableByPlayers) { GunAnimations animations = FlansModClient.getGunAnimations(player, hand); boolean needsToReload = needsToReload(gunstack); boolean shouldShootThisTick = false; switch(type.getFireMode(gunstack)) { case BURST: { //PlayerData burst rounds handled on client if(data.GetBurstRoundsRemaining(hand) > 0) { shouldShootThisTick = true; } // Fallthrough to semi auto } case SEMIAUTO: { if(hold && !held) { shouldShootThisTick = true; } else needsToReload = false; break; } case MINIGUN: { if(needsToReload) { needsToReload = hold; break; } if(hold) { //PlayerData minigunspeed used on client side if (data.minigunSpeed < type.minigunMaxSpeed) { data.minigunSpeed += 2.0f; animations.addMinigunBarrelRotationSpeed(2.0f); } // TODO : Re-add looping sounds if(data.minigunSpeed < type.minigunStartSpeed) { if(type.useLoopingSounds && data.loopedSoundDelay <= 0 && data.minigunSpeed > 0.1F && !data.reloadingRight && !data.isSpinning) { data.loopedSoundDelay = type.warmupSoundLength; PacketPlaySound.sendSoundPacket(player.posX, player.posY, player.posZ, FlansMod.soundRange, player.dimension, type.warmupSound, false); data.isSpinning = true; } break; } } //else fallthrough to full auto } case FULLAUTO: { shouldShootThisTick = hold; if(!shouldShootThisTick) { needsToReload = false; } //Play looping sounds for minigun if(type.useLoopingSounds && data.loopedSoundDelay <= 0 && data.minigunSpeed > type.minigunStartSpeed) { data.loopedSoundDelay = type.loopedSoundLength; PacketPlaySound.sendSoundPacket(player.posX, player.posY, player.posZ, FlansMod.soundRange, player.dimension, type.loopedSound, false); data.isSpinning = true; // isSpinning = true } if(type.useLoopingSounds && data.isSpinning && data.minigunSpeed < type.minigunStartSpeed) { PacketPlaySound.sendSoundPacket(player.posX, player.posY, player.posZ, FlansMod.soundRange, player.dimension, type.cooldownSound, false); data.isSpinning = false; } break; } default: needsToReload = false; break; } // Do reload if we pressed fire. if(needsToReload) { FlansMod.getPacketHandler().sendToServer(new PacketReload(hand, false)); } // Fire! else if(shouldShootThisTick) { shoot(hand, player, gunstack, data, world, animations); } } } /** * Used to determine if for example an player is holding a two handed gun but the other hand (the one without a gun) is holding something else * For example a player is holding two miniguns, a gun requiring both hands, so this method returns true * * @param type The GunType of the gun * @param player The player who is handling the gun * @return if the player can handle the gun based on the contents of the main and off hand and the GunType */ public boolean gunCanBeHandled(GunType type, EntityPlayer player) { // We can always use a 1H gun if(type.oneHanded) return true; ItemStack main = player.getHeldItemMainhand(); ItemStack off = player.getHeldItemOffhand(); Boolean hasItemInBothHands = !main.isEmpty() && !off.isEmpty(); if(hasItemInBothHands) { // Gloves are special enchantable items that can be placed in the offhand while still letting you shoot 2H if(off.getItem() instanceof ItemGlove) return true; else return false; } return true; } public void shoot(EnumHand hand, EntityPlayer player, ItemStack gunstack, PlayerData data, World world, @Nullable GunAnimations animations) { if(type.usableByPlayers) { float shootTime = data.GetShootTime(hand); ItemStack otherHand = null; if(hand == EnumHand.MAIN_HAND) otherHand = player.getHeldItemOffhand(); else otherHand = player.getHeldItemMainhand(); if (!world.isRemote && shootTime > 0f) { //data.addToQueue(hand); //Hacky code //This essentially skips ticks for a smoother client experience if (shootTime < 4) { while (shootTime > 0) { shootTime--; } } } if (world.isRemote && shootTime <= 0) //Send the server the instruction to shoot FlansMod.getPacketHandler().sendToServer(new PacketGunFire(hand)); // For each while(shootTime <= 0.0f) { // Add the delay for this shot and shoot it! shootTime += type.GetShootDelay(gunstack); int bulletID = 0; ItemStack bulletStack = ItemStack.EMPTY.copy(); for(; bulletID < type.numAmmoItemsInGun; bulletID++) { ItemStack checkingStack = getBulletItemStack(gunstack, bulletID); if(checkingStack != null && checkingStack.getItemDamage() < checkingStack.getMaxDamage()) { bulletStack = checkingStack; break; } } if(bulletStack.isEmpty()) { continue; } final ItemStack bullet = bulletStack; final Integer bulletid = bulletID; ItemShootable shootableItem = (ItemShootable)bulletStack.getItem(); ShootableType shootableType = shootableItem.type; Vector3f rayTraceOrigin = new Vector3f(player.getPositionEyes(0.0f)); ShootBulletHandler handler = isExtraBullet -> { if(!isExtraBullet) { // Drop item on shooting if bullet requires it if(shootableType.dropItemOnShoot != null && !player.capabilities.isCreativeMode) dropItem(world, player, shootableType.dropItemOnShoot); // Drop item on shooting if gun requires it if(type.dropItemOnShoot != null)// && !entityplayer.capabilities.isCreativeMode) dropItem(world, player, type.dropItemOnShoot); if(type.knockback > 0) { //TODO : Apply knockback } //Damage the bullet item bullet.setItemDamage(bullet.getItemDamage() + 1); //Update the stack in the gun setBulletItemStack(gunstack, bullet, bulletid); if(type.consumeGunUponUse) { player.setHeldItem(hand, ItemStack.EMPTY.copy()); } } }; if (world.isRemote) { Integer bulletAmount = type.numBullets*shootableType.numBullets; for(int i = 0; i < bulletAmount; i++) { //Smooth effects, no need to wait for the server response handler.shooting(i < bulletAmount - 1); } animations.doShoot(type.getPumpDelay(), type.getPumpTime()); Float recoil = type.getRecoil(gunstack); FlansModClient.playerRecoil += recoil; animations.recoil += recoil; } else { Vector3f rayTraceDirection = new Vector3f(player.getLookVec()); if (shootableType instanceof BulletType) { //Fire gun FireableGun fireableGun = new FireableGun(type, type.getDamage(gunstack), type.getSpread(gunstack), type.bulletSpeed, type.getSpreadPattern(gunstack)); if(otherHand.getItem() instanceof ItemShield || otherHand.getItem() instanceof ItemGlove) { EnchantmentModule.ModifyGun(fireableGun, player, otherHand); } FiredShot shot = new FiredShot(fireableGun, (BulletType)shootableType, (EntityPlayerMP)player); //TODO gunOrigin? & animation origin ShotHandler.fireGun(world, shot, type.numBullets*shootableType.numBullets, rayTraceOrigin, rayTraceDirection, handler); } else if (shootableType instanceof GrenadeType) { //throw grenade ItemGrenade grenade = (ItemGrenade) shootableItem; grenade.throwGrenade(world, player); handler.shooting(false); } boolean silenced = type.getBarrel(gunstack) != null && type.getBarrel(gunstack).silencer; playShotSound(world, rayTraceOrigin, silenced); } int gunSlot = player.inventory.currentItem; if(type.consumeGunUponUse) player.inventory.setInventorySlotContents(gunSlot, ItemStack.EMPTY.copy()); } data.SetShootTime(hand, shootTime); } } public void shootServer(EnumHand hand, EntityPlayerMP player, ItemStack gunstack) { // Get useful objects PlayerData data = PlayerHandler.getPlayerData(player, Side.SERVER); World world = player.getServerWorld(); // This code is not for deployables if(type.deployable) return; if (!gunCanBeHandled(type, player)) return; shoot(hand, player, gunstack, data, world, null); if(FlansMod.DEBUG) { Vector3f gunOrigin = FlansModRaytracer.GetPlayerMuzzlePosition(player, hand); world.spawnEntity(new EntityDebugDot(world, gunOrigin, 100, 1.0f, 1.0f, 1.0f)); } } public void playShotSound(World world, Vector3f position, Boolean silenced) { // Play shot sounds if(soundDelay <= 0 && type.shootSound != null) { PacketPlaySound.sendSoundPacket(position.x, position.y, position.z, FlansMod.soundRange, world.provider.getDimension(), type.shootSound, silenced); soundDelay = type.idleSoundLength; } } @SideOnly(Side.CLIENT) private void PlayShotSound(World world, boolean silenced, float x, float y, float z) { FMLClientHandler.instance().getClient().getSoundHandler().playSound( new PositionedSoundRecord(FlansModResourceHandler.getSoundEvent(type.shootSound), SoundCategory.PLAYERS, silenced ? 5F : 10F, (type.distortSound ? 1.0F / (world.rand.nextFloat() * 0.4F + 0.8F) : 1.0F) * (silenced ? 2F : 1F), x, y, z)); } public void onUpdateServer(ItemStack itemstack, int gunSlot, World world, Entity entity, EnumHand hand, boolean hasOffHand) { if(!(entity instanceof EntityPlayerMP)) { return; } EntityPlayerMP player = (EntityPlayerMP)entity; PlayerData data = PlayerHandler.getPlayerData(player); if(player.inventory.getCurrentItem() != itemstack) { //If the player is no longer holding a gun, emulate a release of the shoot button if(player.inventory.getCurrentItem().isEmpty() || !(player.inventory.getCurrentItem().getItem() instanceof ItemGun)) { data.isShootingRight = data.isShootingLeft = false; } return; } // And finally do sounds if(soundDelay > 0) { soundDelay--; } } /** * Generic update method. If we have an off hand weapon, it will also make calls for that * Passes on to onUpdateEach */ @Override public void onUpdate(ItemStack itemstack, World world, Entity entity, int i, boolean flag) { if(entity instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)entity; EnumHand hand; if(itemstack == player.getHeldItemMainhand()) { hand = EnumHand.MAIN_HAND; } else if(itemstack == player.getHeldItemOffhand()) { hand = EnumHand.OFF_HAND; } else { return; } if(world.isRemote && Minecraft.getMinecraft().currentScreen == null) { // Get button presses. Do this before splitting into each hand. Prevents second pass wiping the data lastRightMouseHeld = rightMouseHeld; lastLeftMouseHeld = leftMouseHeld; rightMouseHeld = Mouse.isButtonDown(1); leftMouseHeld = Mouse.isButtonDown(0); } ItemStack main = player.getHeldItemMainhand(); ItemStack off = player.getHeldItemOffhand(); boolean hasOffHand = !main.isEmpty() && !off.isEmpty(); onUpdateEach(itemstack, i, world, entity, hand, hasOffHand); } } /** * Called once for each weapon we are weilding */ private void onUpdateEach(ItemStack itemstack, int gunSlot, World world, Entity entity, EnumHand hand, boolean hasOffHand) { if(world.isRemote) onUpdateClient(itemstack, gunSlot, world, entity, hand, hasOffHand); else onUpdateServer(itemstack, gunSlot, world, entity, hand, hasOffHand); } public boolean Reload(ItemStack gunstack, World world, Entity entity, IInventory inventory, EnumHand hand, boolean hasOffHand, boolean forceReload, boolean isCreative) { //Deployable guns cannot be reloaded in the inventory //TODO investigate if this code can can actually be called by an deployable if(type.deployable) return false; //If you cannot reload half way through a clip, reject the player for trying to do so if(forceReload && !type.canForceReload) return false; //For playing sounds afterwards boolean reloadedSomething = false; //Check each ammo slot, one at a time for(int i = 0; i < type.numAmmoItemsInGun; i++) { //Get the stack in the slot ItemStack bulletStack = getBulletItemStack(gunstack, i); //If there is no magazine, if the magazine is empty or if this is a forced reload if(bulletStack == null || bulletStack.isEmpty() || bulletStack.getItemDamage() == bulletStack.getMaxDamage() || forceReload) { //Iterate over all inventory slots and find the magazine / bullet item with the most bullets int bestSlot = -1; int bulletsInBestSlot = 0; for(int j = 0; j < inventory.getSizeInventory(); j++) { ItemStack item = inventory.getStackInSlot(j); if(item.getItem() instanceof ItemShootable && type.isCorrectAmmo(((ItemShootable)(item.getItem())).type)) { int bulletsInThisSlot = item.getMaxDamage() - item.getItemDamage(); if(bulletsInThisSlot > bulletsInBestSlot) { bestSlot = j; bulletsInBestSlot = bulletsInThisSlot; } } } //If there was a valid non-empty magazine / bullet item somewhere in the inventory, load it if(bestSlot != -1) { ItemStack newBulletStack = inventory.getStackInSlot(bestSlot); ShootableType newBulletType = ((ItemShootable)newBulletStack.getItem()).type; //Unload the old magazine (Drop an item if it is required and the player is not in creative mode) if(bulletStack != null && bulletStack.getItem() instanceof ItemShootable && ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload != null && !isCreative && bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { if(!world.isRemote) dropItem(world, entity, ((ItemShootable)bulletStack.getItem()).type.dropItemOnReload); } //The magazine was not finished, pull it out and give it back to the player or, failing that, drop it if(bulletStack != null && !bulletStack.isEmpty() && bulletStack.getItemDamage() < bulletStack.getMaxDamage()) { if(!InventoryHelper.addItemStackToInventory(inventory, bulletStack, isCreative)) { if(!world.isRemote) entity.entityDropItem(bulletStack, 0.5F); } } //Load the new magazine ItemStack stackToLoad = newBulletStack.copy(); stackToLoad.setCount(1); setBulletItemStack(gunstack, stackToLoad, i); //Remove the magazine from the inventory if(!isCreative) newBulletStack.setCount(newBulletStack.getCount() - 1); if(newBulletStack.getCount() <= 0) newBulletStack = ItemStack.EMPTY.copy(); inventory.setInventorySlotContents(bestSlot, newBulletStack); //Tell the sound player that we reloaded something reloadedSomething = true; } } } return reloadedSomething; } // TODO : All this bunk /* Melee MESS * @Override public void onUpdate(ItemStack itemstack, World world, Entity pEnt, int i, boolean flag) { if(world.isRemote) onUpdateClient(itemstack, world, pEnt, i, flag); else onUpdateServer(itemstack, world, pEnt, i, flag); if(pEnt instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)pEnt; PlayerData data = PlayerHandler.getPlayerData(player); if(data == null) return; //if(data.lastMeleePositions == null || data.lastMeleePositions.length != type.meleeDamagePoints.size()) //{ // data.lastMeleePositions = new Vector3f[type.meleeDamagePoints.size()]; // for(int j = 0; j < type.meleeDamagePoints.size(); j++) // data.lastMeleePositions[j] = new Vector3f(player.posX, player.posY, player.posZ); //} //Melee weapon if(data.meleeLength > 0 && type.meleePath.size() > 0 && player.inventory.getCurrentItem() == itemstack) { for(int k = 0; k < type.meleeDamagePoints.size(); k++) { Vector3f meleeDamagePoint = type.meleeDamagePoints.get(k); //Do a raytrace from the prev pos to the current pos and attack anything in the way Vector3f nextPos = type.meleePath.get((data.meleeProgress + 1) % type.meleePath.size()); Vector3f nextAngles = type.meleePathAngles.get((data.meleeProgress + 1) % type.meleePathAngles.size()); RotatedAxes nextAxes = new RotatedAxes().rotateGlobalRoll(-nextAngles.x).rotateGlobalPitch(-nextAngles.z).rotateGlobalYaw(-nextAngles.y); Vector3f nextPosInGunCoords = nextAxes.findLocalVectorGlobally(meleeDamagePoint); Vector3f.add(nextPos, nextPosInGunCoords, nextPosInGunCoords); Vector3f.add(new Vector3f(0F, 0F, 0F), nextPosInGunCoords, nextPosInGunCoords); Vector3f nextPosInPlayerCoords = new RotatedAxes(player.rotationYaw + 90F, player.rotationPitch, 0F).findLocalVectorGlobally(nextPosInGunCoords); if(!FlansMod.proxy.isThePlayer(player)) nextPosInPlayerCoords.y += 1.6F; Vector3f nextPosInWorldCoords = new Vector3f(player.posX + nextPosInPlayerCoords.x, player.posY + nextPosInPlayerCoords.y, player.posZ + nextPosInPlayerCoords.z); Vector3f dPos = data.lastMeleePositions[k] == null ? new Vector3f() : Vector3f.sub(nextPosInWorldCoords, data.lastMeleePositions[k], null); if(player.world.isRemote && FlansMod.DEBUG) player.world.spawnEntity(new EntityDebugVector(player.world, data.lastMeleePositions[k], dPos, 200, 1F, 0F, 0F)); //Do the raytrace { //Create a list for all bullet hits ArrayList hits = new ArrayList(); //Iterate over all entities for(int j = 0; j < world.loadedEntityList.size(); j++) { Object obj = world.loadedEntityList.get(j); //Get players if(obj instanceof EntityPlayer) { EntityPlayer otherPlayer = (EntityPlayer)obj; PlayerData otherData = PlayerHandler.getPlayerData(otherPlayer); boolean shouldDoNormalHitDetect = false; if(otherPlayer == player) continue; if(otherData != null) { if(otherPlayer.isDead || otherData.team == Team.spectators) { continue; } int snapshotToTry = player instanceof EntityPlayerMP ? ((EntityPlayerMP)player).ping / 50 : 0; if(snapshotToTry >= otherData.snapshots.length) snapshotToTry = otherData.snapshots.length - 1; PlayerSnapshot snapshot = otherData.snapshots[snapshotToTry]; if(snapshot == null) snapshot = otherData.snapshots[0]; //DEBUG //snapshot = new PlayerSnapshot(player); //Check one last time for a null snapshot. If this is the case, fall back to normal hit detection if(snapshot == null) shouldDoNormalHitDetect = true; else { //Raytrace ArrayList playerHits = snapshot.raytrace(data.lastMeleePositions[k] == null ? nextPosInWorldCoords : data.lastMeleePositions[k], dPos); hits.addAll(playerHits); } } //If we couldn't get a snapshot, use normal entity hitbox calculations if(otherData == null || shouldDoNormalHitDetect) { RayTraceResult mop = data.lastMeleePositions[k] == null ? player.getEntityBoundingBox().calculateIntercept(nextPosInWorldCoords.toVec3(), new Vec3d(0F, 0F, 0F)) : player.getBoundingBox().calculateIntercept(data.lastMeleePositions[k].toVec3(), nextPosInWorldCoords.toVec3()); if(mop != null) { Vector3f hitPoint = new Vector3f(mop.hitVec.x - data.lastMeleePositions[k].x, mop.hitVec.y - data.lastMeleePositions[k].y, mop.hitVec.z - data.lastMeleePositions[k].z); float hitLambda = 1F; if(dPos.x != 0F) hitLambda = hitPoint.x / dPos.x; else if(dPos.y != 0F) hitLambda = hitPoint.y / dPos.y; else if(dPos.z != 0F) hitLambda = hitPoint.z / dPos.z; if(hitLambda < 0) hitLambda = -hitLambda; hits.add(new PlayerBulletHit(new PlayerHitbox(otherPlayer, new RotatedAxes(), new Vector3f(), new Vector3f(), new Vector3f(), EnumHitboxType.BODY), hitLambda)); } } } else { Entity entity = (Entity)obj; if(entity != player && !entity.isDead && (entity instanceof EntityLivingBase || entity instanceof EntityAAGun)) { RayTraceResult mop = entity.getEntityBoundingBox().calculateIntercept(data.lastMeleePositions[k].toVec3(), nextPosInWorldCoords.toVec3()); if(mop != null) { Vector3f hitPoint = new Vector3f(mop.hitVec.x - data.lastMeleePositions[k].x, mop.hitVec.y - data.lastMeleePositions[k].y, mop.hitVec.z - data.lastMeleePositions[k].z); float hitLambda = 1F; if(dPos.x != 0F) hitLambda = hitPoint.x / dPos.x; else if(dPos.y != 0F) hitLambda = hitPoint.y / dPos.y; else if(dPos.z != 0F) hitLambda = hitPoint.z / dPos.z; if(hitLambda < 0) hitLambda = -hitLambda; hits.add(new EntityHit(entity, hitLambda)); } } } } //We hit something if(!hits.isEmpty()) { //Sort the hits according to the intercept position Collections.sort(hits); float swingDistance = dPos.length(); for(BulletHit bulletHit : hits) { if(bulletHit instanceof PlayerBulletHit) { PlayerBulletHit playerHit = (PlayerBulletHit)bulletHit; float damageMultiplier = 1F; switch(playerHit.hitbox.type) { case LEFTITEM : case RIGHTITEM : //Hit a shield. Stop the swing. { data.meleeProgress = data.meleeLength = 0; return; } case HEAD : damageMultiplier = 2F; break; case RIGHTARM : case LEFTARM : damageMultiplier = 0.6F; break; default : } if(playerHit.hitbox.player.attackEntityFrom(getMeleeDamage(player), swingDistance * type.meleeDamage)) { //If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless playerHit.hitbox.player.arrowHitTimer++; playerHit.hitbox.player.hurtResistantTime = playerHit.hitbox.player.maxHurtResistantTime / 2; } if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, new Vector3f(data.lastMeleePositions[k].x + dPos.x * playerHit.intersectTime, data.lastMeleePositions[k].y + dPos.y * playerHit.intersectTime, data.lastMeleePositions[k].z + dPos.z * playerHit.intersectTime), 1000, 1F, 0F, 0F)); } else if(bulletHit instanceof EntityHit) { EntityHit entityHit = (EntityHit)bulletHit; if(entityHit.entity.attackEntityFrom(DamageSource.causePlayerDamage(player), swingDistance * type.meleeDamage) && entityHit.entity instanceof EntityLivingBase) { EntityLivingBase living = (EntityLivingBase)entityHit.entity; //If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless living.arrowHitTimer++; living.hurtResistantTime = living.maxHurtResistantTime / 2; } if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, new Vector3f(data.lastMeleePositions[k].x + dPos.x * entityHit.intersectTime, data.lastMeleePositions[k].y + dPos.y * entityHit.intersectTime, data.lastMeleePositions[k].z + dPos.z * entityHit.intersectTime), 1000, 1F, 0F, 0F)); } } } } //End raytrace data.lastMeleePositions[k] = nextPosInWorldCoords; } //Increment the progress meter data.meleeProgress++; //If we are done, reset the counters if(data.meleeProgress == data.meleeLength) data.meleeProgress = data.meleeLength = 0; } } } * */ private boolean needsToReload(ItemStack stack) { for(int i = 0; i < type.numAmmoItemsInGun; i++) { ItemStack bulletStack = getBulletItemStack(stack, i); if(bulletStack != null && !bulletStack.isEmpty() && bulletStack.getItemDamage() < bulletStack.getMaxDamage()) { return false; } } return true; } public boolean CanReload(ItemStack gunstack, IInventory inventory) { for(int i = 0; i < inventory.getSizeInventory(); i++) { ItemStack stack = inventory.getStackInSlot(i); if(type.isCorrectAmmo(stack)) { return true; } } return false; } private ItemStack getBestNonEmptyShootableStack(ItemStack stack) { for(int i = 0; i < type.numAmmoItemsInGun; i++) { ItemStack shootableStack = getBulletItemStack(stack, i); if(shootableStack != null && !shootableStack.isEmpty() && shootableStack.getItemDamage() < shootableStack.getMaxDamage()) { return shootableStack; } } return null; } // _____________________________________________________________________________ // // Minecraft base item overrides // _____________________________________________________________________________ @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(stack.hasTagCompound() && stack.getTagCompound().hasKey("LegendaryCrafter")) { String crafter = stack.getTagCompound().getString("LegendaryCrafter"); lines.add("Legendary Skin Crafted by " + crafter); } if(type.description != null) { Collections.addAll(lines, type.description.split("_")); } if(type.showDamage) lines.add("\u00a79Damage" + "\u00a77: " + type.getDamage(stack)); if(type.showRecoil) lines.add("\u00a79Recoil" + "\u00a77: " + type.getRecoil(stack)); if(type.showSpread) lines.add("\u00a79Accuracy" + "\u00a77: " + type.getSpread(stack)); if(type.showReloadTime) lines.add("\u00a79Reload Time" + "\u00a77: " + type.getReloadTime(stack) / 20 + "s"); for(AttachmentType attachment : type.getCurrentAttachments(stack)) { if(type.showAttachments) { String line = attachment.name; lines.add(line); } } for(int i = 0; i < type.numAmmoItemsInGun; i++) { ItemStack bulletStack = getBulletItemStack(stack, i); if(bulletStack != null && bulletStack.getItem() instanceof ItemBullet) { BulletType bulletType = ((ItemBullet)bulletStack.getItem()).type; //String line = bulletType.name + (bulletStack.getMaxDamage() == 1 ? "" : " " + (bulletStack.getMaxDamage() - bulletStack.getItemDamage()) + "/" + bulletStack.getMaxDamage()); String line = bulletType.name + " " + (bulletStack.getMaxDamage() - bulletStack.getItemDamage()) + "/" + bulletStack.getMaxDamage(); lines.add(line); } } } @Override /** Make sure client and server side NBTtags update */ public boolean getShareTag() { return true; } public DamageSource getMeleeDamage(EntityPlayer attacker) { return new EntityDamageSourceFlan(type.shortName, attacker, attacker, type); } private boolean isSolid(World world, int i, int j, int k) { IBlockState state = world.getBlockState(new BlockPos(i, j, k)); return state.getMaterial().isSolid() && state.isOpaqueCube(); } //Stop damage being done to entities when scoping etc. @Override public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) { return type.secondaryFunction != EnumSecondaryFunction.MELEE; } @Override public boolean hasCustomEntity(ItemStack stack) { return true; } @Nullable @Override public Entity createEntity(World world, Entity location, ItemStack itemstack) { return new EntityItemCustomRender(location, itemstack); } @Override public boolean isFull3D() { return true; } @Override public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) { if(type.meleeSound != null) PacketPlaySound.sendSoundPacket(entityLiving.posX, entityLiving.posY, entityLiving.posZ, FlansMod.soundRange, entityLiving.dimension, type.meleeSound, true); //Do custom melee code here if(type.secondaryFunction == EnumSecondaryFunction.CUSTOM_MELEE) { //Do animation if(entityLiving.world.isRemote) { GunAnimations animations = FlansModClient.getGunAnimations(entityLiving, EnumHand.MAIN_HAND); animations.doMelee(type.meleeTime); } //Do custom melee hit detection if(entityLiving instanceof EntityPlayer) { PlayerData data = PlayerHandler.getPlayerData((EntityPlayer)entityLiving); data.doMelee((EntityPlayer)entityLiving, type.meleeTime, type); } } return type.secondaryFunction != EnumSecondaryFunction.MELEE; } @Override public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, EntityPlayer player) { World world = player.world; if(!world.isRemote) { // Client will still render block break if player is in creative so update block state IBlockState state = world.getBlockState(pos); world.notifyBlockUpdate(pos, state, state, 3); } return true; } @Override public boolean canHarvestBlock(IBlockState state, ItemStack stack) { return false; } public boolean isItemStackDamageable() { return true; } // ----------------- Paintjobs ----------------- @Override public void getSubItems(CreativeTabs tab, NonNullList items) { if(tab != FlansMod.tabFlanGuns && tab != CreativeTabs.SEARCH) return; PaintableType type = ((IPaintableItem)this).GetPaintableType(); if(FlansMod.addAllPaintjobsToCreative) { for(Paintjob paintjob : type.paintjobs) addPaintjobToList(this, type, paintjob, items); } else addPaintjobToList(this, type, type.defaultPaintjob, items); } private void addPaintjobToList(Item item, PaintableType type, Paintjob paintjob, List list) { ItemStack paintableStack = new ItemStack(item, 1, paintjob.ID); NBTTagCompound tags = new NBTTagCompound(); paintableStack.setTagCompound(tags); list.add(paintableStack); } // --------------------------------------------- @Override public int getMaxItemUseDuration(ItemStack par1ItemStack) { return 100; } @Override public EnumAction getItemUseAction(ItemStack par1ItemStack) { return EnumAction.BOW; } protected static final UUID KNOCKBACK_RESIST_MODIFIER = UUID.fromString("77777777-645C-4F38-A497-9C13A33DB5CF"); protected static final UUID MOVEMENT_SPEED_MODIFIER = UUID.fromString("99999999-4180-4865-B01B-BCCE9785ACA3"); @Override public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) { Multimap multimap = super.getAttributeModifiers(slot, stack); if(slot == EntityEquipmentSlot.MAINHAND) { multimap.put(SharedMonsterAttributes.KNOCKBACK_RESISTANCE.getName(), new AttributeModifier(KNOCKBACK_RESIST_MODIFIER, "KnockbackResist", type.knockbackModifier, 0)); multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "MovementSpeed", type.moveSpeedModifier - 1.0f, 2)); multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", type.meleeDamage, 0)); } return multimap; } @Override public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { return slotChanged; } // For when we have custom paintjob names @Override public String getTranslationKey(ItemStack stack) { return getTranslationKey(); //stack.getTagCompound().getString("Paint"); } @Override public boolean canItemEditBlocks() { return false; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ItemShootable.java ================================================ package com.flansmod.common.guns; import net.minecraft.item.Item; public abstract class ItemShootable extends Item { public ShootableType type; public ItemShootable(ShootableType t) { type = t; maxStackSize = type.maxStackSize; setRegistryName(type.shortName); setMaxDamage(type.roundsPerItem); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/Paintjob.java ================================================ package com.flansmod.common.guns; import java.util.HashMap; import net.minecraft.item.ItemStack; import com.flansmod.common.FlansMod; import com.flansmod.common.paintjob.PaintableType; import com.flansmod.common.types.EnumPaintjobRarity; public class Paintjob { private static HashMap paintjobs = new HashMap<>(); public PaintableType parent; public String iconName; public String textureName; public ItemStack[] dyesNeeded; public int ID; public EnumPaintjobRarity rarity; public Paintjob(PaintableType parent, int id, String iconName, String textureName, ItemStack[] dyesNeeded) { this.parent = parent; this.ID = id; this.iconName = iconName; this.textureName = textureName; this.dyesNeeded = dyesNeeded; this.rarity = EnumPaintjobRarity.UNKNOWN; paintjobs.put(hashCode(), this); } @Override public int hashCode() { return parent.hashCode() ^ ID; } public boolean IsLegendary() { for(ItemStack stack : dyesNeeded) { if(stack.getItem() == FlansMod.rainbowPaintcan) return true; } return false; } public static Paintjob GetPaintjob(int hash) { return paintjobs.get(hash); } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ShootBulletHandler.java ================================================ package com.flansmod.common.guns; /** * Functional interface to add effects when a bullet is fired. This is used to reduce the ammo, apply knockback, drop empty shells, etc. */ public interface ShootBulletHandler { /** * Static instance of ShootBulletHandler, does nothing */ public static ShootBulletHandler instance = isExtraBullet -> {}; /** * @param isExtraBullet is true whenever the current bullet is not the last one to be shot in this batch */ public void shooting(Boolean isExtraBullet); } ================================================ FILE: src/main/java/com/flansmod/common/guns/ShootableType.java ================================================ package com.flansmod.common.guns; import java.util.HashMap; import net.minecraft.client.model.ModelBase; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public abstract class ShootableType extends InfoType { //Aesthetics /** * The model to render for this grenade in the world */ @SideOnly(Side.CLIENT) public ModelBase model; /** * Whether trail particles are given off */ public boolean trailParticles = false; /** * Trail particles given off by this while being thrown */ public String trailParticleType = "smoke"; //Item Stuff /** * The maximum number of grenades that can be stacked together */ public int maxStackSize = 1; /** * Items dropped on various events */ public String dropItemOnReload = null, dropItemOnShoot = null, dropItemOnHit = null; /** * The number of rounds fired by a gun per item */ public int roundsPerItem = 1; /** * The number of bullet entities to create per round */ public int numBullets = 1; /** * Bullet spread multiplier to be applied to gun's bullet spread */ public float bulletSpread = 1F; //Physics and Stuff /** * The speed at which the grenade should fall */ public float fallSpeed = 1.0F; /** * The speed at which to throw the grenade. 0 will just drop it on the floor */ public float throwSpeed = 1.0F; /** * Hit box size */ public float hitBoxSize = 0.5F; //Damage to hit entities /** * Amount of damage to impart upon various entities */ public float damageVsLiving = 1, damageVsDriveable = 1; /** * Whether this grenade will break glass when thrown against it */ public boolean breaksGlass = false; //Detonation Conditions /** * If 0, then the grenade will last until some other detonation condition is met, else the grenade will detonate after this time (in ticks) */ public int fuse = 0; /** * After this time the grenade will despawn quietly. 0 means no despawn time */ public int despawnTime = 0; /** * If true, then this will explode upon hitting something */ public boolean explodeOnImpact = false; //Detonation Stuff /** * The radius in which to spread fire */ public float fireRadius = 0F; /** * The radius of explosion upon detonation */ public float explosionRadius = 0F; /** * Whether the explosion can destroy blocks */ public boolean explosionBreaksBlocks = true; /** * The name of the item to drop upon detonating */ public String dropItemOnDetonate = null; /** * Sound to play upon detonation */ public String detonateSound = ""; /** * The static list of all shootable types */ public static HashMap shootables = new HashMap<>(); public ShootableType(TypeFile file) { super(file); } @Override public void postRead(TypeFile file) { shootables.put(shortName.hashCode(), this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { //Model and Texture if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) model = FlansMod.proxy.loadModel(split[1], shortName, ModelBase.class); //Item Stuff else if(split[0].equals("StackSize") || split[0].equals("MaxStackSize")) maxStackSize = Integer.parseInt(split[1]); else if(split[0].equals("DropItemOnShoot")) dropItemOnShoot = split[1]; else if(split[0].equals("DropItemOnReload")) dropItemOnReload = split[1]; else if(split[0].equals("DropItemOnHit")) dropItemOnHit = split[1]; else if(split[0].equals("RoundsPerItem")) roundsPerItem = Integer.parseInt(split[1]); else if(split[0].equals("NumBullets")) numBullets = Integer.parseInt(split[1]); else if(split[0].equals("Accuracy") || split[0].equals("Spread")) bulletSpread = Float.parseFloat(split[1]); //Physics else if(split[0].equals("FallSpeed")) fallSpeed = Float.parseFloat(split[1]); else if(split[0].equals("ThrowSpeed") || split[0].equals("ShootSpeed")) throwSpeed = Float.parseFloat(split[1]); else if(split[0].equals("HitBoxSize")) hitBoxSize = Float.parseFloat(split[1]); //Hit stuff else if(split[0].equals("HitEntityDamage") || split[0].equals("DamageVsLiving") || split[0].equals("DamageVsPlayer")) damageVsLiving = Float.parseFloat(split[1]); else if(split[0].equals("DamageVsVehicles")) damageVsDriveable = Float.parseFloat(split[1]); else if(split[0].equals("Damage")) { damageVsLiving = damageVsDriveable = Float.parseFloat(split[1]); } else if(split[0].equals("BreaksGlass")) breaksGlass = Boolean.parseBoolean(split[1].toLowerCase()); //Detonation conditions etc else if(split[0].equals("Fuse")) fuse = Integer.parseInt(split[1]); else if(split[0].equals("DespawnTime")) despawnTime = Integer.parseInt(split[1]); else if(split[0].equals("ExplodeOnImpact") || split[0].equals("DetonateOnImpact")) explodeOnImpact = Boolean.parseBoolean(split[1].toLowerCase()); //Detonation else if(split[0].equals("FireRadius") || split[0].equals("Fire")) fireRadius = Float.parseFloat(split[1]); else if(split[0].equals("ExplosionRadius") || split[0].equals("Explosion")) explosionRadius = Float.parseFloat(split[1]); else if(split[0].equals("ExplosionBreaksBlocks")) explosionBreaksBlocks = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("DropItemOnDetonate")) dropItemOnDetonate = split[1]; else if(split[0].equals("DetonateSound")) { detonateSound = split[1]; FlansMod.proxy.loadSound(contentPack, shortName, split[1]); } //Particles else if(split[0].equals("TrailParticles") || split[0].equals("SmokeTrail")) trailParticles = Boolean.parseBoolean(split[1].toLowerCase()); else if(split[0].equals("TrailParticleType")) trailParticleType = split[1]; } catch(Exception e) { FlansMod.log.error("Reading grenade file failed: " + shortName); FlansMod.log.throwing(e); } } public static ShootableType getShootableType(String string) { return shootables.get(string.hashCode()); } public static ShootableType getShootableType(int hash) { return shootables.get(hash); } @Override protected void preRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/ShotHandler.java ================================================ package com.flansmod.common.guns; import static com.flansmod.common.util.BlockUtil.destroyBlock; import static com.flansmod.common.guns.raytracing.FlansModRaytracer.Raytrace; import java.util.List; import java.util.Optional; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.common.FlansMod; import com.flansmod.common.FlansModExplosion; import com.flansmod.common.guns.raytracing.FlansModRaytracer.BlockHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.BulletHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.DriveableHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.EntityHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.PlayerBulletHit; import com.flansmod.common.network.PacketBlockHitEffect; import com.flansmod.common.network.PacketBulletTrail; import com.flansmod.common.network.PacketFlak; import com.flansmod.common.network.PacketHitMarker; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.teams.TeamsRound; import com.flansmod.common.types.InfoType; import com.flansmod.common.vector.Vector3f; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.potion.PotionEffect; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraft.world.WorldServer; /** * Class containing a bunch of shooting related functions */ public class ShotHandler { /** * For any kind of shooting this method should be used. It handles everything including the differentiation between spawning a EntityBullet and performing a raytrace * * @param world World where the shot is fired * @param shot FiredShot object, created using the guidelines * @param bulletAmount Number how many bullets should be fired * @param rayTraceOrigin Origin of the bullet * @param shootingDirection Direction where the bullet will travel */ public static void fireGun(World world, FiredShot shot, Integer bulletAmount, Vector3f rayTraceOrigin, Vector3f shootingDirection) { fireGun(world, shot, bulletAmount, rayTraceOrigin, shootingDirection, ShootBulletHandler.instance); } /** * For any kind of shooting this method should be used. It handles everything including the differentiation between spawning a EntityBullet and performing a raytrace * * @param world World where the shot is fired * @param shot FiredShot object, created using the guidelines * @param bulletAmount Number how many bullets should be fired * @param rayTraceOrigin Origin of the bullet * @param shootingDirection Direction where the bullet will travel * @param handler ShootBulletHandler which is called every time a shot is fired (bulletAmount times) */ public static void fireGun(World world, FiredShot shot, Integer bulletAmount, Vector3f rayTraceOrigin, Vector3f shootingDirection, ShootBulletHandler handler) { if (shot.getFireableGun().getBulletSpeed() == 0f) { //Raytrace createMultipleShots(world, shot, bulletAmount, rayTraceOrigin, shootingDirection, handler); } else { //Spawn EntityBullet for(int i = 0; i < bulletAmount; i++) { world.spawnEntity(new EntityBullet(world, shot, rayTraceOrigin.toVec3(), shootingDirection.toVec3())); handler.shooting(i < bulletAmount - 1); } } } private static void createMultipleShots(World world, FiredShot shot, Integer bulletAmount, Vector3f rayTraceOrigin, Vector3f shootingDirection, ShootBulletHandler handler) { Float bulletspread = 0.0025f * shot.getFireableGun().getGunSpread() * shot.getBulletType().bulletSpread; for(int i = 0; i < bulletAmount; i++) { createShot(world, shot, bulletspread, rayTraceOrigin, new Vector3f(shootingDirection)); handler.shooting(i < bulletAmount - 1); } } private static void createShot(World world, FiredShot shot, Float bulletspread, Vector3f rayTraceOrigin, Vector3f shootingDirection) { randomizeVectorDirection(world, shootingDirection, bulletspread, shot.getFireableGun().getSpreadPattern()); shootingDirection.scale(500.0f); Float penetrationPower = shot.getBulletType().penetratingPower; //first tries to get the player because the players vehicle is also ignored, or get the player independent shooter or null Entity ignore = shot.getPlayerOptional().isPresent() ? shot.getPlayerOptional().get() : shot.getShooterOptional().orElse(null); List hits = Raytrace(world, ignore, false, null, rayTraceOrigin, shootingDirection, 0, penetrationPower); Vector3f previousHitPos = rayTraceOrigin; Vector3f finalhit = null; for (int i = 0;i { FlansMod.getPacketHandler().sendTo(new PacketHitMarker(), player); }); } else if(bulletHit instanceof PlayerBulletHit) { PlayerBulletHit playerHit = (PlayerBulletHit)bulletHit; penetratingPower = playerHit.hitbox.hitByBullet(shot, damage, penetratingPower); if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, hit, 1000, 1F, 0F, 0F)); Optional optionalPlayer = shot.getPlayerOptional(); // Check teams if (optionalPlayer.isPresent()) { EntityPlayerMP player = optionalPlayer.get(); TeamsRound round; if(TeamsManager.getInstance() != null && (round = TeamsManager.getInstance().currentRound) != null) { Optional shooterTeam = round.getTeam(player); Optional victimTeam = round.getTeam(playerHit.hitbox.player); if (!shooterTeam.isPresent() || !victimTeam.isPresent() || !shooterTeam.get().equals(victimTeam.get())) { FlansMod.getPacketHandler().sendTo(new PacketHitMarker(), player); } } else // No teams mod, just add marker { FlansMod.getPacketHandler().sendTo(new PacketHitMarker(), player); } } } else if(bulletHit instanceof EntityHit) { EntityHit entityHit = (EntityHit)bulletHit; if(entityHit.entity != null) { if(entityHit.entity.attackEntityFrom(shot.getDamageSource(), damage * bulletType.damageVsLiving) && entityHit.entity instanceof EntityLivingBase) { EntityLivingBase living = (EntityLivingBase)entityHit.entity; for(PotionEffect effect : bulletType.hitEffects) { living.addPotionEffect(new PotionEffect(effect)); } //If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless living.hurtResistantTime = 0; } if(bulletType.setEntitiesOnFire) entityHit.entity.setFire(20); penetratingPower -= 1F; if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, hit, 1000, 1F, 1F, 0F)); } //Send hit marker, if player is present shot.getPlayerOptional().ifPresent((EntityPlayerMP player) -> { FlansMod.getPacketHandler().sendTo(new PacketHitMarker(), player); }); } else if(bulletHit instanceof BlockHit) { BlockHit blockHit = (BlockHit)bulletHit; RayTraceResult raytraceResult = blockHit.getRayTraceResult(); //If the hit wasn't an entity hit, then it must've been a block hit BlockPos pos = raytraceResult.getBlockPos(); if(FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, hit, 1000, 0F, 1F, 0F)); Material mat = blockHit.getIBlockState().getMaterial(); //If the bullet breaks glass, and can do so according to FlansMod, do so. if(bulletType.breaksGlass && mat == Material.GLASS) { if(TeamsManager.canBreakGlass) { WorldServer worldServer = (WorldServer)world; destroyBlock(worldServer, pos, shot.getPlayerOptional().orElse(null), false); } } IBlockState state = blockHit.getIBlockState().getActualState(world, pos); penetratingPower -= getBlockPenetrationDecrease(state, pos, world); EnumFacing faceing = blockHit.getRayTraceResult().sideHit; Vector3f bulletDir = new Vector3f(shootingDirection); bulletDir.normalise(); bulletDir.scale(0.5f); for (EntityPlayer player : world.playerEntities) { //Checks if the player is in a radius of 300 Blocks (300 squared = 90000) if (player.getDistanceSq(pos) < 90000) { FlansMod.getPacketHandler().sendTo(new PacketBlockHitEffect(hit, bulletDir, pos, faceing), (EntityPlayerMP) player); } } //play sound when bullet hits block PacketPlaySound.sendSoundPacket(hit.x, hit.y, hit.z, bulletType.hitSoundRange, world.provider.getDimension(), bulletType.hitSound, false); //FlansMod.proxy.playBlockBreakSound(pos.getX(), pos.getY(), pos.getZ(), blockHit.getIBlockState().getBlock()); } if(penetratingPower <= 0F || (bulletType.explodeOnImpact //&& (bullet == null || bullet.ticksInAir > 1) )) { return -1f; } return penetratingPower; } /** * @param world World which contains the detonatePos * @param shot FiredShot instance of the shot * @param detonatePos Location where the detonation should happen */ public static void onDetonate(World world, FiredShot shot, Vector3f detonatePos) { BulletType bulletType = shot.getBulletType(); if(bulletType.explosionRadius > 0) { new FlansModExplosion(world, shot.getShooterOptional().orElse(null), shot.getPlayerOptional(), bulletType, detonatePos.x, detonatePos.y, detonatePos.z, bulletType.explosionRadius, bulletType.fireRadius > 0, bulletType.flak > 0, bulletType.explosionBreaksBlocks); } if(bulletType.fireRadius > 0) { for(float i = -bulletType.fireRadius; i < bulletType.fireRadius; i++) { for(float k = -bulletType.fireRadius; k < bulletType.fireRadius; k++) { for(int j = -1; j < 1; j++) { if(world.getBlockState(new BlockPos((int)(detonatePos.x + i), (int)(detonatePos.y + j), (int)(detonatePos.z + k))).getMaterial() == Material.AIR) { world.setBlockState(new BlockPos((int)(detonatePos.x + i), (int)(detonatePos.y + j), (int)(detonatePos.z + k)), Blocks.FIRE.getDefaultState(), 2); } } } } } // Send flak packet if(bulletType.flak > 0) { FlansMod.getPacketHandler().sendToAllAround(new PacketFlak(detonatePos.x, detonatePos.y, detonatePos.z, bulletType.flak, bulletType.flakParticles), detonatePos.x, detonatePos.y, detonatePos.z, 200, world.provider.getDimension()); } // Drop item on hitting if bullet requires it if(bulletType.dropItemOnHit != null) { //TODO save ItemStack on load into the bulletType ItemStack dropStack = InfoType.getRecipeElement(bulletType.dropItemOnHit); if(dropStack != null && !dropStack.isEmpty()) { EntityItem entityitem = new EntityItem(world, detonatePos.x, detonatePos.y, detonatePos.z, dropStack); entityitem.setDefaultPickupDelay(); world.spawnEntity(entityitem); } } } public static void randomizeVectorDirection(World world, Vector3f vector, Float spread, EnumSpreadPattern pattern) { Vector3f xAxis = Vector3f.cross(vector, new Vector3f(0f, 1f, 0f), null); xAxis.normalise(); Vector3f yAxis = Vector3f.cross(vector, xAxis, null); yAxis.normalise(); switch(pattern) { case circle: { float theta = (float)(world.rand.nextDouble() * Math.PI * 2.0f); float radius = (float)world.rand.nextDouble() * spread; float xComponent = radius * (float)Math.sin(theta); float yComponent = radius * (float)Math.cos(theta); xAxis.scale(xComponent); yAxis.scale(yComponent); Vector3f.add(vector, xAxis, vector); Vector3f.add(vector, yAxis, vector); break; } case cube: { vector.x += (float)world.rand.nextGaussian() * spread; vector.y += (float)world.rand.nextGaussian() * spread; vector.z += (float)world.rand.nextGaussian() * spread; break; } case horizontal: { float xComponent = spread * (world.rand.nextFloat() * 2f - 1f); xAxis.scale(xComponent); Vector3f.add(vector, xAxis, vector); break; } case vertical: { float yComponent = spread * (world.rand.nextFloat() * 2f - 1f); yAxis.scale(yComponent); Vector3f.add(vector, yAxis, vector); break; } case triangle: { // Random square, then fold the corners float xComponent = world.rand.nextFloat() * 2f - 1f; float yComponent = world.rand.nextFloat() * 2f - 1f; if(xComponent > 0f) { if(yComponent > 1.0f - xComponent * 2f) { yComponent = -yComponent; xComponent = 1f - xComponent; } } else { if(yComponent > xComponent * 2f + 1f) { yComponent = -yComponent; xComponent = -1f - xComponent; } } xComponent *= spread; yComponent *= spread; xAxis.scale(xComponent); yAxis.scale(yComponent); Vector3f.add(vector, xAxis, vector); Vector3f.add(vector, yAxis, vector); break; } default: break; } } public static float getBlockPenetrationDecrease(IBlockState blockstate, BlockPos pos, World world) { float hardness = blockstate.getBlockHardness(world, pos) * 2; if (hardness < 0) { return 1000; // Some high value for invincible blocks } else { return Math.max(hardness, 1); } } } ================================================ FILE: src/main/java/com/flansmod/common/guns/SlotGun.java ================================================ package com.flansmod.common.guns; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; public class SlotGun extends Slot { private int slotID; private SlotGun gunSlot; public SlotGun(IInventory inventory, int i, int x, int y, SlotGun s) { super(inventory, i, x, y); slotID = i; gunSlot = s; } public boolean isItemValid(ItemStack stack) { if(stack == null) return false; if(stack.isEmpty()) return true; switch(slotID) { case 0: return (stack.getItem() instanceof ItemGun && !((ItemGun)stack.getItem()).GetType().deployable && stack.getTagCompound() != null); case 1: return (canAttachToCurrentGun(stack) && ((ItemAttachment)stack.getItem()).type.type == EnumAttachmentType.barrel); case 2: return (canAttachToCurrentGun(stack) && ((ItemAttachment)stack.getItem()).type.type == EnumAttachmentType.sights); case 3: return (canAttachToCurrentGun(stack) && ((ItemAttachment)stack.getItem()).type.type == EnumAttachmentType.stock); case 4: return (canAttachToCurrentGun(stack) && ((ItemAttachment)stack.getItem()).type.type == EnumAttachmentType.grip); default: return (canAttachToCurrentGun(stack) && ((ItemAttachment)stack.getItem()).type.type == EnumAttachmentType.generic); } } public boolean canAttachToCurrentGun(ItemStack stack) { if(stack == null || !(stack.getItem() instanceof ItemAttachment) || !gunSlot.getHasStack() || !(gunSlot.getStack().getItem() instanceof ItemGun)) return false; AttachmentType attachmentType = ((ItemAttachment)stack.getItem()).type; GunType gunType = ((ItemGun)gunSlot.getStack().getItem()).GetType(); if(gunType.allowAllAttachments || gunType.allowedAttachments.contains(attachmentType)) { switch(attachmentType.type) { case barrel: return gunType.allowBarrelAttachments; case sights: return gunType.allowScopeAttachments; case stock: return gunType.allowStockAttachments; case grip: return gunType.allowGripAttachments; case generic: return slotID < 5 + gunType.numGenericAttachmentSlots; } } return false; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/boxes/BlockGunBox.java ================================================ package com.flansmod.common.guns.boxes; import java.util.ArrayList; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.boxes.GunBoxType.GunBoxEntry; import com.flansmod.common.types.InfoType; public class BlockGunBox extends Block { public GunBoxType type; public BlockGunBox(GunBoxType t) { super(Material.WOOD); setHardness(2F); setResistance(4F); type = t; setRegistryName(type.shortName); setTranslationKey(type.shortName); setCreativeTab(FlansMod.tabFlanGuns); type.block = this; } public void buyGun(InfoType gun, InventoryPlayer inventory, GunBoxType type) { //FlansMod.proxy.buyGun(type, gun); GunBoxEntry entry = type.canCraft(gun); if(entry != null) { boolean canBuy = true; for(ItemStack check : entry.requiredParts) { int numMatchingStuff = 0; for(int j = 0; j < inventory.getSizeInventory(); j++) { ItemStack stack = inventory.getStackInSlot(j); if(stack != null && !stack.isEmpty() && stack.getItem() == check.getItem() && stack.getItemDamage() == check.getItemDamage()) { numMatchingStuff += stack.getCount(); } } if(numMatchingStuff < check.getCount()) { canBuy = false; } } if(canBuy) { for(ItemStack remove : entry.requiredParts) { int amountLeft = remove.getCount(); for(int j = 0; j < inventory.getSizeInventory(); j++) { ItemStack stack = inventory.getStackInSlot(j); if(amountLeft > 0 && stack != null && !stack.isEmpty() && stack.getItem() == remove.getItem() && stack.getItemDamage() == remove.getItemDamage()) { amountLeft -= inventory.decrStackSize(j, amountLeft).getCount(); } } } ItemStack gunStack = new ItemStack(entry.type.item); if(entry.type instanceof GunType) { GunType gunType = (GunType)entry.type; NBTTagCompound tags = new NBTTagCompound(); tags.setString("Paint", gunType.defaultPaintjob.iconName); //Add ammo tags NBTTagList ammoTagsList = new NBTTagList(); for(int j = 0; j < gunType.numAmmoItemsInGun; j++) { ammoTagsList.appendTag(new NBTTagCompound()); } tags.setTag("ammo", ammoTagsList); gunStack.setTagCompound(tags); } if(!inventory.addItemStackToInventory(gunStack)) { // Drop gun on floor inventory.player.dropItem(gunStack, false); } } else { // Cant buy // TODO : Add flashing red squares around the items you lack } } } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float par7, float par8, float par9) { if(player.isSneaking()) return false; if(!world.isRemote) player.openGui(FlansMod.INSTANCE, 5, world, pos.getX(), pos.getY(), pos.getZ()); return true; } @Override public List getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { ArrayList ret = new ArrayList<>(); ret.add(new ItemStack(this, 1, 0)); return ret; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/boxes/BoxType.java ================================================ package com.flansmod.common.guns.boxes; import net.minecraft.client.model.ModelBase; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public abstract class BoxType extends InfoType { public String topTexturePath; public String sideTexturePath; public String bottomTexturePath; public BoxType(TypeFile file) { super(file); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { topTexturePath = Read(split, "TopTexture", topTexturePath); bottomTexturePath = Read(split, "BottomTexture", bottomTexturePath); sideTexturePath = Read(split, "SideTexture", sideTexturePath); } catch(Exception e) { FlansMod.log.error("Reading box file failed : " + shortName); FlansMod.log.throwing(e); } } @Override protected void preRead(TypeFile file) { } @Override protected void postRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return null; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/boxes/ContainerGunBox.java ================================================ package com.flansmod.common.guns.boxes; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; public class ContainerGunBox extends Container { public InventoryPlayer inventory; public ContainerGunBox(InventoryPlayer inventoryplayer) { inventory = inventoryplayer; //Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col + row * 9 + 9, 48 + col * 18, 177 + row * 18)); } } //Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(inventoryplayer, col, 48 + col * 18, 235)); } } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); if(slotID != 0) { if(!mergeItemStack(slotStack, 0, 1, false)) { return ItemStack.EMPTY.copy(); } } else { if(!mergeItemStack(slotStack, 1, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return null; } currentSlot.onTake(player, slotStack); } return stack; } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/boxes/GunBoxType.java ================================================ package com.flansmod.common.guns.boxes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import net.minecraft.block.Block; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraftforge.registries.IForgeRegistry; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class GunBoxType extends BoxType { public BlockGunBox block; /** * Stores pages for the gun box indexed by their title (unlocalized!) */ public HashMap pagesByTitle; public ArrayList pages; /** * Points to the page we are currently adding to. */ private GunBoxPage currentPage; public GunBoxPage defaultPage; private static int lastIconIndex = 2; public static HashMap gunBoxMap = new HashMap<>(); public GunBoxType(TypeFile file) { super(file); pagesByTitle = new HashMap<>(); pages = new ArrayList<>(); } @Override public void preRead(TypeFile file) { super.preRead(file); //Make sure NumGuns is read before anything else for(String line : file.getLines()) { if(line == null) break; if(line.startsWith("//")) continue; String[] split = line.split(" "); if(split.length < 2) continue; if(split[0].equals("NumGuns")) { pagesByTitle.put("default", currentPage = new GunBoxPage("default")); pages.add(currentPage); } } } @Override public void postRead(TypeFile file) { super.postRead(file); gunBoxMap.put(this.shortName, this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { //Sets the current page of the reader. if(split[0].equals("SetPage")) { String pageName = split[1]; for(int i = 2; i < split.length; i++) pageName += " " + split[i]; if(pagesByTitle.get(pageName) == null) pagesByTitle.put(pageName, currentPage = new GunBoxPage(pageName)); pages.add(currentPage); } //Add an info type at the top level. else if(split[0].equals("AddGun") || split[0].equals("AddType")) { currentPage.addNewEntry(InfoType.getType(split[1]), getRecipe(split)); } //Add a subtype (such as ammo) to the current top level InfoType else if(split[0].equals("AddAmmo") || split[0].equals("AddAltType") || split[0].equals("AddAltAmmo") || split[0].equals("AddAlternateAmmo")) { currentPage.addAmmoToCurrentEntry(InfoType.getType(split[1]), getRecipe(split)); } } catch(Exception e) { FlansMod.log.error("Reading gun box file failed : " + shortName); FlansMod.log.throwing(e); } } @Override public void registerItem(IForgeRegistry registry) { item = new ItemBlock(block).setRegistryName(shortName + "_item"); registry.register(item); } @Override public void registerBlock(IForgeRegistry registry) { registry.register(block); } private List getRecipe(String[] split) { List recipe = new ArrayList<>(); for(int i = 0; i < (split.length - 2) / 2; i++) { if(split[i * 2 + 3].contains(".")) recipe.add(getRecipeElement(split[i * 2 + 3].split("\\.")[0], Integer.parseInt(split[i * 2 + 2]), Integer.valueOf(split[i * 2 + 3].split("\\.")[1]))); else recipe.add(getRecipeElement(split[i * 2 + 3], Integer.parseInt(split[i * 2 + 2]), 0)); } return recipe; } public static GunBoxType getBox(String s) { return gunBoxMap.get(s); } public static GunBoxType getBox(Block block) { for(GunBoxType type : gunBoxMap.values()) { if(type.block == block) return type; } return null; } /* Reimported from old code @Override public void addRecipe(Item par1Item) { if (smeltableFrom != null) { GameRegistry.addSmelting(getRecipeElement(smeltableFrom, 0), new ItemStack(item), 0.0F); } if (recipeLine == null) return; try { if (!shapeless) { // Fix oversized recipes int rows = 3; // First column if (((String) recipe[0]).charAt(0) == ' ' && ((String) recipe[1]).charAt(0) == ' ' && ((String) recipe[2]).charAt(0) == ' ') { for (int i = 0; i < 3; i++) recipe[i] = ((String) recipe[i]).substring(1); // New first column if (((String) recipe[0]).charAt(0) == ' ' && ((String) recipe[1]).charAt(0) == ' ' && ((String) recipe[2]).charAt(0) == ' ') { for (int i = 0; i < 3; i++) recipe[i] = ((String) recipe[i]).substring(1); } } // Last column int last = ((String) recipe[0]).length() - 1; if (((String) recipe[0]).charAt(last) == ' ' && ((String) recipe[1]).charAt(last) == ' ' && ((String) recipe[2]).charAt(last) == ' ') { for (int i = 0; i < 3; i++) recipe[i] = ((String) recipe[i]).substring(0, last); // New last column last--; if (((String) recipe[0]).charAt(last) == ' ' && ((String) recipe[1]).charAt(last) == ' ' && ((String) recipe[2]).charAt(last) == ' ') { for (int i = 0; i < 3; i++) recipe[i] = ((String) recipe[i]).substring(0, 0); } } // Top row if (recipe[0].equals(" ") || recipe[0].equals(" ") || recipe[0].equals(" ")) { Object[] newRecipe = new Object[recipe.length - 1]; newRecipe[0] = recipe[1]; newRecipe[1] = recipe[2]; recipe = newRecipe; rows--; // Next top row if (recipe[0].equals(" ") || recipe[0].equals(" ") || recipe[0].equals(" ")) { Object[] newRecipe1 = new Object[recipe.length - 1]; newRecipe1[0] = recipe[1]; recipe = newRecipe1; rows--; } } // Bottom row if (recipe[rows - 1].equals(" ") || recipe[rows - 1].equals(" ") || recipe[rows - 1].equals(" ")) { Object[] newRecipe = new Object[recipe.length - 1]; newRecipe[0] = recipe[0]; newRecipe[1] = recipe[1]; recipe = newRecipe; rows--; // Next bottom row if (recipe[rows - 1].equals(" ") || recipe[rows - 1].equals(" ") || recipe[rows - 1].equals(" ")) { Object[] newRecipe1 = new Object[recipe.length - 1]; newRecipe1[0] = recipe[0]; recipe = newRecipe1; rows--; } } for (int i = 0; i < (recipeLine.length - 1) / 2; i++) { recipe[i * 2 + rows] = recipeLine[i * 2 + 1].charAt(0); // Split ID with . and if it contains a second part, use it // as damage value. if (recipeLine[i * 2 + 2].contains(".")) recipe[i * 2 + rows + 1] = getRecipeElement(recipeLine[i * 2 + 2].split("\\.")[0], Integer.valueOf(recipeLine[i * 2 + 2].split("\\.")[1])); else recipe[i * 2 + rows + 1] = getRecipeElement(recipeLine[i * 2 + 2], 0); } GameRegistry.addRecipe(new ItemStack(block, recipeOutput, 0), recipe); } else { recipe = new Object[recipeLine.length - 1]; for (int i = 0; i < (recipeLine.length - 1); i++) { if (recipeLine[i + 1].contains(".")) recipe[i] = getRecipeElement(recipeLine[i + 1].split("\\.")[0], Integer.valueOf(recipeLine[i + 1].split("\\.")[1])); else recipe[i] = getRecipeElement(recipeLine[i + 1], 0); } GameRegistry.addShapelessRecipe(new ItemStack(block, recipeOutput, 0), recipe); } } catch (Exception e) { FlansMod.log("Failed to add recipe for : " + shortName); FlansMod.log.throwing(e); } } */ /** * Represents a page in the gun box */ public static class GunBoxPage { public List entries; /** * Points to the gun box entry we are currently reading from file. Allows for the old format to write in ammo on a separate line to the gun. */ private GunBoxEntryTopLevel currentlyEditing; public String name; public GunBoxPage(String s) { name = s; entries = new ArrayList<>(); } public void addNewEntry(InfoType type, List requiredParts) { GunBoxEntryTopLevel entry = new GunBoxEntryTopLevel(type, requiredParts); entries.add(entry); currentlyEditing = entry; } public void addAmmoToCurrentEntry(InfoType type, List requiredParts) { currentlyEditing.addAmmo(type, requiredParts); } } /** * Represents an entry on a page of the gun box. */ public static class GunBoxEntry { public InfoType type; public List requiredParts; public GunBoxEntry(InfoType type, List requiredParts) { this.type = type; this.requiredParts = requiredParts; } public boolean haveEnoughOf(InventoryPlayer inv, ItemStack stackNeeded) { //Create a temporary copy of the player inventory for backup purposes InventoryPlayer temporaryInventory = new InventoryPlayer(null); for(int i = 0; i < inv.getSizeInventory(); i++) { temporaryInventory.setInventorySlotContents(i, inv.getStackInSlot(i).copy()); } return haveEnoughOf(temporaryInventory, stackNeeded, false); } private boolean haveEnoughOf(InventoryPlayer temporaryInventory, ItemStack stackNeeded, boolean takeItems) { //The total amount of items found that match this recipe stack int totalAmountFound = 0; //Iterate over the temporary inventory for(int m = 0; m < temporaryInventory.getSizeInventory(); m++) { //Get the stack in each slot ItemStack stackInSlot = temporaryInventory.getStackInSlot(m).copy(); //If the stack is what we want if(stackInSlot.getItem() == stackNeeded.getItem() && stackInSlot.getItemDamage() == stackNeeded.getItemDamage()) { //Work out the amount to take from the stack int amountFound = Math.min(stackInSlot.getCount(), stackNeeded.getCount() - totalAmountFound); //Take it stackInSlot.setCount(stackInSlot.getCount() - amountFound); //Check for empty stacks if(stackInSlot.getCount() <= 0) stackInSlot = ItemStack.EMPTY.copy(); //Put the modified stack back in the inventory temporaryInventory.setInventorySlotContents(m, stackInSlot); //Increase the amount found counter totalAmountFound += amountFound; //If we have enough, stop looking if(totalAmountFound == stackNeeded.getCount()) break; } } return totalAmountFound >= stackNeeded.getCount(); } public boolean canCraft(InventoryPlayer inv, boolean takeItems) { //Create a temporary copy of the player inventory for backup purposes InventoryPlayer temporaryInventory = new InventoryPlayer(null); for(int i = 0; i < inv.getSizeInventory(); i++) { temporaryInventory.setInventorySlotContents(i, inv.getStackInSlot(i).copy()); } //This becomes false if some recipe element is not found on the player boolean canCraft = true; //Draw the stacks that should be in each slot for(ItemStack stackNeeded : requiredParts) { if(!haveEnoughOf(temporaryInventory, stackNeeded, takeItems)) { canCraft = false; break; } } if(canCraft && takeItems) { inv.copyInventory(temporaryInventory); } return canCraft; } } /** * Represents a top level entry, normally a gun. This has child entries, normally ammo that are listed below in the GUI. */ public static class GunBoxEntryTopLevel extends GunBoxEntry { public List childEntries; public GunBoxEntryTopLevel(InfoType type, List requiredParts) { super(type, requiredParts); childEntries = new ArrayList<>(); } public void addAmmo(InfoType type, List requiredParts) { childEntries.add(new GunBoxEntry(type, requiredParts)); } } public GunBoxEntry canCraft(InfoType type) { for(GunBoxPage page : pagesByTitle.values()) { for(GunBoxEntryTopLevel entry : page.entries) { if(entry.type == type) return entry; else { for(GunBoxEntry child : entry.childEntries) { if(child.type == type) return child; } } } } return null; } } ================================================ FILE: src/main/java/com/flansmod/common/guns/raytracing/EnumHitboxType.java ================================================ package com.flansmod.common.guns.raytracing; public enum EnumHitboxType { BODY, HEAD, LEFTARM, RIGHTARM, LEFTITEM, RIGHTITEM } ================================================ FILE: src/main/java/com/flansmod/common/guns/raytracing/FlansModRaytracer.java ================================================ package com.flansmod.common.guns.raytracing; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EnumDriveablePart; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.EntityAAGun; import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.ShotHandler; import com.flansmod.common.teams.Team; import com.flansmod.common.vector.Vector3f; public class FlansModRaytracer { public static List Raytrace(World world, Entity playerToIgnore, boolean canHitSelf, Entity entityToIgnore, Vector3f origin, Vector3f motion, int pingOfShooter, Float gunPenetration) { //Create a list for all bullet hits List hits = new ArrayList<>(); float speed = motion.length(); //Iterate over all entities for(int i = 0; i < world.loadedEntityList.size(); i++) { Entity obj = world.loadedEntityList.get(i); boolean shouldDoNormalHitDetect = true; //Get driveables if(obj instanceof EntityDriveable) { EntityDriveable driveable = (EntityDriveable)obj; shouldDoNormalHitDetect = false; if(driveable.isDead() || driveable.isPartOfThis(playerToIgnore)) continue; //If this bullet is within the driveable's detection range if(driveable.getDistanceSq(origin.x, origin.y, origin.z) <= (driveable.getDriveableType().bulletDetectionRadius + speed) * (driveable.getDriveableType().bulletDetectionRadius + speed)) { //Raytrace the bullet ArrayList driveableHits = driveable.attackFromBullet(origin, motion); hits.addAll(driveableHits); } } //Get players else if(obj instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer)obj; PlayerData data = PlayerHandler.getPlayerData(player); shouldDoNormalHitDetect = false; if(data != null) { if(player.isDead || data.team == Team.spectators) { continue; } if(player == playerToIgnore && !canHitSelf) continue; int snapshotToTry = pingOfShooter / 50; if(snapshotToTry >= data.snapshots.length) snapshotToTry = data.snapshots.length - 1; PlayerSnapshot snapshot = data.snapshots[snapshotToTry]; if(snapshot == null) snapshot = data.snapshots[0]; //DEBUG //snapshot = new PlayerSnapshot(player); //Check one last time for a null snapshot. If this is the case, fall back to normal hit detection if(snapshot == null) shouldDoNormalHitDetect = true; else { //Raytrace ArrayList playerHits = snapshot.raytrace(origin, motion); hits.addAll(playerHits); } } } if(shouldDoNormalHitDetect) { Entity entity = obj; if(entity != entityToIgnore && entity != playerToIgnore && !entity.isDead && (entity instanceof EntityLivingBase || entity instanceof EntityAAGun || entity instanceof EntityGrenade)) { RayTraceResult mop = entity.getEntityBoundingBox().calculateIntercept(origin.toVec3(), new Vec3d(origin.x + motion.x, origin.y + motion.y, origin.z + motion.z)); if(mop != null) { Entity[] parts = entity.getParts(); boolean hit = true; // If parts exist, the intercepted part is calculated and used instead of the whole entity. // If no part is intercepted, the entity itself is not hit if(parts != null) { hit = false; for(Entity part : parts) { RayTraceResult result = part.getEntityBoundingBox().calculateIntercept(origin.toVec3(), new Vec3d(origin.x + motion.x, origin.y + motion.y, origin.z + motion.z)); if(result != null) { mop = result; entity = part; hit = true; break; } } } if(hit) { Vec3d hitPoint = new Vec3d(mop.hitVec.x - origin.x, mop.hitVec.y - origin.y, mop.hitVec.z - origin.z); if (FlansMod.DEBUG) world.spawnEntity(new EntityDebugDot(world, new Vector3f(mop.hitVec), 1000, 1.0f, 0f, 0f)); float hitLambda = 1F; if(motion.x != 0F) hitLambda = (float) (hitPoint.x / motion.x); else if(motion.y != 0F) hitLambda = (float) (hitPoint.y / motion.y); else if(motion.z != 0F) hitLambda = (float) (hitPoint.z / motion.z); if(hitLambda < 0) hitLambda = -hitLambda; hits.add(new EntityHit(entity, hitLambda)); //raytraceBlock(world, mop.hitVec, motion, hits); } } } } } Vec3d mot = new Vector3f(motion).toVec3(); mot = mot.normalize(); mot = mot.scale(0.5d); hits = raytraceBlock(world, origin.toVec3(), new Vec3d(0, 0, 0), motion, mot, hits, gunPenetration, null); //We hit something if(!hits.isEmpty()) { //Sort the hits according to the intercept position Collections.sort(hits); } return hits; } private static List raytraceBlock( World world, Vec3d posVec, Vec3d previousHit, Vector3f motion, Vec3d normalized_motion, List hits, Float penetration, BlockPos oldPos) { //Ray trace the bullet by comparing its next position to its current position Vec3d nextPosVec = new Vec3d(posVec.x + motion.x, posVec.y + motion.y, posVec.z + motion.z); RayTraceResult hit = world.rayTraceBlocks(posVec, nextPosVec, false, true, true); if(hit != null) { Vec3d hitVec = hit.hitVec.subtract(posVec); hitVec = hitVec.add(previousHit); BlockPos pos = hit.getBlockPos(); IBlockState blockState = world.getBlockState(hit.getBlockPos()); if (!pos.equals(oldPos)) { //Calculate the lambda value of the intercept float lambda = 1; //Try each co-ordinate one at a time. if(motion.x != 0) lambda = (float)(hitVec.x / motion.x); else if(motion.y != 0) lambda = (float)(hitVec.y / motion.y); else if(motion.z != 0) lambda = (float)(hitVec.z / motion.z); if(lambda < 0) lambda = -lambda; hits.add(new BlockHit(hit, lambda, blockState)); penetration -= ShotHandler.getBlockPenetrationDecrease(blockState, pos, world); } if (penetration > 0) { hits = raytraceBlock( world, hit.hitVec.add(normalized_motion), hitVec.add(normalized_motion), motion, normalized_motion, hits, penetration, pos); } } return hits; } public static Vector3f GetPlayerMuzzlePosition(EntityPlayer player, EnumHand hand) { PlayerSnapshot snapshot = new PlayerSnapshot(player); ItemStack itemstack = hand == EnumHand.OFF_HAND ? player.getHeldItemOffhand() : player.getHeldItemMainhand(); if(itemstack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)itemstack.getItem()).GetType(); AttachmentType barrelType = gunType.getBarrel(itemstack); return Vector3f.add(new Vector3f(player.posX, player.posY, player.posZ), snapshot.GetMuzzleLocation(gunType, barrelType, hand), null); } return new Vector3f(player.getPositionEyes(0.0f)); } public static abstract class BulletHit implements Comparable { /** * The time along the ray that the intersection happened. Between 0 and 1 */ public float intersectTime; public BulletHit(float f) { intersectTime = f; } @Override public int compareTo(BulletHit other) { if(intersectTime < other.intersectTime) return -1; else if(intersectTime > other.intersectTime) return 1; return 0; } public abstract Entity GetEntity(); } public static class BlockHit extends BulletHit { private RayTraceResult raytraceResult; private IBlockState blockstate; public BlockHit(RayTraceResult mop, Float f, IBlockState blockstate) { super(f); raytraceResult = mop; this.blockstate = blockstate; } @Override public Entity GetEntity() { return null; } public IBlockState getIBlockState() { return blockstate; } public RayTraceResult getRayTraceResult() { return raytraceResult; } } public static class EntityHit extends BulletHit { public Entity entity; public EntityHit(Entity e, float f) { super(f); entity = e; } @Override public Entity GetEntity() { return entity; } } public static class DriveableHit extends BulletHit { public EntityDriveable driveable; public EnumDriveablePart part; public DriveableHit(EntityDriveable d, EnumDriveablePart p, float f) { super(f); part = p; driveable = d; } @Override public Entity GetEntity() { return driveable; } } /** * Raytracing will return a load of these objects containing hit data. These will then be compared against each other and against any block hits * The hit that occurs first along the path of the bullet is the one that is acted upon. Unless the bullet has penetration of course */ public static class PlayerBulletHit extends BulletHit { /** * The hitbox hit */ public PlayerHitbox hitbox; public PlayerBulletHit(PlayerHitbox box, float f) { super(f); hitbox = box; } @Override public Entity GetEntity() { return hitbox.player; } } } ================================================ FILE: src/main/java/com/flansmod/common/guns/raytracing/PlayerHitbox.java ================================================ package com.flansmod.common.guns.raytracing; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.debug.EntityDebugDot; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.guns.BulletType; import com.flansmod.common.guns.FiredShot; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.raytracing.FlansModRaytracer.PlayerBulletHit; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.vector.Vector3f; public class PlayerHitbox { /** */ public EntityPlayer player; /** * The angles of this box */ public RotatedAxes axes; /** * The origin of rotation for this box */ public Vector3f rP; /** * The lower left corner of this box */ public Vector3f o; /** * The dimensions of this box */ public Vector3f d; /** * The type of hitbox */ public EnumHitboxType type; public PlayerHitbox(EntityPlayer player, RotatedAxes axes, Vector3f rotationPoint, Vector3f origin, Vector3f dimensions, EnumHitboxType type) { this.player = player; this.axes = axes; this.o = origin; this.d = dimensions; this.type = type; this.rP = rotationPoint; } @SideOnly(Side.CLIENT) public void renderHitbox(World world, Vector3f pos) { //Vector3f boxOrigin = new Vector3f(pos.x + rP.x, pos.y + rP.y, pos.z + rP.z); //world.spawnEntity(new EntityDebugAABB(world, boxOrigin, d, 2, 1F, 1F, 0F, axes.getYaw(), axes.getPitch(), axes.getRoll(), o)); if(type != EnumHitboxType.RIGHTARM) return; for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 3; k++) { Vector3f point = new Vector3f(o.x + d.x * i / 2, o.y + d.y * j / 2, o.z + d.z * k / 2); point = axes.findLocalVectorGlobally(point); if(FlansMod.DEBUG && world.isRemote) world.spawnEntity(new EntityDebugDot(world, new Vector3f(pos.x + rP.x + point.x, pos.y + rP.y + point.y, pos.z + rP.z + point.z), 1, 0F, 1F, 0F)); } } public PlayerBulletHit raytrace(Vector3f origin, Vector3f motion) { //Move to local coords for this hitbox, but don't modify the original "origin" vector origin = Vector3f.sub(origin, rP, null); origin = axes.findGlobalVectorLocally(origin); motion = axes.findGlobalVectorLocally(motion); //We now have an AABB starting at o and with dimensions d and our ray in the same coordinate system //We are looking for a point at which the ray enters the box, so we need only consider faces that the ray can see. Partition the space into 3 areas in each axis //X - axis and faces x = o.x and x = o.x + d.x if(motion.x != 0F) { if(origin.x < o.x) //Check face x = o.x { float intersectTime = (o.x - origin.x) / motion.x; float intersectY = origin.y + motion.y * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectY >= o.y && intersectY <= o.y + d.y && intersectZ >= o.z && intersectZ <= o.z + d.z) return new PlayerBulletHit(this, intersectTime); } else if(origin.x > o.x + d.x) //Check face x = o.x + d.x { float intersectTime = (o.x + d.x - origin.x) / motion.x; float intersectY = origin.y + motion.y * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectY >= o.y && intersectY <= o.y + d.y && intersectZ >= o.z && intersectZ <= o.z + d.z) return new PlayerBulletHit(this, intersectTime); } } //Z - axis and faces z = o.z and z = o.z + d.z if(motion.z != 0F) { if(origin.z < o.z) //Check face z = o.z { float intersectTime = (o.z - origin.z) / motion.z; float intersectX = origin.x + motion.x * intersectTime; float intersectY = origin.y + motion.y * intersectTime; if(intersectX >= o.x && intersectX <= o.x + d.x && intersectY >= o.y && intersectY <= o.y + d.y) return new PlayerBulletHit(this, intersectTime); } else if(origin.z > o.z + d.z) //Check face z = o.z + d.z { float intersectTime = (o.z + d.z - origin.z) / motion.z; float intersectX = origin.x + motion.x * intersectTime; float intersectY = origin.y + motion.y * intersectTime; if(intersectX >= o.x && intersectX <= o.x + d.x && intersectY >= o.y && intersectY <= o.y + d.y) return new PlayerBulletHit(this, intersectTime); } } //Y - axis and faces y = o.y and y = o.y + d.y if(motion.y != 0F) { if(origin.y < o.y) //Check face y = o.y { float intersectTime = (o.y - origin.y) / motion.y; float intersectX = origin.x + motion.x * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectX >= o.x && intersectX <= o.x + d.x && intersectZ >= o.z && intersectZ <= o.z + d.z) return new PlayerBulletHit(this, intersectTime); } else if(origin.y > o.y + d.y) //Check face x = o.x + d.x { float intersectTime = (o.y + d.y - origin.y) / motion.y; float intersectX = origin.x + motion.x * intersectTime; float intersectZ = origin.z + motion.z * intersectTime; if(intersectX >= o.x && intersectX <= o.x + d.x && intersectZ >= o.z && intersectZ <= o.z + d.z) return new PlayerBulletHit(this, intersectTime); } } return null; } public float hitByBullet(FiredShot shot, Float damage, Float penetratingPower) { BulletType bulletType = shot.getBulletType(); if(bulletType.setEntitiesOnFire) player.setFire(20); for(PotionEffect effect : bulletType.hitEffects) { player.addPotionEffect(new PotionEffect(effect)); } float damageModifier = bulletType.penetratingPower < 0.1F ? penetratingPower / bulletType.penetratingPower : 1; switch(type) { case BODY: break; case HEAD: damageModifier *= 1.6F; break; case LEFTARM: damageModifier *= 0.6F; break; case RIGHTARM: damageModifier *= 0.6F; break; case LEFTITEM: break; case RIGHTITEM: break; default: break; } switch(type) { case BODY: case HEAD: case LEFTARM: case RIGHTARM: { //Calculate the hit damage float hitDamage = damage * shot.getBulletType().damageVsLiving * damageModifier; //Create a damage source object DamageSource damagesource = shot.getDamageSource(type.equals(EnumHitboxType.HEAD)); //When the damage is 0 (such as with Nerf guns) the entityHurt Forge hook is not called, so this hacky thing is here if(!player.world.isRemote && hitDamage == 0 && TeamsManager.getInstance().currentRound != null) TeamsManager.getInstance().currentRound.gametype.playerAttacked((EntityPlayerMP)player, damagesource); //if(damagesource.) //Attack the entity! if(player.attackEntityFrom(damagesource, hitDamage)) { //If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless player.arrowHitTimer++; player.hurtResistantTime = player.maxHurtResistantTime / 2; //Yuck. //PacketDispatcher.sendPacketToAllAround(posX, posY, posZ, 50, dimension, PacketPlaySound.buildSoundPacket(posX, posY, posZ, type.hitSound, true)); } return penetratingPower - 1; } case RIGHTITEM: { ItemStack currentStack = player.getHeldItemMainhand(); if(currentStack != null && currentStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)currentStack.getItem()).GetType(); //TODO : Shield damage return penetratingPower - gunType.shieldDamageAbsorption; } else return penetratingPower; } case LEFTITEM: { ItemStack currentStack = player.getHeldItemOffhand(); if(currentStack != null && currentStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)currentStack.getItem()).GetType(); //TODO : Shield damage return penetratingPower - gunType.shieldDamageAbsorption; } else return penetratingPower; } default: return penetratingPower; } } } ================================================ FILE: src/main/java/com/flansmod/common/guns/raytracing/PlayerSnapshot.java ================================================ package com.flansmod.common.guns.raytracing; import java.util.ArrayList; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.RotatedAxes; import com.flansmod.common.guns.AttachmentType; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; import com.flansmod.common.guns.raytracing.FlansModRaytracer.BulletHit; import com.flansmod.common.guns.raytracing.FlansModRaytracer.PlayerBulletHit; import com.flansmod.common.vector.Vector3f; /** * This class takes a snapshot of the player's position rotation and held items at a certain point in time. * It is used to handle bullet detection. The server will store a second or two of snapshots so that it * can work out where the player thought they were shooting accounting for packet lag */ public class PlayerSnapshot { /** * The player this snapshot is for */ public EntityPlayer player; /** * The player's position at the point the snapshot was taken */ public Vector3f pos; /** * The hitboxes for this player */ public ArrayList hitboxes; /** * The time at which this snapshot was taken */ public long time; public PlayerSnapshot(EntityPlayer p) { player = p; pos = new Vector3f(p.posX, p.posY, p.posZ); //if(FlansMod.proxy.isThePlayer(p)) // pos = new Vector3f(p.posX, p.posY - 1.6F, p.posZ); hitboxes = new ArrayList<>(); RotatedAxes bodyAxes = new RotatedAxes(p.renderYawOffset, 0F, 0F); RotatedAxes headAxes = new RotatedAxes(p.rotationYawHead - p.renderYawOffset, p.rotationPitch, 0F); hitboxes.add(new PlayerHitbox(player, bodyAxes, new Vector3f(0F, 0F, 0F), new Vector3f(-0.25F, 0F, -0.15F), new Vector3f(0.5F, 1.4F, 0.3F), EnumHitboxType.BODY)); hitboxes.add(new PlayerHitbox(player, bodyAxes.findLocalAxesGlobally(headAxes), new Vector3f(0.0F, 1.4F, 0F), new Vector3f(-0.25F, 0F, -0.25F), new Vector3f(0.5F, 0.5F, 0.5F), EnumHitboxType.HEAD)); //Calculate rotation of arms using modified code from ModelBiped float yHead = (p.rotationYawHead - p.renderYawOffset) / (180F / (float)Math.PI); float xHead = p.rotationPitch / (180F / (float)Math.PI); float zRight = 0.0F; float zLeft = 0.0F; float yRight = -0.1F + yHead - ((float)Math.PI / 2F); float yLeft = 0.1F + yHead + 0.4F - ((float)Math.PI / 2F); float xRight = -((float)Math.PI / 2F) + xHead; float xLeft = -((float)Math.PI / 2F) + xHead; zRight += MathHelper.cos(p.ticksExisted * 0.09F) * 0.05F + 0.05F; zLeft -= MathHelper.cos(p.ticksExisted * 0.09F) * 0.05F + 0.05F; xRight += MathHelper.sin(p.ticksExisted * 0.067F) * 0.05F; xLeft -= MathHelper.sin(p.ticksExisted * 0.067F) * 0.05F; RotatedAxes leftArmAxes = (new RotatedAxes()).rotateGlobalPitchInRads(xLeft).rotateGlobalYawInRads((float)Math.PI + yLeft).rotateGlobalRollInRads(-zLeft); RotatedAxes rightArmAxes = (new RotatedAxes()).rotateGlobalPitchInRads(xRight).rotateGlobalYawInRads((float)Math.PI + yRight).rotateGlobalRollInRads(-zRight); float originZRight = MathHelper.sin(-p.renderYawOffset * 3.14159265F / 180F) * 5.0F / 16F; float originXRight = -MathHelper.cos(-p.renderYawOffset * 3.14159265F / 180F) * 5.0F / 16F; float originZLeft = -MathHelper.sin(-p.renderYawOffset * 3.14159265F / 180F) * 5.0F / 16F; float originXLeft = MathHelper.cos(-p.renderYawOffset * 3.14159265F / 180F) * 5.0F / 16F; hitboxes.add(new PlayerHitbox(player, bodyAxes.findLocalAxesGlobally(leftArmAxes), new Vector3f(originXLeft, 1.3F, originZLeft), new Vector3f(-2F / 16F, -0.6F, -2F / 16F), new Vector3f(0.25F, 0.7F, 0.25F), EnumHitboxType.LEFTARM)); hitboxes.add(new PlayerHitbox(player, bodyAxes.findLocalAxesGlobally(rightArmAxes), new Vector3f(originXRight, 1.3F, originZRight), new Vector3f(-2F / 16F, -0.6F, -2F / 16F), new Vector3f(0.25F, 0.7F, 0.25F), EnumHitboxType.RIGHTARM)); //Add box for right hand shield ItemStack playerRightHandStack = player.getHeldItemMainhand(); if(playerRightHandStack != null && playerRightHandStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)playerRightHandStack.getItem()).GetType(); if(gunType.shield) { hitboxes.add(new PlayerHitbox(player, bodyAxes.findLocalAxesGlobally(rightArmAxes), new Vector3f(originXRight, 1.3F, originZRight), new Vector3f(gunType.shieldOrigin.y, -1.05F + gunType.shieldOrigin.x, -1F / 16F + gunType.shieldOrigin.z), new Vector3f(gunType.shieldDimensions.y, gunType.shieldDimensions.x, gunType.shieldDimensions.z), EnumHitboxType.RIGHTITEM)); } } ItemStack playerLeftHandStack = player.getHeldItemOffhand(); if(playerLeftHandStack != null && playerLeftHandStack.getItem() instanceof ItemGun) { GunType gunType = ((ItemGun)playerLeftHandStack.getItem()).GetType(); if(gunType.shield) { hitboxes.add(new PlayerHitbox(player, bodyAxes.findLocalAxesGlobally(rightArmAxes), new Vector3f(originXRight, 1.3F, originZRight), new Vector3f(gunType.shieldOrigin.y, -1.05F + gunType.shieldOrigin.x, -1F / 16F + gunType.shieldOrigin.z), new Vector3f(gunType.shieldDimensions.y, gunType.shieldDimensions.x, gunType.shieldDimensions.z), EnumHitboxType.RIGHTITEM)); } } } public ArrayList raytrace(Vector3f origin, Vector3f motion) { //Get the bullet raytrace vector into local coordinates Vector3f localOrigin = Vector3f.sub(origin, pos, null); //Prepare a list for the hits ArrayList hits = new ArrayList<>(); //Check each hitbox for a hit for(PlayerHitbox hitbox : hitboxes) { PlayerBulletHit hit = hitbox.raytrace(localOrigin, motion); if(hit != null && hit.intersectTime >= 0F && hit.intersectTime <= 1F) { hits.add(hit); } } return hits; } @SideOnly(Side.CLIENT) public void renderSnapshot() { for(PlayerHitbox hitbox : hitboxes) { hitbox.renderHitbox(player.world, pos); } } public PlayerHitbox GetHitbox(EnumHitboxType type) { for(PlayerHitbox hitbox : hitboxes) { if(hitbox.type == type) { return hitbox; } } return null; } public Vector3f GetMuzzleLocation(GunType gunType, AttachmentType barrelAttachment, EnumHand hand) { PlayerHitbox hitbox = GetHitbox(hand == EnumHand.OFF_HAND ? EnumHitboxType.LEFTARM : EnumHitboxType.RIGHTARM); Vector3f muzzlePos = new Vector3f(hitbox.o.x, hitbox.o.y + hitbox.d.y * 0.5f, hitbox.o.z + hitbox.d.z * 0.5f); if(gunType != null && gunType.model != null) { Vector3f barrelAttach = new Vector3f( gunType.model.barrelAttachPoint.z, -gunType.model.barrelAttachPoint.x, gunType.model.barrelAttachPoint.y); Vector3f.add(muzzlePos, barrelAttach, muzzlePos); } muzzlePos = hitbox.axes.findLocalVectorGlobally(muzzlePos); Vector3f.add(muzzlePos, hitbox.rP, muzzlePos); return muzzlePos; } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketAAGunAngles.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import com.flansmod.common.guns.EntityAAGun; public class PacketAAGunAngles extends PacketBase { public int entityID; public float gunYaw; public float gunPitch; public PacketAAGunAngles() { } public PacketAAGunAngles(EntityAAGun entity) { entityID = entity.getEntityId(); gunYaw = entity.gunYaw; gunPitch = entity.gunPitch; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(entityID); data.writeFloat(gunYaw); data.writeFloat(gunPitch); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { entityID = data.readInt(); gunYaw = data.readFloat(); gunPitch = data.readFloat(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { } @Override public void handleClientSide(EntityPlayer clientPlayer) { Entity entity = clientPlayer.world.getEntityByID(entityID); if(entity instanceof EntityAAGun) { EntityAAGun aa = (EntityAAGun)entity; aa.prevGunYaw = aa.gunYaw; aa.prevGunPitch = aa.gunPitch; aa.gunYaw = gunYaw; aa.gunPitch = gunPitch; } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketAddSingleRewardBoxInstance.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; public class PacketAddSingleRewardBoxInstance extends PacketBase { public int boxHash; @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(boxHash); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { boxHash = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.Assert(false, "Handled single reward box packet on server!"); } @Override public void handleClientSide(EntityPlayer clientPlayer) { ClientTeamsData.AddRewardBox(boxHash); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBase.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; /** * Base class for all packets in Flan's Mod. */ public abstract class PacketBase { /** * Encode the packet into a ByteBuf stream. Advanced data handlers can be found at @link{net.minecraftforge.fml.common.network.ByteBufUtils} */ public abstract void encodeInto(ChannelHandlerContext ctx, ByteBuf data); /** * Decode the packet from a ByteBuf stream. Advanced data handlers can be found at @link{net.minecraftforge.fml.common.network.ByteBufUtils} */ public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf data); /** * Handle the packet on server side, post-decoding */ public abstract void handleServerSide(EntityPlayerMP playerEntity); /** * Handle the packet on client side, post-decoding */ @SideOnly(Side.CLIENT) public abstract void handleClientSide(EntityPlayer clientPlayer); /** * Util method for quickly writing strings */ public static void writeUTF(ByteBuf data, String s) { ByteBufUtils.writeUTF8String(data, s); } /** * Util method for quickly reading strings */ public static String readUTF(ByteBuf data) { return ByteBufUtils.readUTF8String(data); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBaseEdit.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.gui.teams.GuiBaseEditor; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.ITeamBase; import com.flansmod.common.teams.TeamsManager; /** * Packet for the base settings GUI * Server to client gives information for the GUI * Client to server returns changes */ public class PacketBaseEdit extends PacketBase { public int baseID; public String baseName; /** * The maps available */ public String[] maps; /** * The map this base is part of, using the index in the above array */ public int mapID; /** * Team ID, 0 = No Team, 1 = Spectator, 2 = Team 1, 3 = Team 2 */ public int teamID; /** * If the server receives a packet with this flag, the base will be destroyed */ public boolean destroy; public PacketBaseEdit() { } /** * Server to client packet */ public PacketBaseEdit(int baseID, String baseName, String[] maps, int mapID, int teamID) { this(baseID, baseName, maps, mapID, teamID, false); } /** * Client to server packet */ public PacketBaseEdit(int baseID, String baseName, String[] maps, int mapID, int teamID, boolean destroy) { this.baseID = baseID; this.baseName = baseName; this.maps = maps; this.mapID = mapID; this.teamID = teamID; this.destroy = destroy; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(baseID); writeUTF(data, baseName); data.writeInt(maps.length); for(String map : maps) writeUTF(data, map); data.writeInt(mapID); data.writeByte((byte)teamID); data.writeBoolean(destroy); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { baseID = data.readInt(); baseName = readUTF(data); int mapsLength = data.readInt(); maps = new String[mapsLength]; for(int i = 0; i < mapsLength; i++) maps[i] = readUTF(data); mapID = data.readInt(); teamID = data.readByte(); destroy = data.readBoolean(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { //Do another op check if(!FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().canSendCommands(playerEntity.getGameProfile())) return; //Find the base and change its attributes (or destroy it) ITeamBase base = TeamsManager.getInstance().getBase(baseID); if(destroy) { base.destroy(); return; } base.setDefaultOwnerID(teamID); base.setOwnerID(teamID); if(mapID != -1) base.setMapFirstTime(TeamsManager.getInstance().getMapFromFullName(maps[mapID])); base.setBaseName(baseName); FlansMod.log.info(playerEntity.getName() + " modified attributes of base " + baseID); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { Minecraft.getMinecraft().displayGuiScreen(new GuiBaseEditor(this)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBlockHitEffect.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.ParticleDigging; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.vector.Vector3f; public class PacketBlockHitEffect extends PacketBase { private Float x; private Float y; private Float z; private Float directionX; private Float directionY; private Float directionZ; private Integer blockX; private Integer blockY; private Integer blockZ; private EnumFacing facing; public PacketBlockHitEffect() { //default constructor } public PacketBlockHitEffect(Vector3f hit, Vector3f direction, BlockPos position, EnumFacing facing) { this(hit.x, hit.y, hit.z, direction.x, direction.y, direction.z, position.getX(), position.getY(), position.getZ(), facing); } public PacketBlockHitEffect(Float x, Float y, Float z, Float directionX, Float directionY, Float directionZ, Integer blockX, Integer blockY, Integer blockZ, EnumFacing facing) { this.x = x; this.y = y; this.z = z; this.directionX = directionX; this.directionY = directionY; this.directionZ = directionZ; this.blockX = blockX; this.blockY = blockY; this.blockZ = blockZ; this.facing = facing; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeFloat(x); data.writeFloat(y); data.writeFloat(z); data.writeFloat(directionX); data.writeFloat(directionY); data.writeFloat(directionZ); data.writeInt(blockX); data.writeInt(blockY); data.writeInt(blockZ); data.writeInt(facing.getIndex()); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { x = data.readFloat(); y = data.readFloat(); z = data.readFloat(); directionX = data.readFloat(); directionY = data.readFloat(); directionZ = data.readFloat(); blockX = data.readInt(); blockY = data.readInt(); blockZ = data.readInt(); facing = EnumFacing.byIndex(data.readInt()); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received Packet packet on client. Skipping."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { World world = clientPlayer.getEntityWorld(); BlockPos pos = new BlockPos(blockX, blockY, blockZ); IBlockState state = world.getBlockState(pos).getActualState(world, pos); Vec3i facingDir = facing.getDirectionVec(); for(int i = 0; i < 2; i++) { // TODO: [1.12] Check why this isn't moving right float scale = (float)world.rand.nextGaussian() * 0.1f + 0.5f; double motionX = (double)facingDir.getX() * scale + world.rand.nextGaussian() * 0.025d; double motionY = (double)facingDir.getY() * scale + world.rand.nextGaussian() * 0.025d; double motionZ = (double)facingDir.getZ() * scale + world.rand.nextGaussian() * 0.025d; motionX += directionX; motionY += directionY; motionZ += directionZ; ParticleDigging fx = (ParticleDigging)Minecraft.getMinecraft().effectRenderer.spawnEffectParticle( EnumParticleTypes.BLOCK_CRACK.getParticleID(), x, y, z, motionX, motionY, motionZ, Block.getIdFromBlock(state.getBlock())); if(fx != null) { fx.setParticleTexture(Minecraft.getMinecraft().getBlockRendererDispatcher() .getModelForState(state).getParticleTexture()); } } double scale = world.rand.nextGaussian() * 0.05d + 0.05d; double motionX = (double)facingDir.getX() * scale + world.rand.nextGaussian() * 0.025d; double motionY = (double)facingDir.getY() * scale + world.rand.nextGaussian() * 0.025d; double motionZ = (double)facingDir.getZ() * scale + world.rand.nextGaussian() * 0.025d; Minecraft.getMinecraft().effectRenderer.spawnEffectParticle(EnumParticleTypes.CLOUD.getParticleID(), x, y, z, motionX, motionY, motionZ); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBreakSound.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.block.Block; import net.minecraft.block.SoundType; import net.minecraft.block.state.IBlockState; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; public class PacketBreakSound extends PacketBase { public int x, y, z; public int blockID; public PacketBreakSound() { } public PacketBreakSound(int x, int y, int z, Block block) { this.x = x; this.y = y; this.z = z; blockID = Block.getIdFromBlock(block); } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(x); data.writeInt(y); data.writeInt(z); data.writeInt(blockID); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { x = data.readInt(); y = data.readInt(); z = data.readInt(); blockID = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received block break sound packet on server. Skipping."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { World world = clientPlayer.world; BlockPos pos = new BlockPos(x, y, z); IBlockState state = world.getBlockState(new BlockPos(x, y, z)); Block block = Block.getBlockById(blockID); FMLClientHandler.instance().getClient().effectRenderer.addBlockDestroyEffects(new BlockPos(x, y, z), block.getDefaultState()); SoundType sound = block.getSoundType(state, world, pos, clientPlayer); SoundEvent event = sound.getBreakSound(); FMLClientHandler.instance().getClient().getSoundHandler().playSound( new PositionedSoundRecord(event, SoundCategory.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F, x + 0.5F, y + 0.5F, z + 0.5F)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBulletTrail.java ================================================ package com.flansmod.common.network; import com.flansmod.client.model.InstantBulletRenderer; import com.flansmod.client.model.InstantBulletRenderer.InstantShotTrail; import com.flansmod.common.FlansMod; import com.flansmod.common.vector.Vector3f; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; public class PacketBulletTrail extends PacketBase { private Vector3f origin; private Vector3f hitPos; private Float width; private Float length; private Float bulletSpeed; private String trailTexture; public PacketBulletTrail() { } public PacketBulletTrail(Vector3f origin, Vector3f hitPos, Float width, Float length, Float bulletSpeed, String trailTexture) { this.origin = origin; this.hitPos = hitPos; this.width = width; this.length = length; this.bulletSpeed = bulletSpeed; this.trailTexture = trailTexture; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { //origin Vector data.writeFloat(origin.x); data.writeFloat(origin.y); data.writeFloat(origin.z); //hit position vector data.writeFloat(hitPos.x); data.writeFloat(hitPos.y); data.writeFloat(hitPos.z); // trail width, length and speed data.writeFloat(width); data.writeFloat(length); data.writeFloat(bulletSpeed); //trailTexture writeUTF(data, trailTexture); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { //origin Vector origin = new Vector3f(data.readFloat(), data.readFloat(), data.readFloat()); //hit position vector hitPos = new Vector3f(data.readFloat(), data.readFloat(), data.readFloat()); // trail width, length and speed width = data.readFloat(); length = data.readFloat(); bulletSpeed = data.readFloat(); //trailTexture trailTexture = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received PacketBulletTrail on Server. This packet should only be send to clients"); } @Override public void handleClientSide(EntityPlayer clientPlayer) { //TODO trails not visible when trail origin position and player camera position are to close. the can only be seen with an slight angle InstantBulletRenderer.AddTrail(new InstantShotTrail(origin, hitPos, width, length, bulletSpeed, trailTexture)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBuyArmour.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.ArmourBoxType; public class PacketBuyArmour extends PacketBase { public String boxShortName; public String armourShortName; public int piece; public PacketBuyArmour() { } public PacketBuyArmour(String box, String armour, int i) { boxShortName = box; armourShortName = armour; piece = i; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { writeUTF(data, boxShortName); writeUTF(data, armourShortName); data.writeByte((byte)piece); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { boxShortName = readUTF(data); armourShortName = readUTF(data); piece = data.readByte(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { ArmourBoxType box = ArmourBoxType.getBox(boxShortName); box.block.buyArmour(armourShortName, piece, playerEntity.inventory); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received armour box purchase packet on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketBuyWeapon.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.boxes.GunBoxType; import com.flansmod.common.types.InfoType; public class PacketBuyWeapon extends PacketBase { public String boxShortName; private String typeShortName; public PacketBuyWeapon() { } public PacketBuyWeapon(GunBoxType box, InfoType type) { boxShortName = box.shortName; typeShortName = type.shortName; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { writeUTF(data, boxShortName); writeUTF(data, typeShortName); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { boxShortName = readUTF(data); typeShortName = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { GunBoxType box = GunBoxType.getBox(boxShortName); box.block.buyGun(InfoType.getType(typeShortName), playerEntity.inventory, box); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received gun box purchase packet on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketCraftDriveable.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveableType; public class PacketCraftDriveable extends PacketBase { public String shortName; public PacketCraftDriveable() { } public PacketCraftDriveable(String s) { shortName = s; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { writeUTF(data, shortName); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { shortName = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { DriveableType type = DriveableType.getDriveable(shortName); //Try to craft the driveable FlansMod.proxy.craftDriveable(playerEntity, type); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received driveable repair packet on client side. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketDriveableControl.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityPlane; import com.flansmod.common.driveables.EntityVehicle; public class PacketDriveableControl extends PacketBase { public int entityId; public double posX, posY, posZ; public float yaw, pitch, roll; public double motX, motY, motZ; public float avelx, avely, avelz; public float throttle; public float fuelInTank; public float steeringYaw; public PacketDriveableControl() { } public PacketDriveableControl(EntityDriveable driveable) { entityId = driveable.getEntityId(); posX = driveable.posX; posY = driveable.posY; posZ = driveable.posZ; yaw = driveable.axes.getYaw(); pitch = driveable.axes.getPitch(); roll = driveable.axes.getRoll(); motX = driveable.motionX; motY = driveable.motionY; motZ = driveable.motionZ; avelx = driveable.angularVelocity.x; avely = driveable.angularVelocity.y; avelz = driveable.angularVelocity.z; throttle = driveable.throttle; fuelInTank = driveable.driveableData.fuelInTank; if(driveable instanceof EntityVehicle) { EntityVehicle veh = (EntityVehicle)driveable; steeringYaw = veh.wheelsYaw; } else if(driveable instanceof EntityPlane) { EntityPlane plane = (EntityPlane)driveable; steeringYaw = plane.flapsYaw; } } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(entityId); data.writeDouble(posX); data.writeDouble(posY); data.writeDouble(posZ); data.writeFloat(yaw); data.writeFloat(pitch); data.writeFloat(roll); data.writeDouble(motX); data.writeDouble(motY); data.writeDouble(motZ); data.writeFloat(avelx); data.writeFloat(avely); data.writeFloat(avelz); data.writeFloat(throttle); data.writeFloat(fuelInTank); data.writeFloat(steeringYaw); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { entityId = data.readInt(); posX = data.readDouble(); posY = data.readDouble(); posZ = data.readDouble(); yaw = data.readFloat(); pitch = data.readFloat(); roll = data.readFloat(); motX = data.readDouble(); motY = data.readDouble(); motZ = data.readDouble(); avelx = data.readFloat(); avely = data.readFloat(); avelz = data.readFloat(); throttle = data.readFloat(); fuelInTank = data.readFloat(); steeringYaw = data.readFloat(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity == null || playerEntity.world == null || playerEntity.world.loadedEntityList == null) return; EntityDriveable driveable = null; for(int i = 0; i < playerEntity.world.loadedEntityList.size(); i++) { Entity obj = playerEntity.world.loadedEntityList.get(i); if(obj instanceof EntityDriveable && obj.getEntityId() == entityId) { driveable = (EntityDriveable)obj; break; } } if(driveable != null) updateDriveable(driveable, false); } protected void updateDriveable(EntityDriveable driveable, boolean clientSide) { driveable.setPositionRotationAndMotion(posX, posY, posZ, yaw, pitch, roll, motX, motY, motZ, avelx, avely, avelz, throttle, steeringYaw); driveable.driveableData.fuelInTank = fuelInTank; } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { if(clientPlayer == null || clientPlayer.world == null) return; EntityDriveable driveable = null; for(Object obj : clientPlayer.world.loadedEntityList) { if(obj instanceof EntityDriveable && ((Entity)obj).getEntityId() == entityId) { driveable = (EntityDriveable)obj; driveable.driveableData.fuelInTank = fuelInTank; if(driveable.getSeat(0) != null && driveable.getSeat(0).getControllingPassenger() == clientPlayer) return; break; } } if(driveable != null) updateDriveable(driveable, true); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketDriveableDamage.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.DriveablePart; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EnumDriveablePart; public class PacketDriveableDamage extends PacketBase { public int entityId; public int[] health; public boolean[] onFire; public PacketDriveableDamage() { health = new int[EnumDriveablePart.values().length]; onFire = new boolean[EnumDriveablePart.values().length]; } public PacketDriveableDamage(EntityDriveable driveable) { entityId = driveable.getEntityId(); health = new int[EnumDriveablePart.values().length]; onFire = new boolean[EnumDriveablePart.values().length]; for(int i = 0; i < EnumDriveablePart.values().length; i++) { EnumDriveablePart ep = EnumDriveablePart.values()[i]; DriveablePart part = driveable.getDriveableData().parts.get(ep); health[i] = part.health; onFire[i] = part.onFire; } } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(entityId); for(int i = 0; i < EnumDriveablePart.values().length; i++) { data.writeInt(health[i]); data.writeBoolean(onFire[i]); } } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { entityId = data.readInt(); for(int i = 0; i < EnumDriveablePart.values().length; i++) { health[i] = data.readInt(); onFire[i] = data.readBoolean(); } } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Driveable damage packet received on server. Skipping."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { EntityDriveable driveable = null; for(Object obj : clientPlayer.world.loadedEntityList) { if(obj instanceof EntityDriveable && ((Entity)obj).getEntityId() == entityId) { driveable = (EntityDriveable)obj; break; } } if(driveable != null) { for(int i = 0; i < EnumDriveablePart.values().length; i++) { EnumDriveablePart ep = EnumDriveablePart.values()[i]; DriveablePart part = driveable.getDriveableData().parts.get(ep); part.health = health[i]; part.onFire = onFire[i]; } } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketDriveableGUI.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; public class PacketDriveableGUI extends PacketBase { public int guiID; public PacketDriveableGUI() { } public PacketDriveableGUI(int i) { guiID = i; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(guiID); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { guiID = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity.getRidingEntity() != null && playerEntity.getRidingEntity() instanceof EntitySeat) { EntityDriveable d = ((EntitySeat)playerEntity.getRidingEntity()).driveable; switch(guiID) { case 0: //Guns playerEntity.openGui(FlansMod.INSTANCE, 6, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; case 1: //Bombs / Mines playerEntity.openGui(FlansMod.INSTANCE, 7, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; case 2: //Fuel playerEntity.openGui(FlansMod.INSTANCE, 8, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; case 3: //Cargo playerEntity.openGui(FlansMod.INSTANCE, 9, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; case 4: //Mecha playerEntity.openGui(FlansMod.INSTANCE, 10, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; case 5: //Missiles / Shells playerEntity.openGui(FlansMod.INSTANCE, 12, playerEntity.world, d.chunkCoordX, d.chunkCoordY, d.chunkCoordZ); break; } } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received GUI open packet on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketDriveableKey.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.common.FlansMod; public class PacketDriveableKey extends PacketBase { public int key; public PacketDriveableKey() { } public PacketDriveableKey(int k) { key = k; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(key); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { key = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity.getRidingEntity() != null && playerEntity.getRidingEntity() instanceof IControllable) { ((IControllable)playerEntity.getRidingEntity()).serverHandleKeyPress(key, playerEntity); } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Driveable keypress packet received on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketDriveableKeyHeld.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.common.FlansMod; public class PacketDriveableKeyHeld extends PacketBase { public int key; public boolean held; public PacketDriveableKeyHeld() { } public PacketDriveableKeyHeld(int key, boolean held) { this.key = key; this.held = held; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(key); data.writeBoolean(held); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { key = data.readInt(); held = data.readBoolean(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity.getRidingEntity() != null && playerEntity.getRidingEntity() instanceof IControllable) { ((IControllable)playerEntity.getRidingEntity()).updateKeyHeldState(key, held); } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Driveable key packet received on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketFlak.java ================================================ package com.flansmod.common.network; import java.util.Random; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.particle.Particle; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.FlansModClient; import com.flansmod.common.FlansMod; public class PacketFlak extends PacketBase { public static Random rand = new Random(); /** * Position of this flak */ public double x, y, z; /** * Num particles */ public int numParticles; /** * Particle type */ public String particleType; public PacketFlak() { } public PacketFlak(double x1, double y1, double z1, int n, String s) { x = x1; y = y1; z = z1; numParticles = n; particleType = s; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeDouble(x); data.writeDouble(y); data.writeDouble(z); data.writeInt(numParticles); writeUTF(data, particleType); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { x = data.readDouble(); y = data.readDouble(); z = data.readDouble(); numParticles = data.readInt(); particleType = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received flak packet on server. Disregarding."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { World world = clientPlayer.world; for(int i = 0; i < numParticles; i++) { Particle obj = FlansModClient.getParticle(particleType, world, x + rand.nextGaussian(), y + rand.nextGaussian(), z + rand.nextGaussian()); if(obj != null) { obj.multiplyVelocity((float)rand.nextGaussian() / 20.0f); // TODO: [1.12] Apparently we can't set the render distance higher, so let's boost the scale and see how that works obj.multipleParticleScaleBy(5.0f); FMLClientHandler.instance().getClient().effectRenderer.addEffect(obj); } } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketGunAnimation.java ================================================ package com.flansmod.common.network; import com.flansmod.client.FlansModClient; import com.flansmod.client.model.GunAnimations; import com.flansmod.client.model.GunAnimations.LookAtState; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.EnumHand; public class PacketGunAnimation extends PacketBase { private AnimationType type; private AnimationType type2 = AnimationType.NONE; private Float minigunRotationAddSpeed; private Integer pumpdelay; private Integer pumptime; private Float recoil; private Integer reloadtime; private EnumHand hand; public PacketGunAnimation() { } public PacketGunAnimation(EnumHand hand, Integer pumpdelay, Integer pumptime, Float recoil) { this.type = AnimationType.SHOOT; this.pumpdelay = pumpdelay; this.pumptime = pumptime; this.recoil = recoil; this.hand = hand; } public PacketGunAnimation(EnumHand hand, Integer pumpdelay, Integer pumptime, Float recoil, Float minigunAddSpeed) { this(hand,pumpdelay,pumptime,recoil); this.type2 = AnimationType.ROTATION; this.minigunRotationAddSpeed = minigunAddSpeed; } public PacketGunAnimation(EnumHand hand, Float minigunAddSpeed) { this.type = AnimationType.ROTATION; this.hand = hand; this.minigunRotationAddSpeed = minigunAddSpeed; } public PacketGunAnimation(EnumHand hand, Integer reloadtime, Integer pumpdelay, Integer pumptime) { this.type = AnimationType.RELOAD; this.hand = hand; this.pumpdelay = pumpdelay; this.pumptime = pumptime; this.reloadtime = reloadtime; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(encode(type)); data.writeInt(encode(type2)); //TODO proper enum encoding data.writeInt(hand.equals(EnumHand.MAIN_HAND)?0:1); encodeInto(ctx, data, type); encodeInto(ctx, data, type2); } private void encodeInto(ChannelHandlerContext ctx, ByteBuf data,AnimationType type) { switch (type) { case NONE: break; case ROTATION: data.writeFloat(minigunRotationAddSpeed); break; case SHOOT: data.writeInt(pumpdelay); data.writeInt(pumptime); data.writeFloat(recoil); break; case RELOAD: data.writeInt(pumpdelay); data.writeInt(pumptime); data.writeInt(reloadtime); break; } } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { this.type = decode(data.readInt()); this.type2 = decode(data.readInt()); //TODO proper enum decoding this.hand = data.readInt()==0?EnumHand.MAIN_HAND:EnumHand.OFF_HAND; decodeInto(ctx, data, type); decodeInto(ctx, data, type2); } private void decodeInto(ChannelHandlerContext ctx, ByteBuf data,AnimationType type) { switch (type) { case NONE: break; case ROTATION: this.minigunRotationAddSpeed = data.readFloat(); break; case SHOOT: pumpdelay = data.readInt(); pumptime = data.readInt(); recoil = data.readFloat(); break; case RELOAD: pumpdelay = data.readInt(); pumptime = data.readInt(); reloadtime = data.readInt(); break; } } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Server Side should not receive this Packet"); } @Override public void handleClientSide(EntityPlayer clientPlayer) { GunAnimations animations = FlansModClient.getGunAnimations(clientPlayer, hand); handleAnimation(animations, type, clientPlayer); handleAnimation(animations, type2, clientPlayer); } private void handleAnimation(GunAnimations animations, AnimationType type, EntityPlayer player) { switch (type) { case NONE: break; case RELOAD: animations.doReload(reloadtime, pumpdelay, pumptime); PlayerData data = PlayerHandler.getPlayerData(player); data.shootTimeRight = data.shootTimeLeft = reloadtime; data.SetBurstRoundsRemaining(hand, 0); data.reloadingLeft = data.reloadingRight = true; break; case SHOOT: //TODO lookatstate not send by Server, may cause problems in future animations.lookAt = LookAtState.NONE; animations.doShoot(pumpdelay, pumptime); FlansModClient.playerRecoil += recoil; animations.recoil += recoil; break; case ROTATION: animations.addMinigunBarrelRotationSpeed(minigunRotationAddSpeed); break; } } //TODO proper enum decoding private static AnimationType decode(Integer i) { if (i == 0) { return AnimationType.NONE; } else if (i == 1) { return AnimationType.RELOAD; } else if (i == 2) { return AnimationType.SHOOT; } else if (i == 3) { return AnimationType.ROTATION; } throw new NullPointerException("Integer not kown"); } //TODO proper enum encoding private static Integer encode(AnimationType a) { if (a == AnimationType.NONE) { return 0; } else if (a == AnimationType.RELOAD) { return 1; } else if (a == AnimationType.SHOOT) { return 2; } else if (a == AnimationType.ROTATION) { return 3; } throw new NullPointerException("Animation not kown"); } public static enum AnimationType { SHOOT,RELOAD,ROTATION,NONE } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketGunFire.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.ItemGun; public class PacketGunFire extends PacketBase { private EnumHand hand; public PacketGunFire() { } public PacketGunFire(EnumHand hand) { this.hand = hand; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { //TODO Proper packet enum encoding data.writeInt(EnumHand.MAIN_HAND.equals(hand)?0:1); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { //TODO Proper packet enum encoding hand = data.readInt()==0?EnumHand.MAIN_HAND:EnumHand.OFF_HAND; } @Override public void handleServerSide(EntityPlayerMP playerEntity) { ItemStack itemstack = playerEntity.getHeldItem(hand); //TODO can itemstack be null? Item item = itemstack.getItem(); if (item instanceof ItemGun) { ItemGun gun = (ItemGun) item; gun.shootServer(hand, playerEntity, itemstack); } else { FlansMod.log.warn("Received invalid PacketGunFire. Item in hand is not an instance of ItemGun"); } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received gun button packet on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketGunPaint.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import com.flansmod.common.guns.ContainerGunModTable; import com.flansmod.common.paintjob.ContainerPaintjobTable; public class PacketGunPaint extends PacketBase { private int paintjobID; public PacketGunPaint() { } public PacketGunPaint(int i) { paintjobID = i; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(paintjobID); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { paintjobID = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity.openContainer instanceof ContainerGunModTable) { ContainerGunModTable gunModTable = ((ContainerGunModTable)playerEntity.openContainer); gunModTable.clickPaintjob(paintjobID); } else if(playerEntity.openContainer instanceof ContainerPaintjobTable) { ContainerPaintjobTable paintjobTable = ((ContainerPaintjobTable)playerEntity.openContainer); paintjobTable.clickPaintjob(paintjobID); } } @Override public void handleClientSide(EntityPlayer clientPlayer) { } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketHandler.java ================================================ package com.flansmod.common.network; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.network.FMLEmbeddedChannel; import net.minecraftforge.fml.common.network.FMLOutboundHandler; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; /** * Flan's Mod packet handler class. Directs packet data to packet classes. * * @author Flan * With much inspiration from http://www.minecraftforge.net/wiki/Netty_Packet_Handling */ @ChannelHandler.Sharable public class PacketHandler extends MessageToMessageCodec { //Map of channels for each side private EnumMap channels; //The list of registered packets. Should contain no more than 256 packets. private LinkedList> packets = new LinkedList<>(); //Whether or not Flan's Mod has initialised yet. Once true, no more packets may be registered. private boolean modInitialised = false; /** * Store received packets in these queues and have the main Minecraft threads use these */ private ConcurrentLinkedQueue receivedPacketsClient = new ConcurrentLinkedQueue<>(); private HashMap> receivedPacketsServer = new HashMap<>(); /** * Registers a packet with the handler */ public boolean registerPacket(Class cl) { if(packets.size() > 256) { FlansMod.log.warn("Packet limit exceeded in Flan's Mod packet handler by packet " + cl.getCanonicalName() + "."); return false; } if(packets.contains(cl)) { FlansMod.log.warn("Tried to register " + cl.getCanonicalName() + " packet class twice."); return false; } if(modInitialised) { FlansMod.log.warn("Tried to register packet " + cl.getCanonicalName() + " after mod initialisation."); return false; } packets.add(cl); return true; } @Override protected void encode(ChannelHandlerContext ctx, PacketBase msg, List out) throws Exception { try { //Define a new buffer to store our data upon encoding ByteBuf encodedData = Unpooled.buffer(); //Get the packet class Class cl = msg.getClass(); //If this packet has not been registered by our handler, reject it if(!packets.contains(cl)) throw new NullPointerException("Packet not registered : " + cl.getCanonicalName()); //Like a packet ID. Stored as the first entry in the packet code for recognition byte discriminator = (byte)packets.indexOf(cl); encodedData.writeByte(discriminator); //Get the packet class to encode our packet msg.encodeInto(ctx, encodedData); //Convert our packet into a Forge packet to get it through the Netty system FMLProxyPacket proxyPacket = new FMLProxyPacket(new PacketBuffer(encodedData.copy()), ctx.channel().attr(NetworkRegistry.FML_CHANNEL).get()); //Add our packet to the outgoing packet queue out.add(proxyPacket); } catch(Exception e) { FlansMod.log.error("ERROR encoding packet"); FlansMod.log.throwing(e); } } @Override protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List out) throws Exception { try { //Get the encoded data from the incoming packet ByteBuf encodedData = msg.payload(); //Get the class for interpreting this packet byte discriminator = encodedData.readByte(); Class cl = packets.get(discriminator); //If this discriminator returns no class, reject it if(cl == null) throw new NullPointerException("Packet not registered for discriminator : " + discriminator); //Create an empty packet and decode our packet data into it PacketBase packet = cl.getConstructor().newInstance(); packet.decodeInto(ctx, encodedData.slice()); //Check the side and handle our packet accordingly switch(FMLCommonHandler.instance().getEffectiveSide()) { case CLIENT: { receivedPacketsClient.offer(packet); //packet.handleClientSide(getClientPlayer()); break; } case SERVER: { INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get(); EntityPlayer player = ((NetHandlerPlayServer)netHandler).player; if(!receivedPacketsServer.containsKey(player.getName())) receivedPacketsServer.put(player.getName(), new ConcurrentLinkedQueue<>()); receivedPacketsServer.get(player.getName()).offer(packet); //packet.handleServerSide(); break; } } } catch(Exception e) { FlansMod.log.error("ERROR decoding packet"); FlansMod.log.throwing(e); } } @SideOnly(Side.CLIENT) public void handleClientPackets() { while(!receivedPacketsClient.isEmpty()) { PacketBase packet = receivedPacketsClient.poll(); packet.handleClientSide(getClientPlayer()); } } public void handleServerPackets() { for(String playerName : receivedPacketsServer.keySet()) { ConcurrentLinkedQueue receivedPacketsFromPlayer = receivedPacketsServer.get(playerName); EntityPlayerMP player = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUsername(playerName); while(!receivedPacketsFromPlayer.isEmpty()) { PacketBase packet = receivedPacketsFromPlayer.poll(); packet.handleServerSide(player); } } } /** * Initialisation method called from FMLInitializationEvent in FlansMod */ public void initialise() { channels = NetworkRegistry.INSTANCE.newChannel("FlansMod", this); registerPacket(PacketAAGunAngles.class); registerPacket(PacketBaseEdit.class); registerPacket(PacketBreakSound.class); registerPacket(PacketBuyArmour.class); registerPacket(PacketBuyWeapon.class); registerPacket(PacketCraftDriveable.class); registerPacket(PacketDriveableControl.class); registerPacket(PacketDriveableDamage.class); registerPacket(PacketDriveableGUI.class); registerPacket(PacketDriveableKey.class); registerPacket(PacketDriveableKeyHeld.class); registerPacket(PacketFlak.class); registerPacket(PacketGunFire.class); registerPacket(PacketGunPaint.class); registerPacket(PacketKillMessage.class); registerPacket(PacketMechaControl.class); registerPacket(PacketMGFire.class); registerPacket(PacketMGMount.class); registerPacket(PacketPlaneControl.class); registerPacket(PacketPlaySound.class); registerPacket(PacketReload.class); registerPacket(PacketRepairDriveable.class); registerPacket(PacketRoundFinished.class); registerPacket(PacketSeatUpdates.class); registerPacket(PacketTeamInfo.class); registerPacket(PacketTeamSelect.class); registerPacket(PacketVehicleControl.class); registerPacket(PacketVoteCast.class); registerPacket(PacketVoting.class); registerPacket(PacketRequestDebug.class); registerPacket(PacketLoadoutData.class); registerPacket(PacketOpenRewardBox.class); registerPacket(PacketAddSingleRewardBoxInstance.class); registerPacket(PacketGunAnimation.class); registerPacket(PacketBulletTrail.class); registerPacket(PacketHitMarker.class); registerPacket(PacketBlockHitEffect.class); } /** * Post-Initialisation method called from FMLPostInitializationEvent in FlansMod * Logically sorts the packets client and server side to ensure a matching ordering */ public void postInitialise() { if(modInitialised) return; modInitialised = true; //Define our comparator on the fly and apply it to our list packets.sort((c1, c2) -> { int com = String.CASE_INSENSITIVE_ORDER.compare(c1.getCanonicalName(), c2.getCanonicalName()); if(com == 0) com = c1.getCanonicalName().compareTo(c2.getCanonicalName()); return com; }); } @SideOnly(Side.CLIENT) private EntityPlayer getClientPlayer() { return Minecraft.getMinecraft().player; } /** * Send a packet to all players */ public void sendToAll(PacketBase packet) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL); channels.get(Side.SERVER).writeAndFlush(packet); } /** * Send a packet to a player */ public void sendTo(PacketBase packet, EntityPlayerMP player) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER); channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player); channels.get(Side.SERVER).writeAndFlush(packet); } /** * Send a packet to all around a point */ public void sendToAllAround(PacketBase packet, NetworkRegistry.TargetPoint point) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT); channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point); channels.get(Side.SERVER).writeAndFlush(packet); } /** * Send a packet to all in a dimension */ public void sendToDimension(PacketBase packet, int dimensionID) { channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION); channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimensionID); channels.get(Side.SERVER).writeAndFlush(packet); } /** * Send a packet to the server */ public void sendToServer(PacketBase packet) { channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER); channels.get(Side.CLIENT).writeAndFlush(packet); } //Vanilla packets follow /** * Send a packet to all players */ public void sendToAll(Packet packet) { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().sendPacketToAllPlayers(packet); } /** * Send a packet to a player */ public void sendTo(Packet packet, EntityPlayerMP player) { player.connection.sendPacket(packet); } /** * Send a packet to all around a point */ public void sendToAllAround(Packet packet, NetworkRegistry.TargetPoint point) { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().sendToAllNearExcept(null, point.x, point.y, point.z, point.range, point.dimension, packet); } /** * Send a packet to all in a dimension */ public void sendToDimension(Packet packet, int dimensionID) { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().sendPacketToAllPlayersInDimension(packet, dimensionID); } /** * Send a packet to the server */ public void sendToServer(Packet packet) { Minecraft.getMinecraft().player.connection.sendPacket(packet); } /** * Send a packet to all around a point without having to create one's own TargetPoint */ public void sendToAllAround(PacketBase packet, double x, double y, double z, float range, int dimension) { sendToAllAround(packet, new NetworkRegistry.TargetPoint(dimension, x, y, z, range)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketHitMarker.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.FlansModClient; import com.flansmod.common.FlansMod; public class PacketHitMarker extends PacketBase { public PacketHitMarker() { //no data } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { //no data } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { //no data } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received PacketHitMarker packet on server. Disregarding."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansModClient.addHitMarker(); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketKillMessage.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import com.flansmod.client.ClientRenderHooks; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; public class PacketKillMessage extends PacketBase { public InfoType killedBy; public String killerName; public String killedName; public boolean headshot; public PacketKillMessage() { } public PacketKillMessage(boolean head, InfoType weapon, String victim, String murderer) { killedBy = weapon; killerName = murderer; killedName = victim; headshot = head; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeBoolean(headshot); writeUTF(data, killedBy.shortName); writeUTF(data, killerName); writeUTF(data, killedName); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { headshot = data.readBoolean(); killedBy = InfoType.getType(readUTF(data)); killerName = readUTF(data); killedName = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received kill message packet on the server. Skipping."); } @Override public void handleClientSide(EntityPlayer clientPlayer) { ClientRenderHooks.addKillMessage(headshot, killedBy, killerName, killedName); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketLoadoutData.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.gui.teams.EnumLoadoutSlot; import com.flansmod.client.gui.teams.GuiTeamSelect; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.LoadoutPool; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManagerRanked; public class PacketLoadoutData extends PacketBase { public String motd = ""; public Team[] teamsAvailable = new Team[0]; public PlayerRankData myRankData = new PlayerRankData(); public LoadoutPool currentPool = null; public PacketLoadoutData() { } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { writeUTF(data, motd); data.writeInt(teamsAvailable.length); for(Team aTeamsAvailable : teamsAvailable) { data.writeInt(aTeamsAvailable == null ? 0 : aTeamsAvailable.shortName.hashCode()); } myRankData.writeToBuf(data); data.writeInt(currentPool == null ? 0 : currentPool.shortName.hashCode()); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { motd = readUTF(data); int numTeams = data.readInt(); teamsAvailable = new Team[numTeams]; for(int i = 0; i < teamsAvailable.length; i++) { teamsAvailable[i] = Team.getTeam(data.readInt()); } myRankData.readFromBuf(data); currentPool = LoadoutPool.GetPool(data.readInt()); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { PlayerRankData rankData = TeamsManagerRanked.rankData.get(playerEntity.getUniqueID()); if(rankData == null) { rankData = new PlayerRankData(); TeamsManagerRanked.rankData.put(playerEntity.getUniqueID(), rankData); } // Client to server. The only bit they are authoritative on is their loadouts. But they still need to be checked for cheating. // TODO: Verify loadout is valid myRankData.currentLevel = rankData.currentLevel; if(myRankData.VerifyLoadouts()) { rankData.loadouts = myRankData.loadouts; } else { FlansMod.Assert(false, "PLAYER " + playerEntity.getDisplayNameString() + " GAVE INCORRECT LOADOUT."); LoadoutPool pool = TeamsManagerRanked.GetInstance().currentPool; if(pool != null) { for(int i = 0; i < 5; i++) { for(int j = 0; j < EnumLoadoutSlot.values().length; j++) { if(pool.defaultLoadouts[i].slots[j] != null) { rankData.loadouts[i].slots[j] = pool.defaultLoadouts[i].slots[j].copy(); } else rankData.loadouts[i].slots[j] = null; } } } } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { ClientTeamsData.motd = motd; ClientTeamsData.theRankData = myRankData; ClientTeamsData.currentPool = currentPool; GuiTeamSelect.teamChoices = teamsAvailable; ClientTeamsData.OpenLandingPage(); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketMGFire.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerHandler; import com.flansmod.common.guns.EntityAAGun; import com.flansmod.common.guns.EntityMG; public class PacketMGFire extends PacketBase { public boolean held; public PacketMGFire() { } public PacketMGFire(boolean h) { held = h; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeBoolean(held); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { held = data.readBoolean(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { EntityMG mg = PlayerHandler.getPlayerData(playerEntity).mountingGun; if(mg != null) { mg.mouseHeld(held); } else if(playerEntity.getRidingEntity() instanceof EntityAAGun) { ((EntityAAGun)playerEntity.getRidingEntity()).setMouseHeld(held); } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("MG firing packet received on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketMGMount.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.EntityMG; public class PacketMGMount extends PacketBase { public int playerEntityId; public int mgEntityId; public boolean mounting; public PacketMGMount() { } public PacketMGMount(EntityPlayer player, EntityMG mg, boolean mounting) { playerEntityId = player.getEntityId(); mgEntityId = mg.getEntityId(); this.mounting = mounting; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(playerEntityId); data.writeInt(mgEntityId); data.writeBoolean(mounting); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { playerEntityId = data.readInt(); mgEntityId = data.readInt(); mounting = data.readBoolean(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received MG mount packet on server. Skipping."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { EntityPlayer player = (EntityPlayer)clientPlayer.world.getEntityByID(playerEntityId); EntityMG mg = (EntityMG)clientPlayer.world.getEntityByID(mgEntityId); if(mg != null && player != null) mg.mountGun(player, mounting); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketMechaControl.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.common.network.ByteBufUtils; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.driveables.mechas.EnumMechaSlotType; public class PacketMechaControl extends PacketDriveableControl { public float legYaw, legSwing; public ItemStack leftStack, rightStack; public PacketMechaControl() { } public PacketMechaControl(EntityDriveable driveable) { super(driveable); EntityMecha mecha = (EntityMecha)driveable; legYaw = mecha.legAxes.getYaw(); legSwing = mecha.legSwing; leftStack = mecha.inventory.getStackInSlot(EnumMechaSlotType.leftTool); rightStack = mecha.inventory.getStackInSlot(EnumMechaSlotType.rightTool); } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.encodeInto(ctx, data); data.writeFloat(legYaw); data.writeFloat(legSwing); ByteBufUtils.writeItemStack(data, leftStack); ByteBufUtils.writeItemStack(data, rightStack); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.decodeInto(ctx, data); legYaw = data.readFloat(); legSwing = data.readFloat(); leftStack = ByteBufUtils.readItemStack(data); rightStack = ByteBufUtils.readItemStack(data); data.release(); } @Override protected void updateDriveable(EntityDriveable driveable, boolean clientSide) { super.updateDriveable(driveable, clientSide); EntityMecha mecha = (EntityMecha)driveable; mecha.legAxes.setAngles(legYaw, 0F, 0F); mecha.legSwing = legSwing / 2F; if(clientSide) { mecha.inventory.setInventorySlotContents(EnumMechaSlotType.leftTool, leftStack); mecha.inventory.setInventorySlotContents(EnumMechaSlotType.rightTool, rightStack); } else { FlansMod.getPacketHandler().sendToAllAround(new PacketMechaControl(mecha), posX, posY, posZ, FlansMod.driveableUpdateRange, mecha.dimension); } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketOpenRewardBox.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.RewardBox; import com.flansmod.common.teams.TeamsManagerRanked; public class PacketOpenRewardBox extends PacketBase { public int boxHash = 0; public int unlockHash = 0; public PacketOpenRewardBox() { } /** * Server to client reward request packet */ public PacketOpenRewardBox(RewardBox box) { boxHash = box.hashCode(); } public PacketOpenRewardBox(int box, int unlock) { boxHash = box; unlockHash = unlock; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(boxHash); data.writeInt(unlockHash); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { boxHash = data.readInt(); unlockHash = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { RewardBox box = RewardBox.GetRewardBox(boxHash); if(box == null) { FlansMod.Assert(false, "Recieved invalid reward box open packet from player " + playerEntity.getDisplayNameString()); } else { FlansMod.log.info("Recieved reward box open packet from player " + playerEntity.getDisplayNameString() + " for box " + box.shortName); TeamsManagerRanked.OpenRewardBox(playerEntity, box); } } @SideOnly(Side.CLIENT) @Override public void handleClientSide(EntityPlayer clientPlayer) { ClientTeamsData.UnlockReward(boxHash, unlockHash); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketPlaneControl.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityPlane; public class PacketPlaneControl extends PacketDriveableControl { public boolean gear, doors, wings; public PacketPlaneControl() { } public PacketPlaneControl(EntityDriveable driveable) { super(driveable); EntityPlane plane = (EntityPlane)driveable; gear = plane.varGear; doors = plane.varDoor; wings = plane.varWing; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.encodeInto(ctx, data); data.writeBoolean(gear); data.writeBoolean(doors); data.writeBoolean(wings); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.decodeInto(ctx, data); gear = data.readBoolean(); doors = data.readBoolean(); wings = data.readBoolean(); data.release(); } @Override protected void updateDriveable(EntityDriveable driveable, boolean clientSide) { super.updateDriveable(driveable, clientSide); EntityPlane plane = (EntityPlane)driveable; plane.varDoor = doors; plane.varGear = gear; plane.varWing = wings; if(!clientSide) { FlansMod.getPacketHandler().sendToAllAround( new PacketPlaneControl(plane), posX, posY, posZ, FlansMod.driveableUpdateRange, plane.dimension); } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketPlaySound.java ================================================ package com.flansmod.common.network; import java.util.Random; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.vector.Matrix2f; public class PacketPlaySound extends PacketBase { public static Random rand = new Random(); public float posX, posY, posZ; public String sound; public boolean distort, silenced; public int hash, value; public PacketPlaySound() { } public static void sendSoundPacket(double x, double y, double z, double range, int dimension, String s, boolean distort) { sendSoundPacket(x, y, z, range, dimension, s, distort, false); } public static void sendSoundPacket(double x, double y, double z, double range, int dimension, String s, boolean distort, boolean silenced) { FlansMod.getPacketHandler().sendToAllAround(new PacketPlaySound(x, y, z, s, distort, silenced), x, y, z, (float)range, dimension); } public PacketPlaySound(double x, double y, double z, String s) { this(x, y, z, s, false); } public PacketPlaySound(double x, double y, double z, String s, boolean distort) { this(x, y, z, s, distort, false); } public PacketPlaySound(double x, double y, double z, String s, boolean distort, boolean silenced) { posX = (float)x; posY = (float)y; posZ = (float)z; sound = s; this.distort = distort; this.silenced = silenced; Matrix2f audioMatrix = Matrix2f.generateAudioMatrix(x, y, z); hash = audioMatrix.coords.hash; value = audioMatrix.value; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeFloat(posX); data.writeFloat(posY); data.writeFloat(posZ); writeUTF(data, sound); data.writeBoolean(distort); data.writeBoolean(silenced); data.writeInt(hash); data.writeInt(value); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { posX = data.readFloat(); posY = data.readFloat(); posZ = data.readFloat(); sound = readUTF(data); distort = data.readBoolean(); silenced = data.readBoolean(); hash = data.readInt(); value = data.readInt(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received play sound packet on server. Skipping."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { SoundEvent event = FlansModResourceHandler.getSoundEvent(sound); FMLClientHandler.instance().getClient().getSoundHandler().playSound( new PositionedSoundRecord(event, SoundCategory.PLAYERS, silenced ? 2F : 4F, (distort ? 1.0F / (rand.nextFloat() * 0.4F + 0.8F) : 1.0F) * (silenced ? 2F : 1F), posX, posY, posZ)); Matrix2f.verifyMatrixNormals(new Matrix2f(hash, value)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketReload.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumHand; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.enchantments.EnchantmentModule; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemGun; /** * This packet is send by the client to request a reload. The server checks if the player can reload and in this case actually reloads and sends a GunAnimationPacket as response. * The GunAnimationPacket plays the reload animation and sets the pumpDelay & pumpTime times to prevent the client from shooting while reloading */ public class PacketReload extends PacketBase { public boolean isOffHand; public boolean isForced; public PacketReload() { } public PacketReload(EnumHand hand, boolean isForced) { this.isOffHand = hand == EnumHand.OFF_HAND; this.isForced = isForced; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeBoolean(isOffHand); data.writeBoolean(isForced); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { isOffHand = data.readBoolean(); isForced = data.readBoolean(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { EnumHand hand = isOffHand ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; PlayerData data = PlayerHandler.getPlayerData(playerEntity); ItemStack main = playerEntity.getHeldItemMainhand(); ItemStack off = playerEntity.getHeldItemOffhand(); ItemStack stack = isOffHand ? off : main; boolean hasOffHand = main != null && !main.isEmpty() && off != null && !off.isEmpty(); ItemStack otherHand = isOffHand ? main : off; if(data != null && stack != null && stack.getItem() instanceof ItemGun) { GunType type = ((ItemGun)stack.getItem()).GetType(); if(((ItemGun)stack.getItem()).Reload(stack, playerEntity.world, playerEntity, playerEntity.inventory, hand, hasOffHand, isForced, playerEntity.capabilities.isCreativeMode)) { float reloadDelay = EnchantmentModule.ModifyReloadTime(type.reloadTime, playerEntity, otherHand); //Set the reload delay data.shootTimeRight = data.shootTimeLeft = reloadDelay; if(isOffHand) data.reloadingLeft = true; else data.reloadingRight = true; //Play reload sound if(type.reloadSound != null) PacketPlaySound.sendSoundPacket(playerEntity.posX, playerEntity.posY, playerEntity.posZ, FlansMod.soundRange, playerEntity.dimension, type.reloadSound, false); FlansMod.getPacketHandler().sendTo(new PacketGunAnimation(hand, (int)reloadDelay, type.getPumpDelayAfterReload(), type.getPumpTime()), playerEntity); } } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Recieved reload packet on client!"); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketRepairDriveable.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntitySeat; import com.flansmod.common.driveables.EnumDriveablePart; public class PacketRepairDriveable extends PacketBase { public String shortName; public PacketRepairDriveable() { } public PacketRepairDriveable(EnumDriveablePart part) { shortName = part.getShortName(); } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { writeUTF(data, shortName); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { shortName = readUTF(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { EnumDriveablePart part = EnumDriveablePart.getPart(shortName); //Try to repair the driveable FlansMod.proxy.repairDriveable(playerEntity, ((EntitySeat)playerEntity.getRidingEntity()).driveable, ((EntitySeat)playerEntity.getRidingEntity()).driveable.getDriveableData().parts.get(part)); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received driveable repair packet on client side. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketRequestDebug.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.common.FMLCommonHandler; import com.flansmod.common.FlansMod; /** * Sent from client to server when player wants to go into debug mode * Sent from server to client to confirm that player may go into debug mode (i.e. player is an op) * * @author James */ public class PacketRequestDebug extends PacketBase { public PacketRequestDebug() { } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().canSendCommands(playerEntity.getGameProfile())) FlansMod.packetHandler.sendTo(new PacketRequestDebug(), playerEntity); } @Override public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.DEBUG = true; } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketRoundFinished.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.teams.RoundFinishedData; public class PacketRoundFinished extends PacketBase { public RoundFinishedData roundFinishedData = new RoundFinishedData(); public PacketRoundFinished() { } public PacketRoundFinished(RoundFinishedData data) { roundFinishedData = data; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { roundFinishedData.WriteInitialData(data); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { roundFinishedData.ReadInitialData(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { ClientTeamsData.SetRoundFinishedData(roundFinishedData); ClientTeamsData.StartTimers(); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketSeatUpdates.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntitySeat; public class PacketSeatUpdates extends PacketBase { public int entityId, seatId; public float yaw, pitch; public PacketSeatUpdates() { } public PacketSeatUpdates(EntitySeat seat) { entityId = seat.driveable.getEntityId(); seatId = seat.seatInfo.id; yaw = seat.looking.getYaw(); pitch = seat.looking.getPitch(); } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeInt(entityId); data.writeInt(seatId); data.writeFloat(yaw); data.writeFloat(pitch); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { entityId = data.readInt(); seatId = data.readInt(); yaw = data.readFloat(); pitch = data.readFloat(); data.release(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(playerEntity == null) { FlansMod.log.warn("Received seat update packet from a null player, skipping!"); return ; } EntityDriveable driveable = null; for(Object obj : playerEntity.world.loadedEntityList) { if(obj instanceof EntityDriveable && ((Entity)obj).getEntityId() == entityId) { driveable = (EntityDriveable)obj; break; } } if(driveable != null) { driveable.getSeat(seatId).prevLooking = driveable.getSeat(seatId).looking.clone(); driveable.getSeat(seatId).looking.setAngles(yaw, pitch, 0F); //If on the server, update all surrounding players with these new angles FlansMod.getPacketHandler().sendToAllAround(this, driveable.posX, driveable.posY, driveable.posZ, FlansMod.soundRange, driveable.dimension); } } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { EntityDriveable driveable = null; for(int i = 0; i < clientPlayer.world.loadedEntityList.size(); i++) { Entity obj = clientPlayer.world.loadedEntityList.get(i); if(obj instanceof EntityDriveable && obj.getEntityId() == entityId) { driveable = (EntityDriveable)obj; break; } } if(driveable != null) { //If this is the player who sent the packet in the first place, don't read it if(driveable.getSeat(seatId) == null || driveable.getSeat(seatId).getControllingPassenger() == clientPlayer) return; driveable.getSeat(seatId).prevLooking = driveable.getSeat(seatId).looking.clone(); driveable.getSeat(seatId).looking.setAngles(yaw, pitch, 0F); } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketTeamInfo.java ================================================ package com.flansmod.common.network; import java.util.ArrayList; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.FlansModClient; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.teams.PlayerClass; import com.flansmod.common.teams.PlayerRankData; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.teams.TeamsManagerRanked; public class PacketTeamInfo extends PacketBase { public String mapShortName; public String map; public String gametype; public boolean showZombieScore; public int numTeams; public TeamData[] teamData; public boolean sortedByTeam; public int timeLeft; public int scoreLimit; public int numLines; public static class TeamData { public Team team; public int score; public int numPlayers; public PlayerScoreData[] playerData; public boolean winner; } public static class PlayerScoreData { public int level; public String username; public int score; public int kills; public int deaths; public TeamData team; public PlayerClass playerClass; public int zombieScore; } public static PlayerScoreData getPlayerScoreData(String username) { if(FlansModClient.teamInfo.teamData == null) return null; for(TeamData team : FlansModClient.teamInfo.teamData) { if(team == null || team.playerData == null) return null; for(PlayerScoreData player : team.playerData) { if(player != null && player.username != null && player.username.equals(username)) return player; } } return null; } public PacketTeamInfo() { } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeBoolean(TeamsManager.canBreakGlass); data.writeBoolean(TeamsManager.vehiclesNeedFuel); data.writeBoolean(TeamsManager.driveablesBreakBlocks); if(TeamsManager.getInstance().currentRound == null) { writeUTF(data, "No Gametype"); data.writeInt(0); } else { writeUTF(data, TeamsManager.getInstance().currentRound.gametype.name); data.writeBoolean(TeamsManager.getInstance().currentRound.gametype.showZombieScore()); writeUTF(data, TeamsManager.getInstance().currentRound.map.name); writeUTF(data, TeamsManager.getInstance().currentRound.map.shortName); data.writeInt(TeamsManager.getInstance().roundTimeLeft); data.writeInt(TeamsManager.getInstance().currentRound.scoreLimit); if(TeamsManager.getInstance().currentRound.gametype.sortScoreboardByTeam()) { data.writeBoolean(true); if(TeamsManager.getInstance().currentRound.teams == null) { data.writeInt(0); } else { data.writeInt(TeamsManager.getInstance().currentRound.teams.length); for(int i = 0; i < TeamsManager.getInstance().currentRound.teams.length; i++) { Team team = TeamsManager.getInstance().currentRound.teams[i]; if(team == null) { writeUTF(data, "none"); continue; } writeUTF(data, team.shortName); data.writeInt(team.score); data.writeBoolean(TeamsManager.getInstance().currentRound.gametype.teamHasWon(team)); team.sortPlayers(); data.writeInt(team.members.size()); for(int j = 0; j < team.members.size(); j++) { String username = team.members.get(j); PlayerData playerData = PlayerHandler.getPlayerData(username, Side.SERVER); writeUTF(data, username); PlayerRankData rankData = TeamsManagerRanked.GetRankData(TeamsManager.getPlayer(username)); if(rankData == null) { data.writeInt(0); } else { data.writeInt(rankData.currentLevel); } if(playerData == null) { data.writeInt(0); data.writeInt(0); data.writeInt(0); writeUTF(data, ""); } else { data.writeInt(playerData.score); data.writeInt(playerData.zombieScore); data.writeInt(playerData.kills); data.writeInt(playerData.deaths); writeUTF(data, playerData.playerClass.GetShortName()); } } } } } else { data.writeBoolean(false); ArrayList playerNames = new ArrayList<>(); for(int i = 0; i < TeamsManager.getInstance().currentRound.teams.length; i++) { Team team = TeamsManager.getInstance().currentRound.teams[i]; if(team == null || team.members == null) { continue; } playerNames.addAll(team.members); } playerNames.sort(new Team.ComparatorScore()); data.writeInt(playerNames.size()); for(String username : playerNames) { PlayerData playerData = PlayerHandler.getPlayerData(username, Side.SERVER); writeUTF(data, username); PlayerRankData rankData = TeamsManagerRanked.GetRankData(TeamsManager.getPlayer(username)); if(rankData == null) { data.writeInt(0); } else { data.writeInt(rankData.currentLevel); } if(playerData == null) { data.writeInt(0); data.writeInt(0); data.writeInt(0); writeUTF(data, ""); } else { data.writeInt(playerData.score); data.writeInt(playerData.kills); data.writeInt(playerData.deaths); writeUTF(data, playerData.playerClass.GetShortName()); } } } } } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { try { TeamsManager.canBreakGlass = data.readBoolean(); TeamsManager.vehiclesNeedFuel = data.readBoolean(); TeamsManager.driveablesBreakBlocks = data.readBoolean(); gametype = readUTF(data); if(gametype.equals("No Gametype")) { numTeams = 0; teamData = new TeamData[0]; } else { showZombieScore = data.readBoolean(); map = readUTF(data); mapShortName = readUTF(data); timeLeft = data.readInt(); scoreLimit = data.readInt(); sortedByTeam = data.readBoolean(); if(sortedByTeam) { numTeams = data.readInt(); numLines = 1; if(numTeams == 0) return; teamData = new TeamData[numTeams]; for(int i = 0; i < numTeams; i++) { teamData[i] = new TeamData(); String teamName = readUTF(data); if(teamName.equals("none")) continue; teamData[i].team = Team.getTeam(teamName); teamData[i].score = data.readInt(); teamData[i].winner = data.readBoolean(); teamData[i].numPlayers = data.readInt(); teamData[i].playerData = new PlayerScoreData[teamData[i].numPlayers]; if(teamData[i].numPlayers > numLines) numLines = teamData[i].numPlayers; for(int j = 0; j < teamData[i].numPlayers; j++) { teamData[i].playerData[j] = new PlayerScoreData(); teamData[i].playerData[j].team = teamData[i]; teamData[i].playerData[j].username = readUTF(data); teamData[i].playerData[j].level = data.readInt(); teamData[i].playerData[j].score = data.readInt(); teamData[i].playerData[j].zombieScore = data.readInt(); teamData[i].playerData[j].kills = data.readInt(); teamData[i].playerData[j].deaths = data.readInt(); teamData[i].playerData[j].playerClass = PlayerClass.getClass(readUTF(data)); } } } else { numLines = 0; teamData = new TeamData[]{new TeamData()}; teamData[0].team = null; teamData[0].score = 0; teamData[0].numPlayers = data.readInt(); teamData[0].playerData = new PlayerScoreData[teamData[0].numPlayers]; numLines += teamData[0].numPlayers; for(int j = 0; j < teamData[0].numPlayers; j++) { teamData[0].playerData[j] = new PlayerScoreData(); teamData[0].playerData[j].team = teamData[0]; teamData[0].playerData[j].username = readUTF(data); teamData[0].playerData[j].level = data.readInt(); teamData[0].playerData[j].score = data.readInt(); teamData[0].playerData[j].kills = data.readInt(); teamData[0].playerData[j].deaths = data.readInt(); teamData[0].playerData[j].playerClass = PlayerClass.getClass(readUTF(data)); } } } } catch(Exception e) { FlansMod.Assert(false, "Messed up in teams packet"); FlansMod.log.throwing(e); teamData = new TeamData[]{new TeamData()}; } finally { data.release(); } } @Override public void handleServerSide(EntityPlayerMP playerEntity) { } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { FlansModClient.teamInfo = this; } public Team getTeam(int spawnerTeamID) { switch(spawnerTeamID) { case 0: return null; case 1: return Team.spectators; default: return teamData.length > spawnerTeamID - 2 && teamData[spawnerTeamID - 2] != null ? teamData[spawnerTeamID - 2].team : null; } } public Team getTeam(EntityPlayer player) { for(TeamData aTeamData : teamData) { for(int j = 0; j < aTeamData.playerData.length; j++) { if(aTeamData.playerData[j].username.equals(player.getDisplayNameString())) { return aTeamData.team; } } } return null; } public boolean roundOver() { if(timeLeft == 0) return true; for(TeamData aTeamData : teamData) { if(aTeamData.score == scoreLimit) return true; } return false; } public Team getWinner() { for(TeamData aTeamData : teamData) { if(aTeamData.winner) return aTeamData.team; } return null; } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketTeamSelect.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.gui.teams.GuiTeamSelect; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.PlayerClass; import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; public class PacketTeamSelect extends PacketBase { public boolean selectionPacket = false; public String selection; public boolean classChoicesPacket = false; public Team[] teams; public PlayerClass[] playerClasses; /** * If true, then this packet simply updates the available choices, rather than forcing the player to choose */ public boolean info = false; public PacketTeamSelect() { } public PacketTeamSelect(Team[] t, boolean i) { selectionPacket = false; classChoicesPacket = false; teams = t; info = i; } public PacketTeamSelect(Team[] t) { this(t, false); } public PacketTeamSelect(PlayerClass[] c) { selectionPacket = false; classChoicesPacket = true; playerClasses = c; } public PacketTeamSelect(String shortName, boolean classPacket) { selectionPacket = true; classChoicesPacket = classPacket; selection = shortName; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeBoolean(selectionPacket); data.writeBoolean(classChoicesPacket); data.writeBoolean(info); //If it is a selection packet, then we need only send the selection if(selectionPacket) { writeUTF(data, selection); } //Otherwise, we must send the full list of teams or classes on offer else { if(classChoicesPacket) { data.writeByte(playerClasses.length); for(PlayerClass playerClass : playerClasses) { writeUTF(data, playerClass.shortName); } } else { data.writeByte(teams.length); for(Team team : teams) { writeUTF(data, team == null ? "null" : team.shortName); } } } } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { selectionPacket = data.readBoolean(); classChoicesPacket = data.readBoolean(); info = data.readBoolean(); if(selectionPacket) { selection = readUTF(data); } else { if(classChoicesPacket) { byte numClasses = data.readByte(); playerClasses = new PlayerClass[numClasses]; for(int i = 0; i < numClasses; i++) { playerClasses[i] = PlayerClass.getClass(readUTF(data)); } } else { byte numTeams = data.readByte(); teams = new Team[numTeams]; for(int i = 0; i < numTeams; i++) { teams[i] = Team.getTeam(readUTF(data)); } } } } /** * Handle player responses to team / class selection packets */ @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(!selectionPacket) { FlansMod.log.warn("Class / Team listing packet received on server. Rejecting."); return; } if(classChoicesPacket) { TeamsManager.getInstance().playerSelectedClass(playerEntity, selection); } else { TeamsManager.getInstance().playerSelectedTeam(playerEntity, selection); } } /** * Handle a request from the server to display a team / class selection window */ @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { if(selectionPacket) { FlansMod.log.warn("Class / Team selection packet received on client. Rejecting."); return; } if(classChoicesPacket) { Minecraft.getMinecraft().displayGuiScreen(new GuiTeamSelect(playerClasses)); } else if(info) { GuiTeamSelect.teamChoices = teams; } else Minecraft.getMinecraft().displayGuiScreen(new GuiTeamSelect(teams)); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketVehicleControl.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import com.flansmod.common.FlansMod; import com.flansmod.common.driveables.EntityDriveable; import com.flansmod.common.driveables.EntityVehicle; public class PacketVehicleControl extends PacketDriveableControl { public boolean doors; public PacketVehicleControl() { } public PacketVehicleControl(EntityDriveable driveable) { super(driveable); EntityVehicle vehicle = (EntityVehicle)driveable; doors = vehicle.varDoor; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.encodeInto(ctx, data); data.writeBoolean(doors); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { super.decodeInto(ctx, data); doors = data.readBoolean(); data.release(); } @Override protected void updateDriveable(EntityDriveable driveable, boolean clientSide) { super.updateDriveable(driveable, clientSide); EntityVehicle vehicle = (EntityVehicle)driveable; vehicle.varDoor = doors; if(!clientSide) { FlansMod.getPacketHandler().sendToAllAround(new PacketVehicleControl(vehicle), posX, posY, posZ, FlansMod.driveableUpdateRange, vehicle.dimension); } } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketVoteCast.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.teams.TeamsManager; public class PacketVoteCast extends PacketBase { public int vote; public PacketVoteCast() { } public PacketVoteCast(int vote) { this.vote = vote; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { data.writeByte(vote); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { vote = data.readByte(); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { if(vote < 0 || vote > TeamsManager.getInstance().voteOptions.length) { FlansMod.log.warn("Invalid vote " + vote + " from " + playerEntity.getName()); return; } PlayerData data = PlayerHandler.getPlayerData(playerEntity, Side.SERVER); data.vote = vote; } @Override public void handleClientSide(EntityPlayer clientPlayer) { FlansMod.log.warn("Received vote cast packet on client. Skipping."); } } ================================================ FILE: src/main/java/com/flansmod/common/network/PacketVoting.java ================================================ package com.flansmod.common.network; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.teams.ClientTeamsData; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.RoundFinishedData; public class PacketVoting extends PacketBase { public RoundFinishedData roundFinishedData = new RoundFinishedData(); public PacketVoting() { } public PacketVoting(RoundFinishedData data) { roundFinishedData = data; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { roundFinishedData.WriteNumVotesUpdate(data); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { roundFinishedData.ReadNumVotesUpdate(data); } @Override public void handleServerSide(EntityPlayerMP playerEntity) { FlansMod.log.warn("Received vote info packet on server. Rejecting."); } @Override @SideOnly(Side.CLIENT) public void handleClientSide(EntityPlayer clientPlayer) { ClientTeamsData.UpdateNumVotes(roundFinishedData); } } ================================================ FILE: src/main/java/com/flansmod/common/paintjob/BlockPaintjobTable.java ================================================ package com.flansmod.common.paintjob; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryHelper; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import com.flansmod.common.FlansMod; public class BlockPaintjobTable extends BlockContainer { public BlockPaintjobTable() { super(Material.ROCK); setHardness(2F); setResistance(4F); setTranslationKey("paintjobTable"); setRegistryName("paintjobTable"); setCreativeTab(FlansMod.tabFlanGuns); } @Override public boolean canPlaceBlockAt(World world, BlockPos pos) { return world.getBlockState(pos.add(0, -1, 0)).isSideSolid(world, pos.add(0, -1, 0), EnumFacing.UP); } @Override public TileEntity createNewTileEntity(World world, int i) { return new TileEntityPaintjobTable(); } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float par7, float par8, float par9) { if(world.isRemote) { FlansMod.playerHandler.getPlayerData(player, Side.CLIENT).shootTimeLeft = FlansMod.playerHandler.getPlayerData(player, Side.CLIENT).shootTimeRight = 10; return true; } TileEntityPaintjobTable table = (TileEntityPaintjobTable)world.getTileEntity(pos); if(!world.isRemote) { player.openGui(FlansMod.INSTANCE, 13, world, pos.getX(), pos.getY(), pos.getZ()); } return true; } @Override public void breakBlock(World worldIn, BlockPos pos, IBlockState state) { TileEntity tileentity = worldIn.getTileEntity(pos); if(tileentity instanceof IInventory) { InventoryHelper.dropInventoryItems(worldIn, pos, (IInventory)tileentity); worldIn.updateComparatorOutputLevel(pos, this); } super.breakBlock(worldIn, pos, state); } } ================================================ FILE: src/main/java/com/flansmod/common/paintjob/ContainerPaintjobTable.java ================================================ package com.flansmod.common.paintjob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.Container; import net.minecraft.inventory.Slot; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.common.guns.Paintjob; public class ContainerPaintjobTable extends Container { public InventoryPlayer playerInv; public TileEntityPaintjobTable table; public World world; public ContainerPaintjobTable(InventoryPlayer i, World w, TileEntityPaintjobTable te) { playerInv = i; world = w; table = te; // Gun slot addSlotToContainer(new Slot(table, 0, 187, 139)); // Paint cans slot addSlotToContainer(new Slot(table, 1, 187, 193)); // Main inventory slots for(int row = 0; row < 3; row++) { for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(playerInv, col + row * 9 + 9, 8 + col * 18, 184 + row * 18)); } } // Quickbar slots for(int col = 0; col < 9; col++) { addSlotToContainer(new Slot(playerInv, col, 8 + col * 18, 242)); } } @Override public void onContainerClosed(EntityPlayer player) { // Save out paintjob? } @Override public boolean canInteractWith(EntityPlayer entityplayer) { return true; } @Override public ItemStack transferStackInSlot(EntityPlayer player, int slotID) { ItemStack stack = ItemStack.EMPTY.copy(); Slot currentSlot = inventorySlots.get(slotID); if(currentSlot != null && currentSlot.getHasStack()) { ItemStack slotStack = currentSlot.getStack(); stack = slotStack.copy(); if(slotID >= 1) { return ItemStack.EMPTY.copy(); } else { if(!mergeItemStack(slotStack, 1, inventorySlots.size(), true)) { return ItemStack.EMPTY.copy(); } } if(slotStack.getCount() == 0) { currentSlot.putStack(ItemStack.EMPTY.copy()); } else { currentSlot.onSlotChanged(); } if(slotStack.getCount() == stack.getCount()) { return ItemStack.EMPTY.copy(); } currentSlot.onTake(player, slotStack); } return stack; } public void pressButton(boolean paint, boolean left) { //Nope. } public void clickPaintjob(int i) { ItemStack paintableStack = table.getPaintableStack(); if(paintableStack != null && paintableStack.getItem() instanceof IPaintableItem) { PaintableType paintableType = ((IPaintableItem)paintableStack.getItem()).GetPaintableType(); clickPaintjob(paintableType.getPaintjob(i)); } } public void clickPaintjob(Paintjob paintjob) { ItemStack paintableStack = table.getPaintableStack(); if(paintableStack != null && paintableStack.getItem() instanceof IPaintableItem) { PaintableType paintableType = ((IPaintableItem)paintableStack.getItem()).GetPaintableType(); int numDyes = paintjob.dyesNeeded.length; if(!playerInv.player.capabilities.isCreativeMode) { //Calculate which dyes we have in our inventory for(int n = 0; n < numDyes; n++) { int amountNeeded = paintjob.dyesNeeded[n].getCount(); for(int s = 0; s < playerInv.getSizeInventory(); s++) { ItemStack stack = playerInv.getStackInSlot(s); if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == paintjob.dyesNeeded[n].getItemDamage()) { amountNeeded -= stack.getCount(); } } //We don't have enough of this dye if(amountNeeded > 0) return; } for(int n = 0; n < numDyes; n++) { int amountNeeded = paintjob.dyesNeeded[n].getCount(); for(int s = 0; s < playerInv.getSizeInventory(); s++) { if(amountNeeded <= 0) continue; ItemStack stack = playerInv.getStackInSlot(s); if(stack != null && stack.getItem() == Items.DYE && stack.getItemDamage() == paintjob.dyesNeeded[n].getItemDamage()) { ItemStack consumed = playerInv.decrStackSize(s, amountNeeded); amountNeeded -= consumed.getCount(); } } } } //Paint the gun. This line is only reached if the player is in creative or they have had their dyes taken already //gunStack.getTagCompound().setString("Paint", paintjob.iconName); paintableStack.setItemDamage(paintjob.ID); } } } ================================================ FILE: src/main/java/com/flansmod/common/paintjob/IPaintableItem.java ================================================ package com.flansmod.common.paintjob; import com.flansmod.common.types.IFlanItem; public interface IPaintableItem extends IFlanItem { PaintableType GetPaintableType(); } ================================================ FILE: src/main/java/com/flansmod/common/paintjob/PaintableType.java ================================================ package com.flansmod.common.paintjob; import java.util.ArrayList; import java.util.HashMap; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.LootEntry; import net.minecraft.world.storage.loot.LootEntryItem; import net.minecraft.world.storage.loot.LootPool; import net.minecraft.world.storage.loot.RandomValueRange; import net.minecraft.world.storage.loot.conditions.LootCondition; import net.minecraft.world.storage.loot.functions.LootFunction; import net.minecraft.world.storage.loot.functions.SetDamage; import net.minecraftforge.event.LootTableLoadEvent; import com.flansmod.client.handlers.FlansModResourceHandler; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.Paintjob; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public abstract class PaintableType extends InfoType { //Paintjobs /** * The list of all available paintjobs for this gun */ public ArrayList paintjobs = new ArrayList<>(); public ArrayList nonlegendarypaintjobs = new ArrayList<>(); /** * The default paintjob for this gun. This is created automatically in the load process from existing info */ public Paintjob defaultPaintjob; /** * Assigns IDs to paintjobs */ private int nextPaintjobID = 1; private static HashMap paintableTypes = new HashMap<>(); public static PaintableType GetPaintableType(int iHash) { return paintableTypes.get(iHash); } public static PaintableType GetPaintableType(String name) { return paintableTypes.get(name.hashCode()); } public PaintableType(TypeFile file) { super(file); } @Override public void postRead(TypeFile file) { super.postRead(file); //After all lines have been read, set up the default paintjob defaultPaintjob = new Paintjob(this, 0, "", texture, new ItemStack[0]); //Move to a new list to ensure that the default paintjob is always first ArrayList newPaintjobList = new ArrayList<>(); newPaintjobList.add(defaultPaintjob); newPaintjobList.addAll(paintjobs); paintjobs = newPaintjobList; if(infoTypes.containsKey(shortName.hashCode())) { FlansMod.Assert(false, "Duplicate info type name " + shortName); } nonlegendarypaintjobs.clear(); for(Paintjob p : paintjobs) { if(!p.IsLegendary()) nonlegendarypaintjobs.add(p); } // Add all custom paintjobs to dungeon loot. Equal chance for each totalDungeonChance += dungeonChance * (nonlegendarypaintjobs.size() - 1); paintableTypes.put(shortName.hashCode(), this); } /** * Pack reader */ protected void read(String[] split, TypeFile file) { super.read(split, file); try { //Paintjobs if(KeyMatches(split, "Paintjob")) { ItemStack[] dyeStacks = new ItemStack[(split.length - 3) / 2]; for(int i = 0; i < (split.length - 3) / 2; i++) { if(split[i * 2 + 3].equals("rainbow")) dyeStacks[i] = new ItemStack(FlansMod.rainbowPaintcan, Integer.parseInt(split[i * 2 + 4])); else dyeStacks[i] = new ItemStack(Items.DYE, Integer.parseInt(split[i * 2 + 4]), getDyeDamageValue(split[i * 2 + 3])); } if(split[1].contains("_")) { int indexOf_ = split[1].indexOf('_'); if(indexOf_ != -1 && split[1].toLowerCase().startsWith(iconPath.toLowerCase())) { split[1] = split[1].substring(indexOf_ + 1); } } paintjobs.add(new Paintjob(this, nextPaintjobID++, split[1], split[2], dyeStacks)); } } catch(Exception e) { FlansMod.log.error("Reading file failed : " + shortName); FlansMod.log.throwing(e); } } public Paintjob getPaintjob(String s) { for(Paintjob paintjob : paintjobs) { if(paintjob.textureName.equals(s)) return paintjob; if(paintjob.iconName.equals(s)) { FlansMod.Assert(false, "Not sure this should be the right way to find a paintjob"); return paintjob; } } FlansMod.Assert(false, "Could not find paintjob " + s); return defaultPaintjob; } public Paintjob getPaintjob(int i) { if(0 <= i && i < paintjobs.size()) return paintjobs.get(i); return defaultPaintjob; } @Override public void addLoot(LootTableLoadEvent event) { if(dungeonChance > 0) { LootPool pool = event.getTable().getPool("FlansMod"); if(pool == null) { pool = new LootPool(new LootEntry[0], new LootCondition[0], new RandomValueRange(1, 1), new RandomValueRange(1, 1), "FlansMod"); event.getTable().addPool(pool); } if(pool != null) { LootEntry entry = new LootEntryItem( item, FlansMod.dungeonLootChance * dungeonChance, 1, new LootFunction[] { new SetDamage(new LootCondition[0], new RandomValueRange(0, nonlegendarypaintjobs.size() - 1)) }, new LootCondition[0], shortName); pool.addEntry(entry); } } } public float GetRecommendedScale() { return 50.0f; } public static boolean HasCustomPaintjob(ItemStack stack) { if(stack == null || stack.isEmpty()) { return false; } if(stack.getItem() instanceof IPaintableItem) { return stack.getTagCompound().hasKey("CustomPaint"); } return false; } public static ResourceLocation GetCustomPaintjobSkinResource(ItemStack stack) { NBTTagCompound tags = stack.getTagCompound().getCompoundTag("CustomPaint"); int customPaintHash = tags.getInteger("Hash"); if(!FlansModResourceHandler.HasResourceForHash(customPaintHash)) { FlansModResourceHandler.CreateSkinResourceFromByteArray(tags.getByteArray("Skin"), tags.getInteger("SkinWidth"), tags.getInteger("SkinHeight"), customPaintHash); FlansModResourceHandler.CreateIconResourceFromByteArray(tags.getByteArray("Icon"), tags.getInteger("IconWidth"), tags.getInteger("IconHeight"), customPaintHash); } return FlansModResourceHandler.GetSkinResourceFromHash(customPaintHash); } public static ResourceLocation GetCustomPaintjobIconResource(ItemStack stack) { NBTTagCompound tags = stack.getTagCompound().getCompoundTag("CustomPaint"); int customPaintHash = tags.getInteger("Hash"); if(!FlansModResourceHandler.HasResourceForHash(customPaintHash)) { FlansModResourceHandler.CreateSkinResourceFromByteArray(tags.getByteArray("Skin"), tags.getInteger("SkinWidth"), tags.getInteger("SkinHeight"), customPaintHash); FlansModResourceHandler.CreateIconResourceFromByteArray(tags.getByteArray("Icon"), tags.getInteger("IconWidth"), tags.getInteger("IconHeight"), customPaintHash); } return FlansModResourceHandler.GetIconResourceFromHash(customPaintHash); } } ================================================ FILE: src/main/java/com/flansmod/common/paintjob/TileEntityPaintjobTable.java ================================================ package com.flansmod.common.paintjob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ITickable; import net.minecraft.util.text.ITextComponent; public class TileEntityPaintjobTable extends TileEntity implements IInventory, ITickable { // Stack 0 is InfoType being painted. Stack 1 is paint cans private ItemStack inventoryStacks[] = new ItemStack[2]; //private CustomPaintjob inProgressPaintjob; public TileEntityPaintjobTable() { } @Override public String getName() { return "PaintjobTable"; } @Override public boolean hasCustomName() { return false; } @Override public int getSizeInventory() { return 2; } @Override public ItemStack getStackInSlot(int index) { return inventoryStacks[index]; } @Override public ItemStack decrStackSize(int index, int count) { if(getStackInSlot(index) != null) { if(count >= getStackInSlot(index).getCount()) { ItemStack returnStack = getStackInSlot(index); setInventorySlotContents(index, null); return returnStack; } else { return getStackInSlot(index).splitStack(count); } } return null; } @Override public void setInventorySlotContents(int index, ItemStack stack) { inventoryStacks[index] = stack; } @Override public int getInventoryStackLimit() { return 64; } @Override public void openInventory(EntityPlayer player) { } @Override public void closeInventory(EntityPlayer player) { } @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return true; } @Override public int getField(int id) { return 0; } @Override public void setField(int id, int value) { } @Override public int getFieldCount() { return 0; } @Override public void clear() { for(int i = 0; i < getSizeInventory(); i++) { setInventorySlotContents(i, null); } } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); for(int i = 0; i < inventoryStacks.length; i++) { NBTTagCompound stackNBT = new NBTTagCompound(); if(getStackInSlot(i) != null) getStackInSlot(i).writeToNBT(stackNBT); nbt.setTag("stack_" + i, stackNBT); } return nbt; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); for(int i = 0; i < inventoryStacks.length; i++) { setInventorySlotContents(i, new ItemStack(nbt.getCompoundTag("stack_" + i))); } } @Override public void update() { } @Override public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound nbt = new NBTTagCompound(); writeToNBT(nbt); return new SPacketUpdateTileEntity(getPos(), getBlockMetadata(), nbt); } @Override public void onDataPacket(net.minecraft.network.NetworkManager net, SPacketUpdateTileEntity packet) { readFromNBT(packet.getNbtCompound()); } public ItemStack getPaintableStack() { return inventoryStacks[0]; } public void setPaintableStack(ItemStack stack) { inventoryStacks[0] = stack; } public ItemStack getPaintCans() { return inventoryStacks[1]; } @Override public ITextComponent getDisplayName() { return null; } @Override public boolean isEmpty() { return inventoryStacks[0] == null || inventoryStacks[0].isEmpty(); } @Override public ItemStack removeStackFromSlot(int index) { ItemStack stack = inventoryStacks[index]; inventoryStacks[index] = null; return stack; } @Override public boolean isUsableByPlayer(EntityPlayer player) { return true; } } ================================================ FILE: src/main/java/com/flansmod/common/parts/EnumPartCategory.java ================================================ package com.flansmod.common.parts; public enum EnumPartCategory { COCKPIT, WING, ENGINE, PROPELLER, BAY, TAIL, WHEEL, CHASSIS, TURRET, FUEL, MISC } ================================================ FILE: src/main/java/com/flansmod/common/parts/ItemPart.java ================================================ package com.flansmod.common.parts; import java.util.List; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import com.flansmod.common.FlansMod; import com.flansmod.common.types.IFlanItem; import com.flansmod.common.types.InfoType; public class ItemPart extends Item implements IFlanItem { public PartType type; public ItemPart(PartType type1) { super(); type = type1; setMaxStackSize(type.stackSize); if(type.category == EnumPartCategory.FUEL) { setMaxDamage(type.fuel); setHasSubtypes(true); } type.item = this; setTranslationKey("FlansMod:" + type.iconPath); setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanParts); } @Override public void addInformation(ItemStack stack, World world, List lines, ITooltipFlag b) { if(type.category == EnumPartCategory.FUEL) { lines.add("Fuel Stored: " + (type.fuel - stack.getItemDamage()) + " / " + type.fuel); } } @Override public InfoType getInfoType() { return type; } } ================================================ FILE: src/main/java/com/flansmod/common/parts/PartType.java ================================================ package com.flansmod.common.parts; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import net.minecraft.client.model.ModelBase; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.common.FlansMod; import com.flansmod.common.types.EnumType; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class PartType extends InfoType { /** * Category */ public EnumPartCategory category; /** * Max stack size of item */ public int stackSize; /** * (Engine) Multiplier applied to the thrust of the driveable */ public float engineSpeed = 1.0F; /** * (Engine) Rate at which this engine consumes fuel */ public float fuelConsumption = 1.0F; /** * (Fuel) The amount of fuel this fuel tank gives */ public int fuel = 0; /** * The types of driveables that this engine works with. Used to designate some engines as mecha CPUs and whatnot */ public List worksWith = Arrays.asList(EnumType.mecha, EnumType.plane, EnumType.vehicle); /** * Let's just say you probably don't want to use this to power a mecha... */ public boolean isAIChip = false; /** * If set to false, then this engine will definitely not be the default for creatively spawned vehicles */ public boolean canBeDefaultEngine = true; public ArrayList partBoxRecipe = new ArrayList<>(); //------- RedstoneFlux ------- /** * If true, then this engine will draw from RedstoneFlux power source items such as power cubes. Otherwise it will draw from Flan's Mod fuel items */ public boolean useRFPower = false; /** * The power draw rate for RF (per tick) */ public int RFDrawRate = 1; //----------------------------- /** * The default engine (normally the first one read by the type loader) for driveables with corrupt nbt or those spawned in creative */ public static HashMap defaultEngines = new HashMap<>(); /** * The list of all PartTypes */ public static List parts = new ArrayList<>(); /** * Hash map sorted */ public static HashMap> partsByCategory = new HashMap<>(); static { for(EnumPartCategory cat : EnumPartCategory.values()) partsByCategory.put(cat, new ArrayList<>()); } public PartType(TypeFile file) { super(file); parts.add(this); } @Override public void postRead(TypeFile file) { if(category == EnumPartCategory.ENGINE && !useRFPower && canBeDefaultEngine) { for(EnumType type : worksWith) { //If there is already a default engine for this type, compare and see if this one is better if(defaultEngines.containsKey(type)) { PartType possiblyInferiorEngine = defaultEngines.get(type); if(isInferiorEngine(possiblyInferiorEngine)) defaultEngines.put(type, this); } else defaultEngines.put(type, this); } } partsByCategory.get(category).add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(split[0].equals("Category")) category = getCategory(split[1]); else if(split[0].equals("StackSize")) stackSize = Integer.parseInt(split[1]); else if(split[0].equals("EngineSpeed")) engineSpeed = Float.parseFloat(split[1]); else if(split[0].equals("FuelConsumption")) fuelConsumption = Float.parseFloat(split[1]); else if(split[0].equals("Fuel")) fuel = Integer.parseInt(split[1]); //Recipe else if(split[0].equals("PartBoxRecipe")) { ItemStack[] stacks = new ItemStack[(split.length - 2) / 2]; for(int i = 0; i < (split.length - 2) / 2; i++) { int amount = Integer.parseInt(split[2 * i + 2]); boolean damaged = split[2 * i + 3].contains("."); String itemName = damaged ? split[2 * i + 3].split("\\.")[0] : split[2 * i + 3]; int damage = damaged ? Integer.parseInt(split[2 * i + 3].split("\\.")[1]) : 0; stacks[i] = getRecipeElement(itemName, amount, damage); } partBoxRecipe.addAll(Arrays.asList(stacks)); } else if(split[0].equals("WorksWith")) { worksWith = new ArrayList<>(); for(int i = 0; i < split.length - 1; i++) { worksWith.add(EnumType.get(split[i + 1])); } } //------- RedstoneFlux ------- else if(split[0].equals("UseRF") || split[0].equals("UseRFPower")) useRFPower = Boolean.parseBoolean(split[1]); else if(split[0].equals("RFDrawRate")) RFDrawRate = Integer.parseInt(split[1]); //----------------------------- else if(split[0].equals("IsAIChip")) isAIChip = Boolean.parseBoolean(split[1]); else if(split[0].equals("CanBeDefaultEngine")) canBeDefaultEngine = Boolean.parseBoolean(split[1]); } catch(Exception e) { FlansMod.log.error("Reading part file failed."); FlansMod.log.throwing(e); } } public boolean isInferiorEngine(PartType quitePossiblyAnInferiorEngine) { return engineSpeed > quitePossiblyAnInferiorEngine.engineSpeed; } public static PartType getPart(String s) { for(PartType part : parts) { if(part.shortName.equals(s)) return part; } return null; } private EnumPartCategory getCategory(String s) { if(s.equals("Cockpit")) return EnumPartCategory.COCKPIT; if(s.equals("Wing")) return EnumPartCategory.WING; if(s.equals("Engine")) return EnumPartCategory.ENGINE; if(s.equals("Propeller")) return EnumPartCategory.PROPELLER; if(s.equals("Bay")) return EnumPartCategory.BAY; if(s.equals("Tail")) return EnumPartCategory.TAIL; if(s.equals("Wheel")) return EnumPartCategory.WHEEL; if(s.equals("Chassis")) return EnumPartCategory.CHASSIS; if(s.equals("Turret")) return EnumPartCategory.TURRET; if(s.equals("Fuel")) return EnumPartCategory.FUEL; if(s.equals("Misc")) return EnumPartCategory.MISC; return EnumPartCategory.MISC; } @Override protected void preRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return null; } } ================================================ FILE: src/main/java/com/flansmod/common/teams/ArmourBoxType.java ================================================ package com.flansmod.common.teams; import java.util.ArrayList; import java.util.HashMap; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraftforge.registries.IForgeRegistry; import com.flansmod.common.FlansMod; import com.flansmod.common.guns.boxes.BoxType; import com.flansmod.common.types.TypeFile; public class ArmourBoxType extends BoxType { public BlockArmourBox block; public ArrayList pages = new ArrayList<>(); /** * The static box map. Indexed by shortName for server ~ client syncing */ public static HashMap boxes = new HashMap<>(); public ArmourBoxType(TypeFile file) { super(file); } @Override public void postRead(TypeFile file) { super.postRead(file); boxes.put(shortName, this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(split[0].toLowerCase().equals("addarmour") || split[0].toLowerCase().equals("addarmor")) { String name = split[2]; for(int i = 3; i < split.length; i++) name = name + " " + split[i]; ArmourBoxEntry entry = new ArmourBoxEntry(split[1], name); //Read the next 4 lines for each armour piece for(int i = 0; i < 4; i++) { String line = null; line = file.readLine(); if(line == null) continue; if(line.startsWith("//")) { i--; continue; } String[] lineSplit = line.split(" "); entry.armours[i] = ArmourType.getArmourType(lineSplit[0]); for(int j = 0; j < (lineSplit.length - 1) / 2; j++) { ItemStack stack = ItemStack.EMPTY.copy(); if(lineSplit[j * 2 + 1].contains(".")) stack = getRecipeElement(lineSplit[j * 2 + 1].split("\\.")[0], Integer.valueOf(lineSplit[j * 2 + 2]), Integer.valueOf(lineSplit[j * 2 + 1].split("\\.")[1])); else stack = getRecipeElement(lineSplit[j * 2 + 1], Integer.valueOf(lineSplit[j * 2 + 2]), 0); if(stack != null && !stack.isEmpty()) entry.requiredStacks[i].add(stack); } } pages.add(entry); } } catch(Exception e) { FlansMod.log.error("Reading gun box file failed : " + shortName); FlansMod.log.throwing(e); } } @Override public void registerItem(IForgeRegistry registry) { item = new ItemBlock(block).setRegistryName(shortName + "_item"); registry.register(item); } @Override public void registerBlock(IForgeRegistry registry) { registry.register(block); } /** * Each instance of this class refers to one page full of recipes, that is, one full set of armour */ public class ArmourBoxEntry { public String shortName; public String name = ""; public ArmourType[] armours; public ArrayList[] requiredStacks; public ArmourBoxEntry(String s, String s1) { shortName = s; name = s1; //Prep arrays and lists armours = new ArmourType[4]; requiredStacks = new ArrayList[4]; for(int i = 0; i < 4; i++) requiredStacks[i] = new ArrayList<>(); } } public static ArmourBoxType getBox(String boxShortName) { return boxes.get(boxShortName); } } ================================================ FILE: src/main/java/com/flansmod/common/teams/ArmourType.java ================================================ package com.flansmod.common.teams; import java.util.ArrayList; import net.minecraft.client.model.ModelBase; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.client.model.ModelCustomArmour; import com.flansmod.common.FlansMod; import com.flansmod.common.types.InfoType; import com.flansmod.common.types.TypeFile; public class ArmourType extends InfoType { public static ArrayList armours = new ArrayList<>(); /** * 0 = Helmet, 1 = Chestplate, 2 = Legs, 3 = Shoes */ public int type; /** * The amount of damage to absorb. From 0 to 1. Stacks additively between armour pieces */ public double defence; public int DamageReductionAmount; // < 0 durability = infinite public int Durability; // Armour toughness, like diamond public int Toughness; // Enchantability, optional public int Enchantability = 10; /** * The name for the armour texture. Texture path/name is assets/flansmod/armor/_1.png or _2 for legs */ public String armourTextureName; /** * Modifiers for various player stats */ public float moveSpeedModifier = 1F, knockbackModifier = 0.2F, jumpModifier = 1F; /** * If true, then the player gets a night vision buff every couple of seconds */ public boolean nightVision = false; /** * The overlay to display when using this helmet. Textures are pulled from the scopes directory */ public String overlay = null; /** * If true, then smoke effects from grenades will have no effect on players wearing this */ public boolean smokeProtection = false; /** * If ture, the player will not receive fall damage */ public boolean negateFallDamage = false; @SideOnly(Side.CLIENT) public ModelCustomArmour model; public ArmourType(TypeFile file) { super(file); armours.add(this); } @Override protected void read(String[] split, TypeFile file) { super.read(split, file); try { if(FMLCommonHandler.instance().getSide().isClient() && split[0].equals("Model")) { model = FlansMod.proxy.loadModel(split[1], shortName, ModelCustomArmour.class); model.type = this; } if(split[0].equals("Type")) { if(split[1].equals("Hat") || split[1].equals("Helmet")) type = 0; if(split[1].equals("Chest") || split[1].equals("Body")) type = 1; if(split[1].equals("Legs") || split[1].equals("Pants")) type = 2; if(split[1].equals("Shoes") || split[1].equals("Boots")) type = 3; } defence = Read(split, "DamageReduction", defence); defence = Read(split, "Defence", defence); moveSpeedModifier = Read(split, "MoveSpeedModifier", moveSpeedModifier); moveSpeedModifier = Read(split, "Slowness", moveSpeedModifier); jumpModifier = Read(split, "JumpModifier", jumpModifier); knockbackModifier = Read(split, "KnockbackReduction", knockbackModifier); knockbackModifier = Read(split, "KnockbackModifier", knockbackModifier); nightVision = Read(split, "NightVision", nightVision); negateFallDamage = Read(split, "NegateFallDamage", negateFallDamage); overlay = Read(split, "Overlay", overlay); smokeProtection = Read(split, "SmokeProtection", smokeProtection); armourTextureName = Read(split, "ArmourTexture", armourTextureName); armourTextureName = Read(split, "ArmorTexture", armourTextureName); Enchantability = Read(split, "Enchantability", Enchantability); Toughness = Read(split, "Toughness", Toughness); Durability = Read(split, "Durability", Durability); DamageReductionAmount = Read(split, "DamageReductionAmount", DamageReductionAmount); } catch(Exception e) { FlansMod.log.error("Reading armour file failed."); FlansMod.log.throwing(e); } } public static ArmourType getArmourType(String string) { for(ArmourType armour : armours) { if(armour.shortName.equals(string)) return armour; } return null; } /** * To be overriden by subtypes for model reloading */ public void reloadModel() { model = FlansMod.proxy.loadModel(modelString, shortName, ModelCustomArmour.class); if(model != null) model.type = this; } @Override protected void preRead(TypeFile file) { } @Override protected void postRead(TypeFile file) { } @Override @SideOnly(Side.CLIENT) public ModelBase GetModel() { return model; } } ================================================ FILE: src/main/java/com/flansmod/common/teams/BlockArmourBox.java ================================================ package com.flansmod.common.teams; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; import com.flansmod.common.CraftingInstance; import com.flansmod.common.FlansMod; import com.flansmod.common.teams.ArmourBoxType.ArmourBoxEntry; public class BlockArmourBox extends Block { public ArmourBoxType type; public BlockArmourBox(ArmourBoxType t) { super(Material.WOOD); type = t; setTranslationKey(type.shortName); setHardness(2F); setResistance(4F); setRegistryName(type.shortName); setCreativeTab(FlansMod.tabFlanTeams); type.block = this; //type.item = Item.getItemFromBlock(this); } public void buyArmour(String shortName, int piece, InventoryPlayer inventory) { if(FMLCommonHandler.instance().getEffectiveSide().isClient()) { FlansMod.proxy.buyArmour(shortName, piece, type); } ArmourBoxEntry entryPicked = null; for(ArmourBoxEntry page : type.pages) { if(page.shortName.equals(shortName)) entryPicked = page; } ItemStack resultStack = new ItemStack(entryPicked.armours[piece].item); CraftingInstance crafting = new CraftingInstance(inventory, entryPicked.requiredStacks[piece], resultStack); if(crafting.canCraft()) { crafting.craft(inventory.player); } } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer entityplayer, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { if(entityplayer.isSneaking()) return false; entityplayer.openGui(FlansMod.INSTANCE, 11, world, pos.getX(), pos.getY(), pos.getZ()); return true; } } ================================================ FILE: src/main/java/com/flansmod/common/teams/BlockSpawner.java ================================================ package com.flansmod.common.teams; import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.block.properties.PropertyInteger; import net.minecraft.block.state.BlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentString; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; import com.flansmod.common.FlansMod; public class BlockSpawner extends BlockContainer { protected static final AxisAlignedBB CARPET_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D); public static final PropertyInteger TYPE = PropertyInteger.create("type", 0, 2); public static boolean colouredPass = false; public BlockSpawner(Material material) { super(material); setCreativeTab(FlansMod.tabFlanTeams); setRegistryName("teamsSpawner"); setDefaultState(blockState.getBaseState().withProperty(TYPE, 0)); } @Override public void getSubBlocks(CreativeTabs tab, NonNullList list) { if(tab == FlansMod.tabFlanTeams) { list.add(new ItemStack(this, 1, 0)); list.add(new ItemStack(this, 1, 1)); list.add(new ItemStack(this, 1, 2)); } } @Override public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { return CARPET_AABB; } @Override public boolean isOpaqueCube(IBlockState state) { return false; } @Override public boolean isFullCube(IBlockState state) { return false; } @Override public boolean canPlaceBlockAt(World world, BlockPos pos) { return world.getBlockState(pos.add(0, -1, 0)).isSideSolid(world, pos.add(0, -1, 0), EnumFacing.UP); } @Override public TileEntity createNewTileEntity(World var1, int i) { return new TileEntitySpawner(); } @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float par7, float par8, float par9) { if(world.isRemote) return true; /* TODO : Check the generalised code in TeamsManager works if(TeamsManager.getInstance().currentGametype != null) TeamsManager.getInstance().currentGametype.objectClickedByPlayer((TileEntitySpawner)world.getTileEntity(x, y, z), (EntityPlayerMP)player); */ if(FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().canSendCommands(player.getGameProfile())) { TileEntitySpawner spawner = (TileEntitySpawner)world.getTileEntity(pos); ItemStack item = player.getHeldItemMainhand(); if(item == null || item.getItem() == null) { spawner.spawnDelay = (spawner.spawnDelay + 200) % 6000; player.sendMessage(new TextComponentString("Set spawn delay to " + spawner.spawnDelay / 20)); } else if(!(item.getItem() instanceof ItemOpStick)) { spawner.stacksToSpawn.add(item.copy()); for(Entity entity : spawner.itemEntities) { entity.setDead(); } spawner.currentDelay = 10; } } return true; } @Override protected BlockStateContainer createBlockState() { return new BlockStateContainer(this, TYPE); } @Override public IBlockState getStateFromMeta(int meta) { return this.getDefaultState().withProperty(TYPE, meta); } @Override public int getMetaFromState(IBlockState state) { return state.getValue(TYPE); } @Override public int damageDropped(IBlockState state) { return state.getValue(TYPE); } } ================================================ FILE: src/main/java/com/flansmod/common/teams/CommandTeams.java ================================================ package com.flansmod.common.teams; import com.mojang.authlib.GameProfile; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.server.MinecraftServer; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.FMLCommonHandler; import com.flansmod.common.FlansMod; public class CommandTeams extends CommandBase { public static TeamsManager teamsManager = TeamsManager.getInstance(); @Override public String getName() { return "teams"; } @Override public int getRequiredPermissionLevel() { return 4; } @Override public void execute(MinecraftServer server, ICommandSender sender, String[] split) throws CommandException { if(teamsManager == null) { sender.sendMessage(new TextComponentString("Teams mod is broken. You will need to look at the server side logs to see what's wrong")); return; } if(split == null || split.length == 0 || split[0].equals("help") || split[0].equals("?")) { if(split.length == 2) sendHelpInformation(sender, Integer.parseInt(split[1])); else sendHelpInformation(sender, 1); return; } //On / off if(split[0].equals("off")) { teamsManager.currentRound = null; teamsManager.enabled = false; TeamsManager.messageAll("Flan's Teams Mod disabled"); return; } if(split[0].equals("on")) { teamsManager.enabled = true; TeamsManager.messageAll("Flan's Teams Mod enabled"); return; } if(!teamsManager.enabled) { sender.sendMessage(new TextComponentString("Teams mod is disabled. Try /teams on")); return; } if(split[0].equals("survival")) { teamsManager.explosions = true; teamsManager.driveablesBreakBlocks = true; teamsManager.bombsEnabled = true; teamsManager.bulletsEnabled = true; teamsManager.forceAdventureMode = false; teamsManager.overrideHunger = false; teamsManager.canBreakGuns = true; teamsManager.canBreakGlass = true; teamsManager.armourDrops = true; teamsManager.weaponDrops = 1; teamsManager.vehiclesNeedFuel = true; teamsManager.mgLife = teamsManager.planeLife = teamsManager.vehicleLife = teamsManager.aaLife = teamsManager.mechaLove = 0; teamsManager.messageAll("Flan's Mod switching to survival presets"); return; } if(split[0].equals("arena")) { teamsManager.explosions = false; teamsManager.driveablesBreakBlocks = false; teamsManager.bombsEnabled = true; teamsManager.bulletsEnabled = true; teamsManager.forceAdventureMode = true; teamsManager.overrideHunger = true; teamsManager.canBreakGuns = true; teamsManager.canBreakGlass = false; teamsManager.armourDrops = false; teamsManager.weaponDrops = 2; teamsManager.vehiclesNeedFuel = false; teamsManager.mgLife = teamsManager.planeLife = teamsManager.vehicleLife = teamsManager.aaLife = teamsManager.mechaLove = 120; TeamsManager.messageAll("Flan's Mod switching to arena mode presets"); return; } if(split[0].equals("motd")) { teamsManager.motd = ""; for(int i = 0; i < split.length - 1; i++) { teamsManager.motd += split[i + 1]; if(i != split.length - 2) { teamsManager.motd += " "; } } sender.sendMessage(new TextComponentString("Server message of the day is now:")); sender.sendMessage(new TextComponentString(teamsManager.motd)); return; } if(split[0].equals("listGametypes")) { sender.sendMessage(new TextComponentString("\u00a72Showing all avaliable gametypes")); sender.sendMessage(new TextComponentString("\u00a72To pick a gametype, use \"/teams setGametype \" with the name in brackets")); for(Gametype gametype : Gametype.gametypes.values()) { sender.sendMessage(new TextComponentString("\u00a7f" + gametype.name + " (" + gametype.shortName + ")")); } return; } /* No longer used if(split[0].equals("setGametype")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("\u00a74To set the gametype, use \"/teams setGametype \" with a valid gametype.")); return; } if(split[1].toLowerCase().equals("none")) { if(teamsManager.currentGametype != null) teamsManager.currentGametype.stopGametype(); teamsManager.currentGametype = null; for(PlayerData data : PlayerHandler.serverSideData.values()) { if(data != null) data.team = null; } return; } Gametype gametype = Gametype.getGametype(split[1]); if(gametype == null) { sender.sendMessage(new TextComponentString("\u00a74Invalid gametype. To see gametypes available type \"/teams listGametypes\"")); return; } if(teamsManager.currentGametype != null) { teamsManager.currentGametype.stopGametype(); } teamsManager.currentGametype = gametype; TeamsManager.messageAll("\u00a72" + sender.getCommandSenderName() + "\u00a7f changed the gametype to \u00a72" + gametype.name); if(teamsManager.teams != null && gametype.numTeamsRequired == teamsManager.teams.length) { TeamsManager.messageAll("\u00a7fTeams will remain the same unless altered by an op."); } else { teamsManager.teams = new Team[gametype.numTeamsRequired]; TeamsManager.messageAll("\u00a7fTeams must be reassigned for this gametype. Please wait for an op to do so."); } gametype.initGametype(); return; }*/ if(split[0].equals("listMaps")) { if(teamsManager.maps == null) { sender.sendMessage(new TextComponentString("The map list is null")); return; } sender.sendMessage(new TextComponentString("\u00a72Listing maps")); for(TeamsMap map : teamsManager.maps.values()) { sender.sendMessage(new TextComponentString((teamsManager.currentRound != null && map == teamsManager.currentRound.map ? "\u00a74" : "") + map.name + " (" + map.shortName + ")")); } return; } if(split[0].equals("addMap")) { if(split.length < 3) { sender.sendMessage(new TextComponentString("You need to specify a map name")); return; } String shortName = split[1]; String name = split[2]; for(int i = 3; i < split.length; i++) { name += " " + split[i]; } teamsManager.maps.put(shortName, new TeamsMap(sender.getEntityWorld(), shortName, name)); sender.sendMessage(new TextComponentString("Added new map : " + name + " (" + shortName + ")")); return; } if(split[0].equals("removeMap")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("You need to specify a map's short name")); return; } if(teamsManager.maps.containsKey(split[1])) { teamsManager.maps.remove(split[1]); sender.sendMessage(new TextComponentString("Removed map " + split[1])); } else { sender.sendMessage(new TextComponentString("Map (" + split[1] + ") not found")); } return; } if(split[0].equals("setRound")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("You need to specify the round index (see /teams listRounds)")); return; } TeamsRound round = teamsManager.rounds.get(Integer.parseInt(split[1])); if(round != null) { teamsManager.nextRound = round; TeamsManager.messageAll("\u00a72Next round will be " + round.gametype.shortName + " in " + round.map.name); } return; } /* if(split[0].equals("listTeams")) { if(teamsManager.currentGametype == null || teamsManager.teams == null) { sender.sendMessage(new TextComponentString("\u00a74The gametype is not yet set. Set it by \"/teams setGametype \"")); return; } sender.sendMessage(new TextComponentString("\u00a72Showing currently in use teams")); for(int i = 0; i < teamsManager.teams.length; i++) { Team team = teamsManager.teams[i]; if(team == null) sender.sendMessage(new TextComponentString("\u00a7f" + i + " : No team")); else sender.sendMessage(new TextComponentString("\u00a7" + team.textColour + i + " : " + team.name + " (" + team.shortName + ")")); } return; } */ if(split[0].equals("listTeams") || split[0].equals("listAllTeams")) { if(Team.teams.isEmpty()) { sender.sendMessage(new TextComponentString("\u00a74No teams available. You need a content pack that has some teams with it")); return; } sender.sendMessage(new TextComponentString("\u00a72Showing all avaliable teams")); sender.sendMessage(new TextComponentString("\u00a72To pick these teams, use /teams setTeams with the names in brackets")); for(Team team : Team.teams) { sender.sendMessage(new TextComponentString("\u00a7" + team.textColour + team.name + " (" + team.shortName + ")")); } return; } /* * No longer used if(split[0].equals("setTeams")) { if(teamsManager.currentGametype == null || teamsManager.teams == null) { sender.sendMessage(new TextComponentString("\u00a74No gametype selected. Please select the gametype with the setGametype command")); return; } if(split.length - 1 != teamsManager.teams.length) { sender.sendMessage(new TextComponentString("\u00a74Wrong number of teams given. This gametype requires " + teamsManager.teams.length + " teams to work")); return; } Team[] teams = new Team[teamsManager.teams.length]; String teamList = ""; for(int i = 0; i < split.length - 1; i++) { Team team = Team.getTeam(split[i + 1]); if(team == null) { sender.sendMessage(new TextComponentString("\u00a74" + split[i + 1] + " is not a valid team")); return; } for(int j = 0; j < i; j++) { if(team == teams[j]) { sender.sendMessage(new TextComponentString("\u00a74You may not add " + split[i + 1] + " twice")); return; } } teams[i] = team; teamList += (i == 0 ? "" : (i == split.length - 2 ? " and " : ", ")) + "\u00a7" + team.textColour + team.name + "\u00a7f"; } teamsManager.teams = teams; teamsManager.currentGametype.teamsSet(); TeamsManager.messageAll("\u00a72" + sender.getCommandSenderName() + "\u00a7f changed the teams to be " + teamList); return; } */ if(split[0].equals("getSticks") || split[0].equals("getOpSticks") || split[0].equals("getOpKit")) { EntityPlayerMP player = getPlayer(sender.getName()); if(player != null) { player.inventory.addItemStackToInventory(new ItemStack(FlansMod.opStick, 1, 0)); player.inventory.addItemStackToInventory(new ItemStack(FlansMod.opStick, 1, 1)); player.inventory.addItemStackToInventory(new ItemStack(FlansMod.opStick, 1, 2)); player.inventory.addItemStackToInventory(new ItemStack(FlansMod.opStick, 1, 3)); sender.sendMessage(new TextComponentString("\u00a72Enjoy your op sticks.")); sender.sendMessage(new TextComponentString("\u00a77The Stick of Connecting connects objects (spawners, banners etc) to bases (flagpoles etc)")); sender.sendMessage(new TextComponentString("\u00a77The Stick of Ownership sets the team that currently owns a base")); sender.sendMessage(new TextComponentString("\u00a77The Stick of Mapping sets the map that a base is currently associated with")); sender.sendMessage(new TextComponentString("\u00a77The Stick of Destruction deletes bases and team objects")); } return; } if(split[0].toLowerCase().equals("autobalance")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.autoBalance = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Autobalance is now " + (TeamsManager.autoBalance ? "enabled" : "disabled"))); return; } if(split[0].equals("useRotation")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.voting = !Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Voting is now " + (TeamsManager.voting ? "enabled" : "disabled"))); return; } if(split[0].equals("voting")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.voting = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Voting is now " + (TeamsManager.voting ? "enabled" : "disabled"))); return; } if(split[0].equals("listRounds") || split[0].equals("listRotation")) { sender.sendMessage(new TextComponentString("\u00a72Current Round List")); for(int i = 0; i < TeamsManager.getInstance().rounds.size(); i++) { TeamsRound entry = TeamsManager.getInstance().rounds.get(i); if(entry.map == null) { sender.sendMessage(new TextComponentString("Round had null map")); return; } if(entry.gametype == null) { sender.sendMessage(new TextComponentString("Round had null gametype")); return; } String s = i + ". " + entry.map.shortName + ", " + entry.gametype.shortName; if(entry == TeamsManager.getInstance().currentRound) { s = "\u00a74" + s; } for(int j = 0; j < entry.teams.length; j++) { s += ", " + entry.teams[j].shortName; } s += ", " + entry.timeLimit; s += ", " + entry.scoreLimit; s += ", Pop : " + (int)(entry.popularity * 100F) + "%"; sender.sendMessage(new TextComponentString(s)); } return; } if(split[0].equals("removeRound") || split[0].equals("removeMapFromRotation") || split[0].equals("removeFromRotation") || split[0].equals("removeRotation")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } int map = Integer.parseInt(split[1]); sender.sendMessage(new TextComponentString("Removed map " + map + " (" + TeamsManager.getInstance().rounds.get(map).map.shortName + ") from rotation")); TeamsManager.getInstance().rounds.remove(map); return; } if(split[0].equals("addMapToRotation") || split[0].equals("addToRotation") || split[0].equals("addRotation") || split[0].equals("addRound")) { if(split.length < 7) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ... ")); return; } TeamsMap map = TeamsManager.getInstance().maps.get(split[1]); if(map == null) { sender.sendMessage(new TextComponentString("Could not find map : " + split[1])); return; } Gametype gametype = Gametype.getGametype(split[2]); if(gametype == null) { sender.sendMessage(new TextComponentString("Could not find gametype : " + split[2])); return; } if(split.length != 5 + gametype.numTeamsRequired) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ... ")); return; } Team[] teams = new Team[gametype.numTeamsRequired]; for(int i = 0; i < teams.length; i++) { teams[i] = Team.getTeam(split[3 + i]); } sender.sendMessage(new TextComponentString("Added map (" + map.shortName + ") to rotation")); TeamsManager.getInstance().rounds.add(new TeamsRound(map, gametype, teams, Integer.parseInt(split[3 + gametype.numTeamsRequired]), Integer.parseInt(split[4 + gametype.numTeamsRequired]))); return; } if(split[0].equals("start") || split[0].equals("begin")) { teamsManager.start(); sender.sendMessage(new TextComponentString("Started teams map rotation")); return; } if(split[0].equals("nextMap") || split[0].equals("next") || split[0].equals("nextRound")) { teamsManager.roundTimeLeft = 1; return; } /* * Ignore if(split[0].equals("goToMap")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } int prevRotation = Integer.parseInt(split[1]) - 1; if(prevRotation == -1) prevRotation = teamsManager.rotation.size() - 1; teamsManager.currentRotationEntry = prevRotation; teamsManager.switchToNextGametype(); return; } */ if(split[0].equals("forceAdventure") || split[0].equals("forceAdventureMode")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.forceAdventureMode = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Adventure mode will " + (TeamsManager.forceAdventureMode ? "now" : "no longer") + " be forced")); return; } if(split[0].equals("overrideHunger") || split[0].equals("noHunger")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.overrideHunger = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Players will " + (TeamsManager.overrideHunger ? "no longer" : "now") + " get hungry during rounds")); return; } if(split[0].equals("explosions")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.explosions = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Expolsions are now " + (TeamsManager.explosions ? "enabled" : "disabled"))); return; } if(split[0].equals("bombs") || split[0].equals("allowBombs")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.bombsEnabled = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Bombs are now " + (TeamsManager.bombsEnabled ? "enabled" : "disabled"))); return; } if(split[0].equals("bullets") || split[0].equals("bulletsEnabled")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.bulletsEnabled = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Bullets are now " + (TeamsManager.bulletsEnabled ? "enabled" : "disabled"))); return; } if(split[0].equals("canBreakGuns")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.canBreakGuns = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("AAGuns and MGs can " + (TeamsManager.canBreakGuns ? "now" : "no longer") + " be broken")); return; } if(split[0].equals("canBreakGlass")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.canBreakGlass = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Glass and glowstone can " + (TeamsManager.canBreakGlass ? "now" : "no longer") + " be broken")); return; } if(split[0].equals("armourDrops") || split[0].equals("armorDrops")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.armourDrops = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Armour will " + (TeamsManager.armourDrops ? "now" : "no longer") + " be dropped")); return; } if(split[0].equals("weaponDrops")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } if(split[1].toLowerCase().equals("on")) { TeamsManager.weaponDrops = 1; sender.sendMessage(new TextComponentString("Weapons will be dropped normally")); } else if(split[1].toLowerCase().equals("off")) { TeamsManager.weaponDrops = 0; sender.sendMessage(new TextComponentString("Weapons will be not be dropped")); } else if(split[1].toLowerCase().equals("smart")) { TeamsManager.weaponDrops = 2; sender.sendMessage(new TextComponentString("Smart drops enabled")); } return; } if(split[0].equals("fuelNeeded")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } TeamsManager.vehiclesNeedFuel = Boolean.parseBoolean(split[1]); sender.sendMessage(new TextComponentString("Vehicles will " + (TeamsManager.vehiclesNeedFuel ? "now" : "no longer") + " require fuel")); return; } if(split[0].equals("mgLife")) { if(split.length != 2) { sender.sendMessage(new TextComponentString("Incorrect Usage : Should be /teams " + split[0] + "